Support runtime access to public signal names
This commit is contained in:
parent
2be6b3481c
commit
ba93a08b40
4
Changes
4
Changes
|
|
@ -3,6 +3,10 @@ Revision history for Verilator
|
||||||
The contributors that suggested a given feature are shown in []. [by ...]
|
The contributors that suggested a given feature are shown in []. [by ...]
|
||||||
indicates the contributor was also the author of the fix; Thanks!
|
indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
|
* Verilator 3.8***
|
||||||
|
|
||||||
|
*** Support runtime access to public signal names.
|
||||||
|
|
||||||
* Verilator 3.801 2010/03/17
|
* Verilator 3.801 2010/03/17
|
||||||
|
|
||||||
*** Support "break", "continue", "return".
|
*** Support "break", "continue", "return".
|
||||||
|
|
|
||||||
|
|
@ -1017,12 +1017,14 @@ VerilatedScope::VerilatedScope() {
|
||||||
m_callbacksp = NULL;
|
m_callbacksp = NULL;
|
||||||
m_namep = NULL;
|
m_namep = NULL;
|
||||||
m_funcnumMax = 0;
|
m_funcnumMax = 0;
|
||||||
|
m_varsp = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedScope::~VerilatedScope() {
|
VerilatedScope::~VerilatedScope() {
|
||||||
VerilatedImp::scopeErase(this);
|
VerilatedImp::scopeErase(this);
|
||||||
if (m_namep) { delete [] m_namep; m_namep = NULL; }
|
if (m_namep) { delete [] m_namep; m_namep = NULL; }
|
||||||
if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; }
|
if (m_callbacksp) { delete [] m_callbacksp; m_callbacksp = NULL; }
|
||||||
|
if (m_varsp) { delete m_varsp; m_varsp = NULL; }
|
||||||
m_funcnumMax = 0; // Force callback table to empty
|
m_funcnumMax = 0; // Force callback table to empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1058,6 +1060,46 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int dims, ...) {
|
||||||
|
// Grab dimensions
|
||||||
|
// In the future we may just create a large table at emit time and statically construct from that.
|
||||||
|
if (!finalize) return;
|
||||||
|
|
||||||
|
if (!m_varsp) m_varsp = new VerilatedVarNameMap();
|
||||||
|
VerilatedVar var (namep, datap, vltype);
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap,dims);
|
||||||
|
for (int i=0; i<dims; ++i) {
|
||||||
|
int msb = va_arg(ap,int);
|
||||||
|
int lsb = va_arg(ap,int);
|
||||||
|
if (i==0) {
|
||||||
|
var.m_range.m_lhs = msb;
|
||||||
|
var.m_range.m_rhs = lsb;
|
||||||
|
} else if (i==1) {
|
||||||
|
var.m_array.m_lhs = msb;
|
||||||
|
var.m_array.m_rhs = lsb;
|
||||||
|
} else {
|
||||||
|
// We could have a linked list of ranges, but really this whole thing needs
|
||||||
|
// to be generalized to support structs and unions, etc.
|
||||||
|
vl_fatal(__FILE__,__LINE__,"",(string("Unsupported multi-dimensional public varInsert: ")+namep).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
m_varsp->insert(make_pair(namep,var));
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVar* VerilatedScope::varFind(const char* namep) const {
|
||||||
|
if (VL_LIKELY(m_varsp)) {
|
||||||
|
VerilatedVarNameMap::iterator it = m_varsp->find(namep);
|
||||||
|
if (VL_LIKELY(it != m_varsp->end())) {
|
||||||
|
return &(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void* VerilatedScope::exportFindNullError(int funcnum) const {
|
void* VerilatedScope::exportFindNullError(int funcnum) const {
|
||||||
// Slowpath - Called only when find has failed
|
// Slowpath - Called only when find has failed
|
||||||
string msg = (string("Testbench C called '")
|
string msg = (string("Testbench C called '")
|
||||||
|
|
@ -1085,6 +1127,12 @@ void VerilatedScope::scopeDump() const {
|
||||||
m_callbacksp[i], VerilatedImp::exportName(i));
|
m_callbacksp[i], VerilatedImp::exportName(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (varsp()) {
|
||||||
|
for (VerilatedVarNameMap::const_iterator it = varsp()->begin();
|
||||||
|
it != varsp()->end(); ++it) {
|
||||||
|
VL_PRINTF(" VAR %p: %s\n", &(it->second), it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
|
|
|
||||||
|
|
@ -66,9 +66,22 @@ typedef void (*VerilatedVoidCb)(void);
|
||||||
|
|
||||||
class SpTraceVcd;
|
class SpTraceVcd;
|
||||||
class SpTraceVcdCFile;
|
class SpTraceVcdCFile;
|
||||||
|
class VerilatedVar;
|
||||||
|
class VerilatedVarNameMap;
|
||||||
class VerilatedVcd;
|
class VerilatedVcd;
|
||||||
class VerilatedVcdC;
|
class VerilatedVcdC;
|
||||||
|
|
||||||
|
enum VerilatedVarType {
|
||||||
|
VLVT_UNKNOWN=0,
|
||||||
|
VLVT_PTR, // Pointer to something
|
||||||
|
VLVT_UINT8, // AKA CData
|
||||||
|
VLVT_UINT16, // AKA SData
|
||||||
|
VLVT_UINT32, // AKA IData
|
||||||
|
VLVT_UINT64, // AKA QData
|
||||||
|
VLVT_WDATA, // AKA WData
|
||||||
|
VLVT_STRING // C++ string
|
||||||
|
};
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
/// Base class for all Verilated module classes
|
/// Base class for all Verilated module classes
|
||||||
|
|
||||||
|
|
@ -155,6 +168,7 @@ class VerilatedScope {
|
||||||
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
void** m_callbacksp; ///< Callback table pointer (Fastpath)
|
||||||
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
|
||||||
// 4 bytes padding (on -m64), for rent.
|
// 4 bytes padding (on -m64), for rent.
|
||||||
|
VerilatedVarNameMap* m_varsp; ///< Variable map
|
||||||
const char* m_namep; ///< Scope name (Slowpath)
|
const char* m_namep; ///< Scope name (Slowpath)
|
||||||
|
|
||||||
public: // But internals only - called from VerilatedModule's
|
public: // But internals only - called from VerilatedModule's
|
||||||
|
|
@ -162,9 +176,12 @@ public: // But internals only - called from VerilatedModule's
|
||||||
~VerilatedScope();
|
~VerilatedScope();
|
||||||
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
|
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
|
||||||
void exportInsert(int finalize, const char* namep, void* cb);
|
void exportInsert(int finalize, const char* namep, void* cb);
|
||||||
|
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int dims, ...);
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
const char* name() const { return m_namep; }
|
const char* name() const { return m_namep; }
|
||||||
inline VerilatedSyms* symsp() const { return m_symsp; }
|
inline VerilatedSyms* symsp() const { return m_symsp; }
|
||||||
|
VerilatedVar* varFind(const char* namep) const;
|
||||||
|
VerilatedVarNameMap* varsp() const { return m_varsp; }
|
||||||
void* exportFindError(int funcnum) const;
|
void* exportFindError(int funcnum) const;
|
||||||
void* exportFindNullError(int funcnum) const;
|
void* exportFindNullError(int funcnum) const;
|
||||||
void scopeDump() const;
|
void scopeDump() const;
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@
|
||||||
#include "verilatedos.h"
|
#include "verilatedos.h"
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_heavy.h"
|
#include "verilated_heavy.h"
|
||||||
|
#include "verilated_syms.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
@ -41,13 +42,6 @@ class VerilatedScope;
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
struct VerilatedCStrCmp {
|
|
||||||
// For ordering maps keyed by const char*'s
|
|
||||||
bool operator() (const char *a, const char *b) const {
|
|
||||||
return std::strcmp(a, b) < 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class VerilatedImp {
|
class VerilatedImp {
|
||||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
// -*- C++ -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2010 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.
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilator: Include to allow symbol inspection
|
||||||
|
///
|
||||||
|
/// This file is for inclusion by files that need to inspect
|
||||||
|
/// the symbol table. It is not included in verilated.h
|
||||||
|
/// as it requires some heavyweight C++ classes.
|
||||||
|
///
|
||||||
|
/// Code available from: http://www.veripool.org/verilator
|
||||||
|
///
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _VERILATED_SYMS_H_
|
||||||
|
#define _VERILATED_SYMS_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
|
#include "verilated_heavy.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
// Types
|
||||||
|
|
||||||
|
struct VerilatedCStrCmp {
|
||||||
|
/// Ordering maps keyed by const char*'s
|
||||||
|
bool operator() (const char *a, const char *b) const {
|
||||||
|
return std::strcmp(a, b) < 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
/// Verilator range
|
||||||
|
|
||||||
|
class VerilatedRange {
|
||||||
|
int m_lhs;
|
||||||
|
int m_rhs;
|
||||||
|
protected:
|
||||||
|
friend class VerilatedVar;
|
||||||
|
friend class VerilatedScope;
|
||||||
|
VerilatedRange() : m_lhs(0), m_rhs(0) {}
|
||||||
|
void sets(int lhs, int rhs) { m_lhs=lhs; m_rhs=rhs; }
|
||||||
|
public:
|
||||||
|
~VerilatedRange() {}
|
||||||
|
int lhs() const { return m_lhs; }
|
||||||
|
int rhs() const { return m_rhs; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
/// Verilator variable
|
||||||
|
|
||||||
|
class VerilatedVar {
|
||||||
|
void* m_datap; // Location of data
|
||||||
|
VerilatedVarType m_vltype; // Data type
|
||||||
|
VerilatedRange m_range; // First range
|
||||||
|
VerilatedRange m_array; // Array
|
||||||
|
const char* m_namep; // Name - slowpath
|
||||||
|
protected:
|
||||||
|
friend class VerilatedScope;
|
||||||
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype)
|
||||||
|
: m_datap(datap), m_vltype(vltype), m_namep(namep) {}
|
||||||
|
public:
|
||||||
|
~VerilatedVar() {}
|
||||||
|
void* datap() const { return m_datap; }
|
||||||
|
VerilatedVarType vltype() const { return m_vltype; }
|
||||||
|
const VerilatedRange& range() const { return m_range; }
|
||||||
|
const VerilatedRange& array() const { return m_array; }
|
||||||
|
const char* namep() const { return m_namep; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
/// Types
|
||||||
|
|
||||||
|
struct VerilatedVarNameMap : public map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||||
|
VerilatedVarNameMap() {}
|
||||||
|
~VerilatedVarNameMap() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
|
|
@ -137,6 +137,31 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string AstVar::vlEnumType() const {
|
||||||
|
string arg;
|
||||||
|
AstBasicDType* bdtypep = basicp();
|
||||||
|
bool strtype = bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::STRING;
|
||||||
|
if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::CHARPTR) {
|
||||||
|
return "VLVT_PTR";
|
||||||
|
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||||
|
return "VLVT_PTR";
|
||||||
|
} else if (strtype) {
|
||||||
|
arg += "VLVT_STRING";
|
||||||
|
} else if (widthMin() <= 8) {
|
||||||
|
arg += "VLVT_UINT8";
|
||||||
|
} else if (widthMin() <= 16) {
|
||||||
|
arg += "VLVT_UINT16";
|
||||||
|
} else if (widthMin() <= VL_WORDSIZE) {
|
||||||
|
arg += "VLVT_UINT32";
|
||||||
|
} else if (isQuad()) {
|
||||||
|
arg += "VLVT_UINT64";
|
||||||
|
} else if (isWide()) {
|
||||||
|
arg += "VLVT_WDATA";
|
||||||
|
}
|
||||||
|
// else return "VLVT_UNKNOWN"
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
|
||||||
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
string AstVar::cPubArgType(bool named, bool forReturn) const {
|
||||||
if (forReturn) named=false;
|
if (forReturn) named=false;
|
||||||
string arg;
|
string arg;
|
||||||
|
|
@ -348,6 +373,8 @@ string AstScopeName::scopeSymName() const {
|
||||||
out += textp->text();
|
out += textp->text();
|
||||||
}
|
}
|
||||||
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
|
||||||
|
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
|
||||||
|
if (out.substr(0,1) == ".") out.replace(0,1,"");
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos=out.find(".")) != string::npos) {
|
while ((pos=out.find(".")) != string::npos) {
|
||||||
out.replace(pos, 1, "__");
|
out.replace(pos, 1, "__");
|
||||||
|
|
|
||||||
|
|
@ -542,8 +542,9 @@ private:
|
||||||
bool m_sc:1; // SystemC variable
|
bool m_sc:1; // SystemC variable
|
||||||
bool m_scClocked:1; // SystemC sc_clk<> needed
|
bool m_scClocked:1; // SystemC sc_clk<> needed
|
||||||
bool m_scSensitive:1;// SystemC sensitive() needed
|
bool m_scSensitive:1;// SystemC sensitive() needed
|
||||||
bool m_sigPublic:1; // User C code accesses this signal
|
bool m_sigPublic:1; // User C code accesses this signal or is top signal
|
||||||
bool m_sigModPublic:1;// User C code accesses this signal and module
|
bool m_sigModPublic:1;// User C code accesses this signal and module
|
||||||
|
bool m_sigUserPublic:1; // User C code accesses this signal
|
||||||
bool m_usedClock:1; // Signal used as a clock
|
bool m_usedClock:1; // Signal used as a clock
|
||||||
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
|
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
|
||||||
bool m_funcLocal:1; // Local variable for a function
|
bool m_funcLocal:1; // Local variable for a function
|
||||||
|
|
@ -561,7 +562,7 @@ private:
|
||||||
m_primaryIO=false;
|
m_primaryIO=false;
|
||||||
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
||||||
m_usedClock=false; m_usedParam=false;
|
m_usedClock=false; m_usedParam=false;
|
||||||
m_sigPublic=false; m_sigModPublic=false;
|
m_sigPublic=false; m_sigModPublic=false; m_sigUserPublic=false;
|
||||||
m_funcLocal=false; m_funcReturn=false;
|
m_funcLocal=false; m_funcReturn=false;
|
||||||
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
|
||||||
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
||||||
|
|
@ -607,6 +608,7 @@ public:
|
||||||
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
|
||||||
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
|
||||||
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
|
||||||
|
string vlEnumType() const; // Return VerilatorImp enum name for argument: VLVT_UINT32, etc
|
||||||
void combineType(AstVarType type);
|
void combineType(AstVarType type);
|
||||||
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
|
||||||
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType)
|
||||||
|
|
@ -628,6 +630,7 @@ public:
|
||||||
void usedParam(bool flag) { m_usedParam = flag; }
|
void usedParam(bool flag) { m_usedParam = flag; }
|
||||||
void sigPublic(bool flag) { m_sigPublic = flag; }
|
void sigPublic(bool flag) { m_sigPublic = flag; }
|
||||||
void sigModPublic(bool flag) { m_sigModPublic = flag; }
|
void sigModPublic(bool flag) { m_sigModPublic = flag; }
|
||||||
|
void sigUserPublic(bool flag) { m_sigUserPublic = flag; if (flag) m_sigPublic = flag; }
|
||||||
void sc(bool flag) { m_sc = flag; }
|
void sc(bool flag) { m_sc = flag; }
|
||||||
void scSensitive(bool flag) { m_scSensitive = flag; }
|
void scSensitive(bool flag) { m_scSensitive = flag; }
|
||||||
void primaryIO(bool flag) { m_primaryIO = flag; }
|
void primaryIO(bool flag) { m_primaryIO = flag; }
|
||||||
|
|
@ -670,6 +673,7 @@ public:
|
||||||
bool isScSensitive() const { return m_scSensitive; }
|
bool isScSensitive() const { return m_scSensitive; }
|
||||||
bool isSigPublic() const;
|
bool isSigPublic() const;
|
||||||
bool isSigModPublic() const { return m_sigModPublic; }
|
bool isSigModPublic() const { return m_sigModPublic; }
|
||||||
|
bool isSigUserPublic() const { return m_sigUserPublic; }
|
||||||
bool isTrace() const { return m_trace; }
|
bool isTrace() const { return m_trace; }
|
||||||
bool isConst() const { return m_isConst; }
|
bool isConst() const { return m_isConst; }
|
||||||
bool isStatic() const { return m_isStatic; }
|
bool isStatic() const { return m_isStatic; }
|
||||||
|
|
@ -699,6 +703,7 @@ public:
|
||||||
combineType(typevarp->varType());
|
combineType(typevarp->varType());
|
||||||
if (typevarp->isSigPublic()) sigPublic(true);
|
if (typevarp->isSigPublic()) sigPublic(true);
|
||||||
if (typevarp->isSigModPublic()) sigModPublic(true);
|
if (typevarp->isSigModPublic()) sigModPublic(true);
|
||||||
|
if (typevarp->isSigUserPublic()) sigUserPublic(true);
|
||||||
if (typevarp->attrScClocked()) attrScClocked(true);
|
if (typevarp->attrScClocked()) attrScClocked(true);
|
||||||
}
|
}
|
||||||
void inlineAttrReset(const string& name) {
|
void inlineAttrReset(const string& name) {
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,24 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
|
struct ScopeNameData { string m_symName; string m_prettyName;
|
||||||
|
ScopeNameData(const string& symName, const string& prettyName)
|
||||||
|
: m_symName(symName), m_prettyName(prettyName) {}
|
||||||
|
};
|
||||||
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
struct ScopeFuncData { AstScopeName* m_scopep; AstCFunc* m_funcp; AstNodeModule* m_modp;
|
||||||
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* modp)
|
||||||
: m_scopep(scopep), m_funcp(funcp), m_modp(modp) {}
|
: m_scopep(scopep), m_funcp(funcp), m_modp(modp) {}
|
||||||
};
|
};
|
||||||
|
struct ScopeVarData { string m_scopeName; string m_varBasePretty; AstVar* m_varp;
|
||||||
|
AstNodeModule* m_modp; AstScope* m_scopep;
|
||||||
|
ScopeVarData(const string& scopeName, const string& varBasePretty, AstVar* varp, AstNodeModule* modp, AstScope* scopep)
|
||||||
|
: m_scopeName(scopeName), m_varBasePretty(varBasePretty), m_varp(varp), m_modp(modp), m_scopep(scopep) {}
|
||||||
|
};
|
||||||
typedef map<string,ScopeFuncData> ScopeFuncs;
|
typedef map<string,ScopeFuncData> ScopeFuncs;
|
||||||
typedef map<string,AstScopeName*> ScopeNames;
|
typedef map<string,ScopeVarData> ScopeVars;
|
||||||
|
typedef map<string,ScopeNameData> ScopeNames;
|
||||||
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
|
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
|
||||||
|
typedef pair<AstNodeModule*,AstVar*> ModVarPair;
|
||||||
struct CmpName {
|
struct CmpName {
|
||||||
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
|
||||||
return lhsp.first->name() < rhsp.first->name();
|
return lhsp.first->name() < rhsp.first->name();
|
||||||
|
|
@ -71,8 +82,10 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
vector<ScopeModPair> m_scopes; // Every scope by module
|
vector<ScopeModPair> m_scopes; // Every scope by module
|
||||||
vector<AstCFunc*> m_dpis; // DPI functions
|
vector<AstCFunc*> m_dpis; // DPI functions
|
||||||
|
vector<ModVarPair> m_modVars; // Each public {mod,var}
|
||||||
ScopeNames m_scopeNames; // Each unique AstScopeName
|
ScopeNames m_scopeNames; // Each unique AstScopeName
|
||||||
ScopeFuncs m_scopeFuncs; // Each {scope,dpiexportfunc}
|
ScopeFuncs m_scopeFuncs; // Each {scope,dpi-export-func}
|
||||||
|
ScopeVars m_scopeVars; // Each {scope,public-var}
|
||||||
V3LanguageWords m_words; // Reserved word detector
|
V3LanguageWords m_words; // Reserved word detector
|
||||||
int m_coverBins; // Coverage bin number
|
int m_coverBins; // Coverage bin number
|
||||||
int m_labelNum; // Next label number
|
int m_labelNum; // Next label number
|
||||||
|
|
@ -95,10 +108,65 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void varsExpand() {
|
||||||
|
// We didn'e have all m_scopes loaded when we encountered variables, so expand them now
|
||||||
|
// It would be less code if each module inserted its own variables.
|
||||||
|
// Someday. For now public isn't common.
|
||||||
|
for (vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
|
||||||
|
AstScope* scopep = it->first; AstNodeModule* smodp = it->second;
|
||||||
|
for (vector<ModVarPair>::iterator it = m_modVars.begin(); it != m_modVars.end(); ++it) {
|
||||||
|
AstNodeModule* modp = it->first;
|
||||||
|
if (modp == smodp) {
|
||||||
|
AstVar* varp = it->second;
|
||||||
|
// Need to split the module + var name into the original-ish full scope and variable name under that scope.
|
||||||
|
// The module instance name is included later, when we know the scopes this module is under
|
||||||
|
string whole = scopep->name()+"__DOT__"+varp->name();
|
||||||
|
string scpName;
|
||||||
|
string varBase;
|
||||||
|
if (whole.substr(0,10) == "__DOT__TOP") whole.replace(0,10,"");
|
||||||
|
string::size_type pos = whole.rfind("__DOT__");
|
||||||
|
if (pos != string::npos) {
|
||||||
|
scpName = whole.substr(0,pos);
|
||||||
|
varBase = whole.substr(pos+strlen("__DOT__"));
|
||||||
|
} else {
|
||||||
|
varBase = whole;
|
||||||
|
}
|
||||||
|
//UINFO(9,"For "<<scopep->name()<<" - "<<varp->name()<<" Scp "<<scpName<<" Var "<<varBase<<endl);
|
||||||
|
string varBasePretty = AstNode::prettyName(varBase);
|
||||||
|
string scpPretty = AstNode::prettyName(scpName);
|
||||||
|
string scpSym;
|
||||||
|
{
|
||||||
|
string out = scpName;
|
||||||
|
string::size_type pos;
|
||||||
|
while ((pos=out.find("__PVT__")) != string::npos) {
|
||||||
|
out.replace(pos, 7, "");
|
||||||
|
}
|
||||||
|
if (out.substr(0,10) == "TOP__DOT__") out.replace(0,10,"");
|
||||||
|
if (out.substr(0,4) == "TOP.") out.replace(0,4,"");
|
||||||
|
while ((pos=out.find(".")) != string::npos) {
|
||||||
|
out.replace(pos, 1, "__");
|
||||||
|
}
|
||||||
|
while ((pos=out.find("__DOT__")) != string::npos) {
|
||||||
|
out.replace(pos, 7, "__");
|
||||||
|
}
|
||||||
|
scpSym = out;
|
||||||
|
}
|
||||||
|
//UINFO(9," scnameins sp "<<scpName<<" sp "<<scpPretty<<" ss "<<scpSym<<endl);
|
||||||
|
if (m_scopeNames.find(scpSym) == m_scopeNames.end()) {
|
||||||
|
m_scopeNames.insert(make_pair(scpSym, ScopeNameData(scpSym, scpPretty)));
|
||||||
|
}
|
||||||
|
m_scopeVars.insert(make_pair(scpSym + " " + varp->name(),
|
||||||
|
ScopeVarData(scpSym, varBasePretty, varp, modp, scopep)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||||
// Collect list of scopes
|
// Collect list of scopes
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
varsExpand();
|
||||||
|
|
||||||
// Sort by names, so line/process order matters less
|
// Sort by names, so line/process order matters less
|
||||||
sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
||||||
|
|
@ -125,8 +193,9 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
}
|
}
|
||||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||||
string name = nodep->scopeSymName();
|
string name = nodep->scopeSymName();
|
||||||
|
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettyName()<<" ss "<<name<<endl);
|
||||||
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
if (m_scopeNames.find(name) == m_scopeNames.end()) {
|
||||||
m_scopeNames.insert(make_pair(name, nodep));
|
m_scopeNames.insert(make_pair(name, ScopeNameData(name, nodep->scopePrettyName())));
|
||||||
}
|
}
|
||||||
if (nodep->dpiExport()) {
|
if (nodep->dpiExport()) {
|
||||||
if (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
|
if (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
|
||||||
|
|
@ -134,6 +203,12 @@ class EmitCSyms : EmitCBaseVisitor {
|
||||||
ScopeFuncData(nodep, m_funcp, m_modp)));
|
ScopeFuncData(nodep, m_funcp, m_modp)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
if (nodep->isSigUserPublic()) {
|
||||||
|
m_modVars.push_back(make_pair(m_modp, nodep));
|
||||||
|
}
|
||||||
|
}
|
||||||
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
||||||
// Assign numbers to all bins, so we know how big of an array to use
|
// Assign numbers to all bins, so we know how big of an array to use
|
||||||
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
if (!nodep->dataDeclNullp()) { // else duplicate we don't need code for
|
||||||
|
|
@ -255,7 +330,7 @@ void EmitCSyms::emitSymHdr() {
|
||||||
|
|
||||||
puts("\n// SCOPE NAMES\n");
|
puts("\n// SCOPE NAMES\n");
|
||||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
puts("VerilatedScope __Vscope_"+it->second->scopeSymName()+";\n");
|
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
puts("\n// CREATORS\n");
|
puts("\n// CREATORS\n");
|
||||||
|
|
@ -345,8 +420,8 @@ void EmitCSyms::emitSymImp() {
|
||||||
|
|
||||||
puts("// Setup scope names\n");
|
puts("// Setup scope names\n");
|
||||||
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
|
||||||
puts("__Vscope_"+it->second->scopeSymName()+".configure(this,name(),");
|
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
|
||||||
putsQuoted(it->second->scopePrettyName());
|
putsQuoted(it->second.m_prettyName);
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -367,6 +442,55 @@ void EmitCSyms::emitSymImp() {
|
||||||
puts("));\n");
|
puts("));\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// It would be less code if each module inserted its own variables.
|
||||||
|
// Someday. For now public isn't common.
|
||||||
|
for (ScopeVars::iterator it = m_scopeVars.begin(); it != m_scopeVars.end(); ++it) {
|
||||||
|
AstNodeModule* modp = it->second.m_modp;
|
||||||
|
AstScope* scopep = it->second.m_scopep;
|
||||||
|
AstVar* varp = it->second.m_varp;
|
||||||
|
//
|
||||||
|
int dim=0;
|
||||||
|
string bounds;
|
||||||
|
if (AstBasicDType* basicp = varp->basicp()) {
|
||||||
|
// Range is always first, it's not in "C" order
|
||||||
|
if (basicp->rangep()) {
|
||||||
|
bounds += " ,"; bounds += cvtToStr(basicp->rangep()->msbConst());
|
||||||
|
bounds += ","; bounds += cvtToStr(basicp->rangep()->lsbConst());
|
||||||
|
dim++;
|
||||||
|
}
|
||||||
|
for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) {
|
||||||
|
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||||
|
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
|
||||||
|
bounds += " ,"; bounds += cvtToStr(adtypep->arrayp()->msbConst());
|
||||||
|
bounds += ","; bounds += cvtToStr(adtypep->arrayp()->lsbConst());
|
||||||
|
dim++;
|
||||||
|
dtypep = adtypep->dtypep();
|
||||||
|
}
|
||||||
|
else break; // AstBasicDType - nothing below, 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//
|
||||||
|
if (dim>2) {
|
||||||
|
puts("//UNSUP "); // VerilatedImp can't deal with >2d arrays
|
||||||
|
}
|
||||||
|
puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,");
|
||||||
|
putsQuoted(it->second.m_varBasePretty);
|
||||||
|
puts(", &(");
|
||||||
|
if (modp->isTop()) {
|
||||||
|
puts(scopep->nameDotless());
|
||||||
|
puts("p->");
|
||||||
|
} else {
|
||||||
|
puts(scopep->nameDotless());
|
||||||
|
puts(".");
|
||||||
|
}
|
||||||
|
puts(varp->name());
|
||||||
|
puts("), ");
|
||||||
|
puts(varp->vlEnumType()); // VLVT_UINT32 etc
|
||||||
|
puts(",");
|
||||||
|
puts(cvtToStr(dim));
|
||||||
|
puts(bounds);
|
||||||
|
puts(");\n");
|
||||||
|
}
|
||||||
puts("}\n");
|
puts("}\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ private:
|
||||||
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
|
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
|
||||||
// Cleared each cell
|
// Cleared each cell
|
||||||
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
|
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
|
||||||
|
// AstVar::user3() // bool Don't alias the user4, keep it as signal
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
|
|
@ -151,6 +152,10 @@ private:
|
||||||
UINFO(6,"One-to-one "<<connectRefp<<endl);
|
UINFO(6,"One-to-one "<<connectRefp<<endl);
|
||||||
UINFO(6," -to "<<pinNewVarp<<endl);
|
UINFO(6," -to "<<pinNewVarp<<endl);
|
||||||
pinNewVarp->user2p(connectRefp);
|
pinNewVarp->user2p(connectRefp);
|
||||||
|
// Public output inside the cell must go via an assign rather than alias
|
||||||
|
// Else the public logic will set the alias, loosing the value to be propagated up
|
||||||
|
// (InOnly isn't a problem as the AssignAlias will create the assignment for us)
|
||||||
|
pinNewVarp->user3(pinNewVarp->isSigUserPublic() && pinNewVarp->isOutOnly());
|
||||||
}
|
}
|
||||||
// Cleanup var names, etc, to not conflict
|
// Cleanup var names, etc, to not conflict
|
||||||
m_cellp = nodep;
|
m_cellp = nodep;
|
||||||
|
|
@ -175,6 +180,7 @@ private:
|
||||||
// user2p is either a const or a var.
|
// user2p is either a const or a var.
|
||||||
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
|
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
|
||||||
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
|
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
|
||||||
|
UINFO(1,"connectto: "<<nodep->user2p()->castNode()<<endl);
|
||||||
if (!exprconstp && !exprvarrefp) {
|
if (!exprconstp && !exprvarrefp) {
|
||||||
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
|
||||||
}
|
}
|
||||||
|
|
@ -182,6 +188,15 @@ private:
|
||||||
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||||
new AstVarRef(nodep->fileline(), nodep, true),
|
new AstVarRef(nodep->fileline(), nodep, true),
|
||||||
exprconstp->cloneTree(true)));
|
exprconstp->cloneTree(true)));
|
||||||
|
} else if (nodep->user3()) {
|
||||||
|
// Public variable at the lower module end - we need to make sure we propagate
|
||||||
|
// the logic changes up and down; if we aliased, we might remove the change detection
|
||||||
|
// on the output variable.
|
||||||
|
UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
|
||||||
|
if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
|
||||||
|
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
|
||||||
|
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||||
|
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||||
} else {
|
} else {
|
||||||
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
|
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
|
||||||
new AstVarRef(nodep->fileline(), nodep, true),
|
new AstVarRef(nodep->fileline(), nodep, true),
|
||||||
|
|
@ -216,8 +231,9 @@ private:
|
||||||
}
|
}
|
||||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||||
if (m_cellp) {
|
if (m_cellp) {
|
||||||
if (nodep->varp()->user2p() // It's being converted to a alias.
|
if (nodep->varp()->user2p() // It's being converted to an alias.
|
||||||
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases
|
&& !nodep->varp()->user3()
|
||||||
|
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
|
||||||
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
|
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
|
||||||
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
|
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
|
||||||
if (exprconstp) {
|
if (exprconstp) {
|
||||||
|
|
|
||||||
|
|
@ -274,12 +274,12 @@ private:
|
||||||
}
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
||||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
m_varp->sigPublic(true); m_varp->sigModPublic(true);
|
m_varp->sigUserPublic(true); m_varp->sigModPublic(true);
|
||||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
||||||
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
|
||||||
m_varp->sigPublic(true);
|
m_varp->sigUserPublic(true);
|
||||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||||
}
|
}
|
||||||
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
// -*- C++ -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2010-2010 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 "Vt_dpi_var.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "svdpi.h"
|
||||||
|
|
||||||
|
#include "verilated_syms.h"
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
struct MyMon {
|
||||||
|
vluint32_t* sigsp[2];
|
||||||
|
MyMon() { sigsp[0]=NULL; sigsp[1]=NULL; }
|
||||||
|
};
|
||||||
|
MyMon mons[2];
|
||||||
|
|
||||||
|
void mon_register_a(const char* namep, void* sigp, bool isOut) {
|
||||||
|
// Callback from initial block in monitor
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
VL_PRINTF("- mon_register_a(\"%s\", %p, %d);\n", namep, sigp, isOut);
|
||||||
|
#endif
|
||||||
|
mons[0].sigsp[isOut] = (vluint32_t*)sigp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mon_do(MyMon* monp) {
|
||||||
|
if (!monp->sigsp[0]) vl_fatal(__FILE__,__LINE__,"","never registered");
|
||||||
|
if (!monp->sigsp[1]) vl_fatal(__FILE__,__LINE__,"","never registered");
|
||||||
|
*monp->sigsp[1] = (*(monp->sigsp[0]))+1;
|
||||||
|
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
VL_PRINTF("- mon_do(%08x(&%p) -> %08x(&%p));\n",
|
||||||
|
*(monp->sigsp[0]), monp->sigsp[0], *(monp->sigsp[1]), monp->sigsp[1]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void mon_class_name(const char* namep) {
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
VL_PRINTF("- mon_class_name(\"%s\");\n", namep);
|
||||||
|
#endif
|
||||||
|
// Check the C's calling name of "" doesn't lead to extra dots in the name()
|
||||||
|
if (namep && namep[0]=='.') vl_fatal(__FILE__,__LINE__,"", (string("Unexp class name ")+namep).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void mon_scope_name(const char* namep);
|
||||||
|
void mon_scope_name(const char* namep) {
|
||||||
|
const char* modp = svGetNameFromScope(svGetScope());
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
VL_PRINTF("- mon_scope_name('%s', \"%s\");\n", modp, namep);
|
||||||
|
#endif
|
||||||
|
if (strcmp(namep,"t.sub")) vl_fatal(__FILE__,__LINE__,"", (string("Unexp scope name ")+namep).c_str());
|
||||||
|
if (strcmp(modp,"t.sub")) vl_fatal(__FILE__,__LINE__,"", (string("Unexp dpiscope name ")+modp).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void mon_register_b(const char* namep, int isOut);
|
||||||
|
void mon_register_b(const char* namep, int isOut) {
|
||||||
|
const char* modp = svGetNameFromScope(svGetScope());
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
VL_PRINTF("- mon_register_b('%s', \"%s\", %d);\n", modp, namep, isOut);
|
||||||
|
#endif
|
||||||
|
// Use scope to get pointer and size of signal
|
||||||
|
const VerilatedScope* scopep = Verilated::dpiScope();
|
||||||
|
const VerilatedVar* varp = scopep->varFind(namep);
|
||||||
|
if (!varp) {
|
||||||
|
VL_PRINTF("%%Warning: mon_register_b signal not found: \"%s\"\n", namep);
|
||||||
|
} else if (varp->vltype() != VLVT_UINT32) {
|
||||||
|
VL_PRINTF("%%Warning: wrong type for signal: \"%s\"\n", namep);
|
||||||
|
} else {
|
||||||
|
vluint32_t* datap = (vluint32_t*)(varp->datap());
|
||||||
|
VL_PRINTF("- mon_register_b('%s', \"%s\", %p, %d);\n", modp, namep, datap, isOut);
|
||||||
|
mons[1].sigsp[isOut] = (vluint32_t*)(varp->datap());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void mon_register_done();
|
||||||
|
void mon_register_done() {
|
||||||
|
const char* modp = svGetNameFromScope(svGetScope());
|
||||||
|
#ifdef TEST_VERBOSE
|
||||||
|
VL_PRINTF("- mon_register_done('%s');\n", modp);
|
||||||
|
#endif
|
||||||
|
// Print list of all signals - if we didn't register2 anything we'd pick them off here
|
||||||
|
const VerilatedScope* scopep = Verilated::dpiScope();
|
||||||
|
if (VerilatedVarNameMap* varsp = scopep->varsp()) {
|
||||||
|
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
|
||||||
|
it != varsp->end(); ++it) {
|
||||||
|
VL_PRINTF("- mon2: %s\n", it->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mon_eval() {
|
||||||
|
// Callback from always@ negedge
|
||||||
|
mon_do(&mons[0]);
|
||||||
|
mon_do(&mons[1]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//======================================================================
|
||||||
|
|
||||||
|
unsigned int main_time = false;
|
||||||
|
|
||||||
|
double sc_time_stamp () {
|
||||||
|
return main_time;
|
||||||
|
}
|
||||||
|
int main(int argc, char **argv, char **env) {
|
||||||
|
double sim_time = 1100;
|
||||||
|
Verilated::commandArgs(argc, argv);
|
||||||
|
Verilated::debug(0);
|
||||||
|
|
||||||
|
VM_PREFIX* topp = new VM_PREFIX (""); // Note null name - we're flattening it out
|
||||||
|
|
||||||
|
#ifdef VERILATOR
|
||||||
|
# ifdef TEST_VERBOSE
|
||||||
|
Verilated::scopesDump();
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
topp->eval();
|
||||||
|
topp->clk = 0;
|
||||||
|
main_time += 10;
|
||||||
|
|
||||||
|
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
|
||||||
|
main_time += 1;
|
||||||
|
topp->eval();
|
||||||
|
topp->clk = !topp->clk;
|
||||||
|
//mon_do();
|
||||||
|
}
|
||||||
|
if (!Verilated::gotFinish()) {
|
||||||
|
vl_fatal(__FILE__,__LINE__,"main", "%Error: Timeout; never got a $finish");
|
||||||
|
}
|
||||||
|
topp->final();
|
||||||
|
|
||||||
|
delete topp; topp=NULL;
|
||||||
|
exit(0L);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 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.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
make_top_shell => 0,
|
||||||
|
make_main => 0,
|
||||||
|
verilator_flags2 => ["--exe --no-l2name $Self->{t_dir}/t_dpi_var.cpp"],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
check_finished=>1,
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// Copyright 2010 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.
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
integer cyc=0;
|
||||||
|
|
||||||
|
wire monclk = ~clk;
|
||||||
|
|
||||||
|
int in;
|
||||||
|
int fr_a;
|
||||||
|
int fr_b;
|
||||||
|
int fr_chk;
|
||||||
|
sub sub (.*);
|
||||||
|
|
||||||
|
// Test loop
|
||||||
|
always @ (posedge clk) begin
|
||||||
|
`ifdef TEST_VERBOSE
|
||||||
|
$write("[%0t] cyc==%0d in=%x fr_a=%x b=%x fr_chk=%x\n",$time, cyc, in, fr_a, fr_b, fr_chk);
|
||||||
|
`endif
|
||||||
|
cyc <= cyc + 1;
|
||||||
|
in <= {in[30:0], in[31]^in[2]^in[0]};
|
||||||
|
if (cyc==0) begin
|
||||||
|
// Setup
|
||||||
|
in <= 32'hd70a4497;
|
||||||
|
end
|
||||||
|
else if (cyc<3) begin
|
||||||
|
end
|
||||||
|
else if (cyc<10) begin
|
||||||
|
if (fr_chk != fr_a) $stop;
|
||||||
|
if (fr_chk != fr_b) $stop;
|
||||||
|
end
|
||||||
|
else if (cyc==10) begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
import "DPI-C" context function void mon_scope_name (input string formatted /*verilator sformat*/ );
|
||||||
|
import "DPI-C" context function void mon_register_b(string name, int isOut);
|
||||||
|
import "DPI-C" context function void mon_register_done();
|
||||||
|
|
||||||
|
module sub (/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
fr_a, fr_b, fr_chk,
|
||||||
|
// Inputs
|
||||||
|
in
|
||||||
|
);
|
||||||
|
|
||||||
|
`systemc_imp_header
|
||||||
|
void mon_class_name(const char* namep);
|
||||||
|
void mon_register_a(const char* namep, void* sigp, bool isOut);
|
||||||
|
bool mon_eval();
|
||||||
|
`verilog
|
||||||
|
|
||||||
|
input int in /*verilator public_flat*/;
|
||||||
|
output int fr_a /*verilator public_flat*/;
|
||||||
|
output int fr_b /*verilator public_flat*/;
|
||||||
|
output int fr_chk;
|
||||||
|
|
||||||
|
reg [3:0] onearray [1:2] /*verilator public_flat*/;
|
||||||
|
reg [3:0] twoarray [1:2][3:4] /*verilator public_flat*/;
|
||||||
|
|
||||||
|
always @* fr_chk = in + 1;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
// Test the naming
|
||||||
|
$c("mon_class_name(name());");
|
||||||
|
mon_scope_name("%m");
|
||||||
|
// Scheme A - pass pointer directly
|
||||||
|
$c("mon_register_a(\"in\",&",in,",false);");
|
||||||
|
$c("mon_register_a(\"fr_a\",&",fr_a,",true);");
|
||||||
|
// Scheme B - use VPIish callbacks to see what signals exist
|
||||||
|
mon_register_b("in", 0);
|
||||||
|
mon_register_b("fr_b", 1);
|
||||||
|
mon_register_done();
|
||||||
|
end
|
||||||
|
|
||||||
|
always @(posedge t.monclk) begin
|
||||||
|
// Hack - Write all outputs, so the data will get scheduled to propagate out of this module
|
||||||
|
// FUTURE Long term, we should detect a public signal has been written
|
||||||
|
// with a new value, and create an event that flips monclk automatically
|
||||||
|
if ($c1("mon_eval()")) begin
|
||||||
|
// This code doesn't execute, just is here so verilator schedules the code.
|
||||||
|
fr_a = 0;
|
||||||
|
fr_b = 0;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue