// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2013-2014 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License.
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
//*************************************************************************

#include "vpi_user.h"

class TestSimulator {
private:
    struct SimTypes {
	int verilator;
	int icarus;
	int mti;
	int ncsim;
	int vcs;
    };
    s_vpi_vlog_info   m_info;
    SimTypes          m_simulators;
public:
    TestSimulator() {
	vpi_get_vlog_info(&m_info);
	if (0 == strcmp(m_info.product, "Verilator")) {
	    m_simulators.verilator = true;
	} else if (0 == strcmp(m_info.product, "Verilator")) {
	    m_simulators.icarus = true;
	} else if (0 == strncmp(m_info.product, "Chronologic Simulation VCS", strlen("Chronologic Simulation VCS"))) {
	    m_simulators.vcs = true;
	} else {
	    printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n",
		   __FILE__, __LINE__, m_info.product);
	}
    }
    ~TestSimulator() { }
    // METHORS
private:
    static TestSimulator& singleton() {
	static TestSimulator s_singleton;
	return s_singleton;
    }
    static const SimTypes& simulators() { return singleton().m_simulators; }
public:
    static const s_vpi_vlog_info& get_info() { return singleton().m_info; }
    // Simulator names
    static bool is_icarus() { return simulators().icarus; }
    static bool is_verilator() { return simulators().verilator; }
    static bool is_mti() { return simulators().mti; }
    static bool is_ncsim() { return simulators().ncsim; }
    static bool is_vcs() { return simulators().vcs; }
    // Simulator properties
    static bool is_event_driven() { return !simulators().verilator; }
    static bool has_get_scalar() { return !simulators().icarus; }
    // return test level scope
    static const char* top() {
	if (simulators().verilator) {
	    return "t";
	} else {
	    return "top.t";
	}
    }
    // return absolute scope of obj
    static const char* rooted(const char *obj) {
	static char buf[256];
	snprintf(buf, sizeof(buf), "%s.%s", top(), obj);
	return buf;
    }
};

#define VPI_HANDLE(signal) vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(signal), NULL);
