Support runtime access to public signal names

This commit is contained in:
Wilson Snyder 2010-03-17 08:22:49 -04:00
parent 2be6b3481c
commit ba93a08b40
13 changed files with 614 additions and 19 deletions

View File

@ -3,6 +3,10 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
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
*** Support "break", "continue", "return".

View File

@ -1017,12 +1017,14 @@ VerilatedScope::VerilatedScope() {
m_callbacksp = NULL;
m_namep = NULL;
m_funcnumMax = 0;
m_varsp = NULL;
}
VerilatedScope::~VerilatedScope() {
VerilatedImp::scopeErase(this);
if (m_namep) { delete [] m_namep; m_namep = 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
}
@ -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 {
// Slowpath - Called only when find has failed
string msg = (string("Testbench C called '")
@ -1085,6 +1127,12 @@ void VerilatedScope::scopeDump() const {
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);
}
}
}
//===========================================================================

View File

@ -66,9 +66,22 @@ typedef void (*VerilatedVoidCb)(void);
class SpTraceVcd;
class SpTraceVcdCFile;
class VerilatedVar;
class VerilatedVarNameMap;
class VerilatedVcd;
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
@ -155,6 +168,7 @@ class VerilatedScope {
void** m_callbacksp; ///< Callback table pointer (Fastpath)
int m_funcnumMax; ///< Maxium function number stored (Fastpath)
// 4 bytes padding (on -m64), for rent.
VerilatedVarNameMap* m_varsp; ///< Variable map
const char* m_namep; ///< Scope name (Slowpath)
public: // But internals only - called from VerilatedModule's
@ -162,9 +176,12 @@ public: // But internals only - called from VerilatedModule's
~VerilatedScope();
void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp);
void exportInsert(int finalize, const char* namep, void* cb);
void varInsert(int finalize, const char* namep, void* datap, VerilatedVarType vltype, int dims, ...);
// ACCESSORS
const char* name() const { return m_namep; }
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* exportFindNullError(int funcnum) const;
void scopeDump() const;

View File

@ -31,6 +31,7 @@
#include "verilatedos.h"
#include "verilated.h"
#include "verilated_heavy.h"
#include "verilated_syms.h"
#include <map>
#include <vector>
@ -41,13 +42,6 @@ class VerilatedScope;
//======================================================================
// 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 {
// Whole class is internal use only - Global information shared between verilated*.cpp files.

92
include/verilated_syms.h Normal file
View File

@ -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

View File

@ -137,6 +137,31 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
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 {
if (forReturn) named=false;
string arg;
@ -348,6 +373,8 @@ string AstScopeName::scopeSymName() const {
out += textp->text();
}
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;
while ((pos=out.find(".")) != string::npos) {
out.replace(pos, 1, "__");

View File

@ -542,8 +542,9 @@ private:
bool m_sc:1; // SystemC variable
bool m_scClocked:1; // SystemC sc_clk<> 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_sigUserPublic:1; // User C code accesses this signal
bool m_usedClock:1; // Signal used as a clock
bool m_usedParam:1; // Parameter is referenced (on link; later signals not setup)
bool m_funcLocal:1; // Local variable for a function
@ -561,7 +562,7 @@ private:
m_primaryIO=false;
m_sc=false; m_scClocked=false; m_scSensitive=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_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=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 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 vlEnumType() const; // Return VerilatorImp enum name for argument: VLVT_UINT32, etc
void combineType(AstVarType type);
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)
@ -628,6 +630,7 @@ public:
void usedParam(bool flag) { m_usedParam = flag; }
void sigPublic(bool flag) { m_sigPublic = 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 scSensitive(bool flag) { m_scSensitive = flag; }
void primaryIO(bool flag) { m_primaryIO = flag; }
@ -670,6 +673,7 @@ public:
bool isScSensitive() const { return m_scSensitive; }
bool isSigPublic() const;
bool isSigModPublic() const { return m_sigModPublic; }
bool isSigUserPublic() const { return m_sigUserPublic; }
bool isTrace() const { return m_trace; }
bool isConst() const { return m_isConst; }
bool isStatic() const { return m_isStatic; }
@ -699,6 +703,7 @@ public:
combineType(typevarp->varType());
if (typevarp->isSigPublic()) sigPublic(true);
if (typevarp->isSigModPublic()) sigModPublic(true);
if (typevarp->isSigUserPublic()) sigUserPublic(true);
if (typevarp->attrScClocked()) attrScClocked(true);
}
void inlineAttrReset(const string& name) {

View File

@ -45,13 +45,24 @@ class EmitCSyms : EmitCBaseVisitor {
AstUser1InUse m_inuser1;
// 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;
ScopeFuncData(AstScopeName* scopep, AstCFunc* funcp, AstNodeModule* 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,AstScopeName*> ScopeNames;
typedef map<string,ScopeVarData> ScopeVars;
typedef map<string,ScopeNameData> ScopeNames;
typedef pair<AstScope*,AstNodeModule*> ScopeModPair;
typedef pair<AstNodeModule*,AstVar*> ModVarPair;
struct CmpName {
inline bool operator () (const ScopeModPair& lhsp, const ScopeModPair& rhsp) const {
return lhsp.first->name() < rhsp.first->name();
@ -71,8 +82,10 @@ class EmitCSyms : EmitCBaseVisitor {
AstNodeModule* m_modp; // Current module
vector<ScopeModPair> m_scopes; // Every scope by module
vector<AstCFunc*> m_dpis; // DPI functions
vector<ModVarPair> m_modVars; // Each public {mod,var}
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
int m_coverBins; // Coverage bin 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
virtual void visit(AstNetlist* nodep, AstNUser*) {
// Collect list of scopes
nodep->iterateChildren(*this);
varsExpand();
// Sort by names, so line/process order matters less
sort(m_scopes.begin(), m_scopes.end(), CmpName());
@ -125,8 +193,9 @@ class EmitCSyms : EmitCBaseVisitor {
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
string name = nodep->scopeSymName();
//UINFO(9,"scnameins sp "<<nodep->name()<<" sp "<<nodep->scopePrettyName()<<" ss "<<name<<endl);
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 (!m_funcp) nodep->v3fatalSrc("ScopeName not under DPI function");
@ -134,6 +203,12 @@ class EmitCSyms : EmitCBaseVisitor {
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*) {
// 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
@ -255,7 +330,7 @@ void EmitCSyms::emitSymHdr() {
puts("\n// SCOPE NAMES\n");
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");
@ -345,8 +420,8 @@ void EmitCSyms::emitSymImp() {
puts("// Setup scope names\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
puts("__Vscope_"+it->second->scopeSymName()+".configure(this,name(),");
putsQuoted(it->second->scopePrettyName());
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
putsQuoted(it->second.m_prettyName);
puts(");\n");
}
@ -367,6 +442,55 @@ void EmitCSyms::emitSymImp() {
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");
}

View File

@ -57,6 +57,7 @@ private:
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
// Cleared each cell
// 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
AstNodeModule* m_modp; // Current module
@ -151,6 +152,10 @@ private:
UINFO(6,"One-to-one "<<connectRefp<<endl);
UINFO(6," -to "<<pinNewVarp<<endl);
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
m_cellp = nodep;
@ -175,6 +180,7 @@ private:
// user2p is either a const or a var.
AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
UINFO(1,"connectto: "<<nodep->user2p()->castNode()<<endl);
if (!exprconstp && !exprvarrefp) {
nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
}
@ -182,6 +188,15 @@ private:
m_modp->addStmtp(new AstAssignW(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, 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 {
m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
@ -216,8 +231,9 @@ private:
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (m_cellp) {
if (nodep->varp()->user2p() // It's being converted to a alias.
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases
if (nodep->varp()->user2p() // It's being converted to an alias.
&& !nodep->varp()->user3()
&& !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
if (exprconstp) {

View File

@ -274,12 +274,12 @@ private:
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
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;
}
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->sigPublic(true);
m_varp->sigUserPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {

View File

@ -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);
}

21
test_regress/t/t_dpi_var.pl Executable file
View File

@ -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;

100
test_regress/t/t_dpi_var.v Normal file
View File

@ -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