Add --protect-ids to obscure information in objects, bug1521.

This commit is contained in:
Wilson Snyder 2019-10-06 13:24:21 -04:00
parent ed1e5fb509
commit 91f1acd85f
30 changed files with 723 additions and 138 deletions

View File

@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
*** Examples have been renamed.
*** Add --protect-ids to obscure information in objects, bug1521. [Todd Strader]
* Verilator 4.020 2019-10-06

View File

@ -352,6 +352,8 @@ detailed descriptions in L</"VERILATION ARGUMENTS"> for more information.
--prefix <topname> Name of top level class
--prof-cfuncs Name functions for profiling
--prof-threads Enable generating gantt chart data for threads
--protect-key <key> Key for symbol protection
--protect-ids Hash identifier names for obscurity
--private Debugging; see docs
--public Debugging; see docs
--public-flat-rw Mark all variables, etc as public_flat_rw
@ -1153,6 +1155,42 @@ When profiling is enabled, the runtime will emit a blurb of profiling data
in non-human-friendly form. The C<verilator_gantt> script will transform
this into a nicer visual format and produce some related statistics.
=item --protect-key I<key>
Specifies the private key for --protect-ids. For best security this key
should be 16 or more random bytes, a reasonable medium-security choice is
the output of uuidgen. Typically, a key would be created by the user once
for a given protected design library, then every Verilator run for
subsequent versions of that library would be passed the same
--protect-key. Thus, if the input Verilog is similar between library
versions (Verilator runs), the Verilated code will likewise be mostly
similar.
If --protect-key is not specified and a key is needed, Verilator will
generate a new key for every Verilator run. As the key is not saved, this
is best for security, but means every Verilator run will give vastly
different output even for identical input, perhaps harming compile times
(and certainly thrashing any I<ccache>).
=item --protect-ids
Hash any private identifiers (variable, module, and assertion block names
that are not on the top level) into hashed random-looking identifiers,
resulting after compilation in protected library binaries that expose less
design information. This hashing uses the provided or default
--protect-key, see important details there.
Verilator will also create a {prefix}__idmap.xml file which contains the
mapping from the hashed identifiers back to the original identifiers. This
idmap file is to be kept private, and is to assist mapping any runtime
design assertions, coverage, or trace information, which will report the
hashed identifiers, back to the original design's identifier names.
Using DPI imports/exports is allowed and generally relatively safe in terms
of information disclosed, which is limited to the DPI function prototyptes.
Use of the VPI is not recommended as many design details may be exposed,
and an INSECURE warning will be issued.
=item --private
Opposite of --public. Is the default; this option exists for backwards
@ -1910,6 +1948,7 @@ In certain debug and other modes, it also creates:
{prefix}__Trace{__n}.cpp // Wave file generation code (--trace)
{prefix}__cdc.txt // Clock Domain Crossing checks (--cdc)
{prefix}__stats.txt // Statistics (--stats)
{prefix}__idmap.txt // Symbol demangling (--protect-ids)
It also creates internal files that can be mostly ignored:
@ -3714,6 +3753,16 @@ non-delayed assignment. See also the COMBDLY warning.
Ignoring this warning may make Verilator simulations differ from other
simulators.
=item INSECURE
Warns that the combination of options selected may be defeating the attempt
to protect/obscure identifiers or hide information in the model. Correct
the options provided, or inspect the output code to see if the information
exposed is acceptable.
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
=item LITENDIAN
Warns that a packed vector is declared with little endian bit numbering

View File

@ -81,6 +81,7 @@ void AstNode::init() {
// Attributes
m_didWidth = false;
m_doingWidth = false;
m_protect = true;
m_user1u = VNUser(0);
m_user1Cnt = 0;
m_user2u = VNUser(0);
@ -133,6 +134,10 @@ string AstNode::encodeNumber(vlsint64_t num) {
}
}
string AstNode::nameProtect() const {
return VIdProtect::protectIf(name(), protect());
}
string AstNode::shortName() const {
string pretty = name();
string::size_type pos;

View File

@ -1165,6 +1165,7 @@ class AstNode {
// Attributes
bool m_didWidth:1; // Did V3Width computation
bool m_doingWidth:1; // Inside V3Width
bool m_protect:1; // Protect name if protection is on
// // Space for more bools here
// This member ordering both allows 64 bit alignment and puts associated data together
@ -1278,6 +1279,7 @@ public:
virtual void tag(const string& text) {}
virtual string tag() const { return ""; }
virtual string verilogKwd() const { return ""; }
string nameProtect() const; // Name with --protect-id applied
string shortName() const; // Name with __PVT__ removed for concatenating scopes
static string dedotName(const string& namein); // Name with dots removed
static string prettyName(const string& namein); // Name for printing out to the user
@ -1297,8 +1299,10 @@ public:
void didWidth(bool flag) { m_didWidth = flag; }
bool didWidth() const { return m_didWidth; }
bool didWidthAndSet() { if (didWidth()) return true; didWidth(true); return false; }
void doingWidth(bool flag) { m_doingWidth = flag; }
bool doingWidth() const { return m_doingWidth; }
void doingWidth(bool flag) { m_doingWidth = flag; }
bool protect() const { return m_protect; }
void protect(bool flag) { m_protect = flag; }
//TODO stomp these width functions out, and call via dtypep() instead
int width() const;
@ -1845,6 +1849,7 @@ public:
AstVarScope* varScopep() const { return m_varScopep; }
void varScopep(AstVarScope* varscp) { m_varScopep = varscp; }
string hiername() const { return m_hiername; }
string hiernameProtect() const;
void hiername(const string& hn) { m_hiername = hn; }
bool hierThis() const { return m_hierThis; }
void hierThis(bool flag) { m_hierThis = flag; }

View File

@ -56,6 +56,10 @@ void AstNodeVarRef::cloneRelink() {
if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep(); }
}
string AstNodeVarRef::hiernameProtect() const {
return VIdProtect::protectWordsIf(hiername(), protect());
}
int AstNodeSel::bitConst() const {
AstConst* constp = VN_CAST(bitp(), Const);
return (constp ? constp->toSInt() : 0);
@ -269,7 +273,7 @@ string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
oname += "&";
mayparen = true;
}
if (named) oname += " "+name();
if (named) oname += " "+VIdProtect::protectIf(name(), protect());
string oarray;
if (isDpiOpenArray() || direction().isRefOrConstRef()) {
@ -594,6 +598,10 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variabl
return nodep;
}
string AstCCall::hiernameProtect() const {
return VIdProtect::protectWordsIf(hiername(), protect());
}
const char* AstScope::broken() const {
BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());

View File

@ -6094,6 +6094,7 @@ public:
AstCFunc* funcp() const { return m_funcp; }
string hiername() const { return m_hiername; }
void hiername(const string& hn) { m_hiername = hn; }
string hiernameProtect() const;
void argTypes(const string& str) { m_argTypes = str; }
string argTypes() const { return m_argTypes; }
//

View File

@ -226,6 +226,7 @@ private:
funcp->slow(true);
funcp->isStatic(false);
funcp->entryPoint(true);
funcp->protect(false);
funcp->addInitsp(new AstCStmt
(nodep->fileline(),
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));

View File

@ -128,12 +128,12 @@ public:
if (const AstEnumDType* adtypep
= VN_CAST(nodep->dtypep()->skipRefToEnump(), EnumDType)) {
if (adtypep->width()>64) {
putsDecoration("// enum "+nodep->name()+" // Ignored: Too wide for C++\n");
putsDecoration("// enum "+nodep->nameProtect()+" // Ignored: Too wide for C++\n");
} else {
puts("enum "+nodep->name()+" {\n");
for (AstEnumItem* itemp = adtypep->itemsp();
itemp; itemp = VN_CAST(itemp->nextp(), EnumItem)) {
puts(itemp->name());
puts(itemp->nameProtect());
puts(" = ");
iterateAndNextNull(itemp->valuep());
if (VN_IS(itemp->nextp(), EnumItem)) puts(",");
@ -214,8 +214,8 @@ public:
virtual void visit(AstAlwaysPublic*) {
}
virtual void visit(AstCCall* nodep) {
puts(nodep->hiername());
puts(nodep->funcp()->name());
puts(nodep->hiernameProtect());
puts(nodep->funcp()->nameProtect());
puts("(");
puts(nodep->argTypes());
bool comma = (nodep->argTypes() != "");
@ -237,8 +237,14 @@ public:
}
virtual void visit(AstComment* nodep) {
string at;
if (nodep->showAt()) at = " at "+nodep->fileline()->ascii();
putsDecoration(string("// ")+nodep->name()+at+"\n");
if (nodep->showAt()) {
at = " at "+nodep->fileline()->ascii();
// If protecting, passthru less information about the design
if (!v3Global.opt.protectIds()) return;
}
if (!(nodep->protect() && v3Global.opt.protectIds())) {
putsDecoration(string("// ")+nodep->name()+at+"\n");
}
iterateChildren(nodep);
}
virtual void visit(AstCoverDecl* nodep) {
@ -251,12 +257,13 @@ public:
// hierarchies itself, and if verilator_cov also did it, you'd end up
// with (number-of-instant) times too many counts in this bin.
puts(", first"); // Enable, passed from __Vconfigure parameter
puts(", "); putsQuoted(nodep->fileline()->filename());
puts(", "); putsQuoted(protect(nodep->fileline()->filename()));
puts(", "); puts(cvtToStr(nodep->fileline()->lineno()));
puts(", "); puts(cvtToStr(nodep->column()));
puts(", "); putsQuoted((nodep->hier()!=""?".":"")+nodep->hier());
puts(", "); putsQuoted(nodep->page());
puts(", "); putsQuoted(nodep->comment());
puts(", "); putsQuoted((!nodep->hier().empty() ? "." : "")
+protectWordsIf(nodep->hier(), nodep->protect()));
puts(", "); putsQuoted(protectWordsIf(nodep->page(), nodep->protect()));
puts(", "); putsQuoted(protectWordsIf(nodep->comment(), nodep->protect()));
puts(");\n");
}
virtual void visit(AstCoverInc* nodep) {
@ -280,7 +287,7 @@ public:
if (!nodep->dpiExport()) {
// this is where the DPI import context scope is set
string scope = nodep->scopeDpiName();
putbs("(&(vlSymsp->__Vscope_"+scope+"))");
putbs("(&(vlSymsp->"+protect("__Vscope_"+scope)+"))");
}
}
virtual void visit(AstSFormat* nodep) {
@ -520,14 +527,14 @@ public:
}
virtual void visit(AstStop* nodep) {
puts("VL_STOP_MT(");
putsQuoted(nodep->fileline()->filename());
putsQuoted(protect(nodep->fileline()->filename()));
puts(",");
puts(cvtToStr(nodep->fileline()->lineno()));
puts(",\"\");\n");
}
virtual void visit(AstFinish* nodep) {
puts("VL_FINISH_MT(");
putsQuoted(nodep->fileline()->filename());
putsQuoted(protect(nodep->fileline()->filename()));
puts(",");
puts(cvtToStr(nodep->fileline()->lineno()));
puts(",\"\");\n");
@ -555,13 +562,13 @@ public:
iterateAndNextNull(nodep->bodysp());
}
virtual void visit(AstUCStmt* nodep) {
putsDecoration("// $c statement at "+nodep->fileline()->ascii()+"\n");
putsDecoration(ifNoProtect("// $c statement at "+nodep->fileline()->ascii()+"\n"));
iterateAndNextNull(nodep->bodysp());
puts("\n");
}
virtual void visit(AstUCFunc* nodep) {
puts("\n");
putsDecoration("// $c function at "+nodep->fileline()->ascii()+"\n");
putsDecoration(ifNoProtect("// $c function at "+nodep->fileline()->ascii()+"\n"));
iterateAndNextNull(nodep->bodysp());
puts("\n");
}
@ -701,8 +708,8 @@ public:
}
// Terminals
virtual void visit(AstVarRef* nodep) {
puts(nodep->hiername());
puts(nodep->varp()->name());
puts(nodep->hiernameProtect());
puts(nodep->varp()->nameProtect());
}
void emitCvtPackStr(AstNode* nodep) {
if (const AstConst* constp = VN_CAST(nodep, Const)) {
@ -756,8 +763,8 @@ public:
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
puts(assigntop->hiername());
puts(assigntop->varp()->name());
puts(assigntop->hiernameProtect());
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
@ -779,8 +786,8 @@ public:
if (!assigntop) {
puts(assignString);
} else if (VN_IS(assigntop, VarRef)) {
puts(assigntop->hiername());
puts(assigntop->varp()->name());
puts(assigntop->hiernameProtect());
puts(assigntop->varp()->nameProtect());
} else {
iterateAndNextNull(assigntop);
}
@ -1090,7 +1097,7 @@ class EmitCImp : EmitCStmts {
ExecMTask* mtp = nodep->execMTaskp();
puts("\n");
puts("void ");
puts(modClassName(m_modp)+"::"+mtp->cFuncName());
puts(modClassName(m_modp)+"::"+protect(mtp->cFuncName()));
puts("(bool even_cycle, void* symtab) {\n");
// Declare and set vlSymsp
@ -1119,13 +1126,13 @@ class EmitCImp : EmitCStmts {
if (nodep->ifdef()!="") puts("#ifdef "+nodep->ifdef()+"\n");
if (nodep->isInline()) puts("VL_INLINE_OPT ");
puts(nodep->rtnTypeVoid()); puts(" ");
puts(modClassName(m_modp)+"::"+nodep->name()
puts(modClassName(m_modp)+"::"+nodep->nameProtect()
+"("+cFuncArgs(nodep)+") {\n");
// "+" in the debug indicates a print from the model
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ ");
for (int i=0; i<m_modp->level(); ++i) { puts(" "); }
puts(modClassName(m_modp)+"::"+nodep->name()
puts(modClassName(m_modp)+"::"+nodep->nameProtect()
+"\\n\"); );\n");
// Declare and set vlTOPp
@ -1172,8 +1179,8 @@ class EmitCImp : EmitCStmts {
doubleOrDetect(changep, gotOne);
}
}
if (gotOne) {
puts(");\n");
if (gotOne) puts(");\n");
if (gotOne && !v3Global.opt.protectIds()) {
//puts("VL_DEBUG_IF( if (__req) cout<<\"- CLOCKREQ );");
for (std::vector<AstChangeDet*>::iterator it = m_blkChangeDetVec.begin();
it != m_blkChangeDetVec.end(); ++it) {
@ -1232,14 +1239,14 @@ class EmitCImp : EmitCStmts {
if (runInline) {
// The thread calling eval() will run this mtask inline,
// along with its packed successors.
puts(execMTasks[i]->cFuncName()
puts(protect(execMTasks[i]->cFuncName())
+ "(vlTOPp->__Vm_even_cycle, vlSymsp);\n");
puts("Verilated::mtaskId(0);\n");
} else {
// The other N-1 go to the thread pool.
puts("vlTOPp->__Vm_threadPoolp->workerp("
+ cvtToStr(i)+")->addTask("
+ execMTasks[i]->cFuncName()
+ protect(execMTasks[i]->cFuncName())
+ ", vlTOPp->__Vm_even_cycle, vlSymsp);\n");
}
}
@ -1307,7 +1314,7 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
puts(nodep->scType());
puts("> ");
}
puts(nodep->name());
puts(nodep->nameProtect());
emitDeclArrayBrackets(nodep);
puts(";\n");
} else if (basicp && basicp->isOpaque()) {
@ -1326,7 +1333,7 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
else if (nodep->widthMin() <= 16) puts("16");
else if (nodep->isWide()) puts("W");
puts("("+nodep->name());
puts("("+nodep->nameProtect());
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole
// thing, msb/lsb is just lowest dimension
@ -1357,7 +1364,7 @@ void EmitCStmts::emitVarDecl(const AstVar* nodep, const string& prefixIfImp) {
puts("SIGW(");
}
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
puts(nodep->name());
puts(nodep->nameProtect());
emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole
// thing, msb/lsb is just lowest dimension
@ -1387,12 +1394,12 @@ void EmitCStmts::emitVarCtors(bool* firstp) {
bool isArray = !VN_CAST(varp->dtypeSkipRefp(), BasicDType);
if (isArray) {
puts("// Skipping array: ");
puts(varp->name());
puts(varp->nameProtect());
puts("\n");
} else {
emitCtorSep(firstp);
puts(varp->name());
puts("("); putsQuoted(varp->name()); puts(")");
puts(varp->nameProtect());
puts("("); putsQuoted(varp->nameProtect()); puts(")");
}
}
puts("\n#endif\n");
@ -1456,8 +1463,8 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format,
UASSERT_OBJ(m_wideTempRefp, nodep,
"Wide Op w/ no temp, perhaps missing op in V3EmitC?");
COMMA;
puts(m_wideTempRefp->hiername());
puts(m_wideTempRefp->varp()->name());
puts(m_wideTempRefp->hiernameProtect());
puts(m_wideTempRefp->varp()->nameProtect());
m_wideTempRefp = NULL;
needComma = true;
}
@ -1727,7 +1734,7 @@ void EmitCImp::emitVarReset(AstVar* varp) {
UASSERT_OBJ(varp->valuep(), varp, "No init for a param?");
// If a simple CONST value we initialize it using an enum
// If an ARRAYINIT we initialize it using an initial block similar to a signal
//puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n");
//puts("// parameter "+varp->nameProtect()+" = "+varp->valuep()->name()+"\n");
}
else if (AstInitArray* initarp = VN_CAST(varp->valuep(), InitArray)) {
if (AstUnpackArrayDType* arrayp = VN_CAST(varp->dtypeSkipRefp(), UnpackArrayDType)) {
@ -1736,7 +1743,8 @@ void EmitCImp::emitVarReset(AstVar* varp) {
puts("{ int __Vi=0;");
puts(" for (; __Vi<"+cvtToStr(arrayp->elementsConst()));
puts("; ++__Vi) {\n");
emitSetVarConstant(varp->name()+"[__Vi]", VN_CAST(initarp->defaultp(), Const));
emitSetVarConstant(varp->nameProtect()+"[__Vi]",
VN_CAST(initarp->defaultp(), Const));
puts("}}\n");
}
int pos = 0;
@ -1744,7 +1752,8 @@ void EmitCImp::emitVarReset(AstVar* varp) {
int index = initarp->posIndex(pos);
UASSERT_OBJ(initarp->defaultp() || index==pos, initarp,
"Not enough values in array initialization");
emitSetVarConstant(varp->name()+"["+cvtToStr(index)+"]", VN_CAST(itemp, Const));
emitSetVarConstant(varp->nameProtect()
+"["+cvtToStr(index)+"]", VN_CAST(itemp, Const));
}
} else {
varp->v3fatalSrc("InitArray under non-arrayed var");
@ -1780,11 +1789,11 @@ void EmitCImp::emitVarReset(AstVar* varp) {
else puts("VL_RAND_RESET_W(");
puts(cvtToStr(varp->widthMin()));
puts(",");
puts(varp->name());
puts(varp->nameProtect());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(");\n");
} else {
puts(varp->name());
puts(varp->nameProtect());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
// If --x-initial-edge is set, we want to force an initial
// edge on uninitialized clocks (from 'X' to whatever the
@ -1868,7 +1877,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
puts("\n");
}
putsDecoration("// Reset structure values\n");
puts("_ctor_var_reset();\n");
puts(protect("_ctor_var_reset")+"();\n");
emitTextSection(AstType::atScCtor);
if (modp->isTop() && v3Global.opt.mtasks()) {
@ -1907,11 +1916,12 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) {
}
void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
puts("\nvoid "+modClassName(modp)+"::__Vconfigure("+symClassName()+"* vlSymsp, bool first) {\n");
puts("\nvoid "+modClassName(modp)+"::"+protect("__Vconfigure")
+"("+symClassName()+"* vlSymsp, bool first) {\n");
puts( "if (0 && first) {} // Prevent unused\n");
puts( "this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it.
if (v3Global.opt.coverage() ) {
puts("this->_configure_coverage(vlSymsp, first);\n");
puts(protect("_configure_coverage")+"(vlSymsp, first);\n");
}
puts("}\n");
splitSizeInc(10);
@ -1962,7 +1972,7 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string op = de ? ">>" : "<<";
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
puts("void "+modClassName(modp)+"::"+funcname+"("+classname+"& os) {\n");
puts("void "+modClassName(modp)+"::"+protect(funcname)+"("+classname+"& os) {\n");
// Place a computed checksum to insure proper structure save/restore formatting
// OK if this hash includes some things we won't dump, since
// just looking for loading the wrong model
@ -2019,7 +2029,7 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
puts(" for (; "+ivar+"<"+cvtToStr(elementp->widthWords()));
puts("; ++"+ivar+") {\n");
}
puts("os"+op+varp->name());
puts("os"+op+varp->nameProtect());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(";\n");
for (int v=0; v<vects; ++v) puts( "}}\n");
@ -2028,7 +2038,7 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
}
if (modp->isTop()) { // Save the children
puts( "__VlSymsp->"+funcname+"(os);\n");
puts( "__VlSymsp->"+protect(funcname)+"(os);\n");
}
puts("}\n");
}
@ -2051,10 +2061,8 @@ void EmitCImp::emitTextSection(AstType type) {
if (last_line < 0) {
puts("\n//*** Below code from `systemc in Verilog file\n");
}
ofp()->putsNoTracking("//#line "+cvtToStr(nodep->fileline()->lineno())
+" ");
ofp()->putsQuoted(nodep->fileline()->filename());
ofp()->putsNoTracking("\n");
putsDecoration(ifNoProtect("// From `systemc at "
+nodep->fileline()->ascii()+"\n"));
last_line = nodep->fileline()->lineno();
}
ofp()->putsNoTracking(textp->text());
@ -2075,7 +2083,7 @@ void EmitCImp::emitCellCtors(AstNodeModule* modp) {
}
for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstCell* cellp = VN_CAST(nodep, Cell)) {
puts("VL_CELL("+cellp->name()+", "+modClassName(cellp->modp())+");\n");
puts("VL_CELL("+cellp->nameProtect()+", "+modClassName(cellp->modp())+");\n");
}
}
}
@ -2105,7 +2113,7 @@ void EmitCImp::emitSensitives() {
puts(" for (; "+ivar+"<="+cvtToStr(arrayp->msb()));
puts("; ++"+ivar+") {\n");
}
puts("sensitive << "+varp->name());
puts("sensitive << "+varp->nameProtect());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
puts(";\n");
for (int v=0; v<vects; ++v) puts( "}}\n");
@ -2128,13 +2136,13 @@ void EmitCImp::emitSettleLoop(const std::string& eval_call, bool initial) {
puts( "// Note you must run make with OPT=-DVL_DEBUG for debug prints.\n");
puts( "int __Vsaved_debug = Verilated::debug();\n");
puts( "Verilated::debug(1);\n");
puts( "__Vchange = _change_request(vlSymsp);\n");
puts( "__Vchange = "+protect("_change_request")+"(vlSymsp);\n");
puts( "Verilated::debug(__Vsaved_debug);\n");
puts( "VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Verilated model didn't ");
if (initial) puts("DC ");
puts( "converge\");\n");
puts( "} else {\n");
puts( "__Vchange = _change_request(vlSymsp);\n");
puts( "__Vchange = "+protect("_change_request")+"(vlSymsp);\n");
puts( "}\n");
puts("} while (VL_UNLIKELY(__Vchange));\n");
}
@ -2146,10 +2154,11 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
puts(EmitCBaseVisitor::symTopAssign()+"\n");
puts("#ifdef VL_DEBUG\n");
putsDecoration("// Debug assertions\n");
puts("_eval_debug_assertions();\n");
puts(protect("_eval_debug_assertions")+"();\n");
puts("#endif // VL_DEBUG\n");
putsDecoration("// Initialize\n");
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) _eval_initial_loop(vlSymsp);\n");
puts("if (VL_UNLIKELY(!vlSymsp->__Vm_didInit)) "
+protect("_eval_initial_loop")+"(vlSymsp);\n");
if (v3Global.opt.inhibitSim()) {
puts("if (VL_UNLIKELY(__Vm_inhibitSim)) return;\n");
}
@ -2201,7 +2210,7 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
emitSettleLoop(
(string("VL_DEBUG_IF(VL_DBG_MSGF(\"+ Clock loop\\n\"););\n")
+ (v3Global.opt.trace() ? "vlSymsp->__Vm_activity = true;\n" : "")
+ "_eval(vlSymsp);"), false);
+ protect("_eval")+"(vlSymsp);"), false);
if (v3Global.opt.threads() == 1) {
puts("Verilated::endOfThreadMTask(vlSymsp->__Vm_evalMsgQp);\n");
}
@ -2212,14 +2221,15 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
splitSizeInc(10);
//
puts("\nvoid "+modClassName(modp)+"::_eval_initial_loop("+EmitCBaseVisitor::symClassVar()+") {\n");
puts("\nvoid "+modClassName(modp)+"::"+protect("_eval_initial_loop")
+"("+EmitCBaseVisitor::symClassVar()+") {\n");
puts("vlSymsp->__Vm_didInit = true;\n");
puts("_eval_initial(vlSymsp);\n");
puts(protect("_eval_initial")+"(vlSymsp);\n");
if (v3Global.opt.trace()) {
puts("vlSymsp->__Vm_activity = true;\n");
}
emitSettleLoop((string("_eval_settle(vlSymsp);\n")
+"_eval(vlSymsp);"), true);
emitSettleLoop((protect("_eval_settle")+"(vlSymsp);\n"
+protect("_eval")+"(vlSymsp);"), true);
puts("}\n");
splitSizeInc(10);
}
@ -2428,7 +2438,8 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
if (funcp->ifdef()!="") puts("#ifdef "+funcp->ifdef()+"\n");
if (funcp->isStatic().trueU()) puts("static ");
puts(funcp->rtnTypeVoid()); puts(" ");
puts(funcp->name()); puts("("+cFuncArgs(funcp)+")");
puts(funcp->nameProtect());
puts("("+cFuncArgs(funcp)+")");
if (funcp->slow()) puts(" VL_ATTR_COLD");
puts(";\n");
if (funcp->ifdef()!="") puts("#endif // "+funcp->ifdef()+"\n");
@ -2446,7 +2457,7 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
if (mtp->threadRoot()) {
// Emit function declaration for this mtask
ofp()->putsPrivate(true);
puts("static void "); puts(mtp->cFuncName());
puts("static void "); puts(protect(mtp->cFuncName()));
puts("(bool even_cycle, void* symtab);\n");
}
}
@ -2558,7 +2569,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (modp->isTop()) puts("// Public to allow access to /*verilator_public*/ items;\n");
if (modp->isTop()) puts("// otherwise the application code can consider these internals.\n");
}
puts(modClassName(cellp->modp())+"* "+cellp->name()+";\n");
puts(modClassName(cellp->modp())+"* "+cellp->nameProtect()+";\n");
}
}
}
@ -2604,16 +2615,16 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
// These should be static const values, however microsloth VC++ doesn't
// support them. They also cause problems with GDB under GCC2.95.
if (varp->isWide()) { // Unsupported for output
putsDecoration("// enum WData "+varp->name()+" //wide");
putsDecoration("// enum WData "+varp->nameProtect()+" //wide");
} else if (!VN_IS(varp->valuep(), Const)) { // Unsupported for output
//putsDecoration("// enum ..... "+varp->name()
//putsDecoration("// enum ..... "+varp->nameProtect()
// +"not simple value, see variable above instead");
} else if (VN_IS(varp->dtypep(), BasicDType)
&& VN_CAST(varp->dtypep(), BasicDType)->isOpaque()) { // Can't put out e.g. doubles
} else {
puts("enum ");
puts(varp->isQuad()?"_QData":"_IData");
puts(""+varp->name()+" { "+varp->name()+" = ");
puts(""+varp->nameProtect()+" { "+varp->nameProtect()+" = ");
iterateAndNextNull(varp->valuep());
puts("};");
}
@ -2672,27 +2683,28 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n// INTERNAL METHODS\n");
if (modp->isTop()) {
ofp()->putsPrivate(true); // private:
puts("static void _eval_initial_loop("+EmitCBaseVisitor::symClassVar()+");\n");
puts("static void "+protect("_eval_initial_loop")
+"("+EmitCBaseVisitor::symClassVar()+");\n");
}
ofp()->putsPrivate(false); // public:
puts("void __Vconfigure("+symClassName()+"* symsp, bool first);\n");
puts("void "+protect("__Vconfigure")+"("+symClassName()+"* symsp, bool first);\n");
emitIntFuncDecls(modp);
if (v3Global.opt.trace()) {
ofp()->putsPrivate(false); // public:
puts("static void traceInit("+v3Global.opt.traceClassBase()
puts("static void "+protect("traceInit")+"("+v3Global.opt.traceClassBase()
+"* vcdp, void* userthis, uint32_t code);\n");
puts("static void traceFull("+v3Global.opt.traceClassBase()
puts("static void "+protect("traceFull")+"("+v3Global.opt.traceClassBase()
+"* vcdp, void* userthis, uint32_t code);\n");
puts("static void traceChg("+v3Global.opt.traceClassBase()
puts("static void "+protect("traceChg")+"("+v3Global.opt.traceClassBase()
+"* vcdp, void* userthis, uint32_t code);\n");
}
if (v3Global.opt.savable()) {
ofp()->putsPrivate(false); // public:
puts("void __Vserialize(VerilatedSerialize& os);\n");
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
puts("void "+protect("__Vserialize")+"(VerilatedSerialize& os);\n");
puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n");
puts("\n");
}
@ -2703,10 +2715,10 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (v3Global.opt.savable() && modp->isTop()) {
puts("inline VerilatedSerialize& operator<<(VerilatedSerialize& os, "
+modClassName(modp)+"& rhs) {\n"
"Verilated::quiesce(); rhs.__Vserialize(os); return os; }\n");
"Verilated::quiesce(); rhs."+protect("__Vserialize")+"(os); return os; }\n");
puts("inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, "
+modClassName(modp)+"& rhs) {\n"
"Verilated::quiesce(); rhs.__Vdeserialize(os); return os; }\n");
"Verilated::quiesce(); rhs."+protect("__Vdeserialize")+"(os); return os; }\n");
puts("\n");
}
@ -2838,8 +2850,8 @@ class EmitCTrace : EmitCStmts {
// METHODS
void newOutCFile(int filenum) {
string filename = (v3Global.opt.makeDir()+"/"+ topClassName()
+"__Trace");
string filename = (v3Global.opt.makeDir()+"/"
+topClassName()+"_"+protect("_Trace"));
if (filenum) filename += "__"+cvtToStr(filenum);
filename += (m_slow ? "__Slow":"");
filename += ".cpp";
@ -2868,13 +2880,13 @@ class EmitCTrace : EmitCStmts {
puts("void "+topClassName()+"::trace(");
puts(v3Global.opt.traceClassBase()+"C* tfp, int, int) {\n");
puts( "tfp->spTrace()->addCallback("
"&"+topClassName()+"::traceInit"
+", &"+topClassName()+"::traceFull"
+", &"+topClassName()+"::traceChg, this);\n");
"&"+topClassName()+"::"+protect("traceInit")
+", &"+topClassName()+"::"+protect("traceFull")
+", &"+topClassName()+"::"+protect("traceChg")+", this);\n");
puts("}\n");
splitSizeInc(10);
puts("void "+topClassName()+"::traceInit("
puts("void "+topClassName()+"::"+protect("traceInit")+"("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
putsDecoration("// Callback from vcd->open()\n");
puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n");
@ -2883,17 +2895,17 @@ class EmitCTrace : EmitCStmts {
puts( "VL_FATAL_MT(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
puts("}\n");
puts("vcdp->scopeEscape(' ');\n");
puts("t->traceInitThis(vlSymsp, vcdp, code);\n");
puts("t->"+protect("traceInitThis")+"(vlSymsp, vcdp, code);\n");
puts("vcdp->scopeEscape('.');\n"); // Restore so later traced files won't break
puts("}\n");
splitSizeInc(10);
puts("void "+topClassName()+"::traceFull("
puts("void "+topClassName()+"::"+protect("traceFull")+"("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
putsDecoration("// Callback from vcd->dump()\n");
puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n");
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
puts("t->traceFullThis(vlSymsp, vcdp, code);\n");
puts("t->"+protect("traceFullThis")+"(vlSymsp, vcdp, code);\n");
puts("}\n");
splitSizeInc(10);
@ -2903,13 +2915,13 @@ class EmitCTrace : EmitCStmts {
void emitTraceFast() {
puts("\n//======================\n\n");
puts("void "+topClassName()+"::traceChg("
puts("void "+topClassName()+"::"+protect("traceChg")+"("
+v3Global.opt.traceClassBase()+"* vcdp, void* userthis, uint32_t code) {\n");
putsDecoration("// Callback from vcd->dump()\n");
puts(topClassName()+"* t = ("+topClassName()+"*)userthis;\n");
puts(EmitCBaseVisitor::symClassVar()+" = t->__VlSymsp; // Setup global symbol table\n");
puts("if (vlSymsp->getClearActivity()) {\n");
puts("t->traceChgThis(vlSymsp, vcdp, code);\n");
puts("t->"+protect("traceChgThis")+"(vlSymsp, vcdp, code);\n");
puts("}\n");
puts("}\n");
splitSizeInc(10);
@ -2954,7 +2966,7 @@ class EmitCTrace : EmitCStmts {
puts("(c+"+cvtToStr(nodep->code()));
if (nodep->arrayRange().ranged()) puts("+i*"+cvtToStr(nodep->widthWords()));
puts(",");
putsQuoted(nodep->showname());
putsQuoted(VIdProtect::protectWordsIf(nodep->showname(), nodep->protect()));
// Direction
if (v3Global.opt.traceFormat().fstFlavor()) {
puts(","+cvtToStr(enumNum));
@ -3033,7 +3045,7 @@ class EmitCTrace : EmitCStmts {
enump->user1(enumNum);
int nvals = 0;
puts("{\n");
puts("const char* __VenumItemNames[]\n");
puts("const char* "+protect("__VenumItemNames")+"[]\n");
puts("= {");
for (AstEnumItem* itemp = enump->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
@ -3042,7 +3054,7 @@ class EmitCTrace : EmitCStmts {
}
puts("};\n");
nvals = 0;
puts("const char* __VenumItemValues[]\n");
puts("const char* "+protect("__VenumItemValues")+"[]\n");
puts("= {");
for (AstEnumItem* itemp = enump->itemsp(); itemp;
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
@ -3055,7 +3067,9 @@ class EmitCTrace : EmitCStmts {
+", \""+enump->prettyName()+"\", "
+cvtToStr(nvals)
+", "+cvtToStr(enump->widthMin())
+", __VenumItemNames, __VenumItemValues);\n");
+", "+protect("__VenumItemNames")
+", "+protect("__VenumItemValues")
+");\n");
puts("}\n");
}
return enumNum;
@ -3146,7 +3160,7 @@ class EmitCTrace : EmitCStmts {
puts("\n");
puts(nodep->rtnTypeVoid()); puts(" ");
puts(topClassName()+"::"+nodep->name()
puts(topClassName()+"::"+nodep->nameProtect()
+"("+cFuncArgs(nodep)+") {\n");
if (nodep->symProlog()) puts(EmitCBaseVisitor::symTopAssign()+"\n");

View File

@ -46,7 +46,13 @@ public:
void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); }
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
bool optSystemC() { return v3Global.opt.systemC(); }
static string symClassName() { return v3Global.opt.prefix()+"__Syms"; }
static string protect(const string& name) { return VIdProtect::protectIf(name, true); }
static string protectIf(const string& name, bool doIt) {
return VIdProtect::protectIf(name, doIt); }
static string protectWordsIf(const string& name, bool doIt) {
return VIdProtect::protectWordsIf(name, doIt); }
static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; }
static string symClassName() { return v3Global.opt.prefix()+"_"+protect("_Syms"); }
static string symClassVar() { return symClassName()+"* __restrict vlSymsp"; }
static string symTopAssign() {
return v3Global.opt.prefix()+"* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;"; }
@ -54,7 +60,7 @@ public:
if (modp->isTop()) {
return v3Global.opt.prefix();
} else {
return v3Global.opt.modPrefix() + "_" + modp->name();
return v3Global.opt.modPrefix()+"_"+protect(modp->name());
}
}
static string topClassName() { // Return name of top wrapper module

View File

@ -405,7 +405,7 @@ void EmitCSyms::emitSymHdr() {
for (ScopeFuncs::iterator it = m_scopeFuncs.begin(); it != m_scopeFuncs.end(); ++it) {
AstCFunc* funcp = it->second.m_funcp;
if (funcp->dpiExport()) {
string cbtype = v3Global.opt.prefix()+"__Vcb_"+funcp->cname()+"_t";
string cbtype = protect(v3Global.opt.prefix()+"__Vcb_"+funcp->cname()+"_t");
types["typedef void (*"+cbtype+") ("+cFuncArgs(funcp)+");\n"] = 1;
}
}
@ -430,11 +430,11 @@ void EmitCSyms::emitSymHdr() {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (modp->isTop()) {
ofp()->printf("%-30s ", (modClassName(modp)+"*").c_str());
puts(scopep->nameDotless()+"p;\n");
puts(protectIf(scopep->nameDotless()+"p", scopep->protect())+";\n");
}
else {
ofp()->printf("%-30s ", (modClassName(modp)+"").c_str());
puts(scopep->nameDotless()+";\n");
puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n");
}
}
@ -446,7 +446,7 @@ void EmitCSyms::emitSymHdr() {
if (!m_scopeNames.empty()) { // Scope names
puts("\n// SCOPE NAMES\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
puts("VerilatedScope __Vscope_"+it->second.m_symName+";\n");
puts("VerilatedScope "+protect("__Vscope_"+it->second.m_symName)+";\n");
}
}
@ -476,8 +476,8 @@ void EmitCSyms::emitSymHdr() {
puts("inline bool getClearActivity() { bool r=__Vm_activity; __Vm_activity=false; return r; }\n");
}
if (v3Global.opt.savable() ) {
puts("void __Vserialize(VerilatedSerialize& os);\n");
puts("void __Vdeserialize(VerilatedDeserialize& os);\n");
puts("void "+protect("__Vserialize")+"(VerilatedSerialize& os);\n");
puts("void "+protect("__Vdeserialize")+"(VerilatedDeserialize& os);\n");
}
puts("\n");
puts("} VL_ATTR_ALIGNED(64);\n");
@ -558,7 +558,7 @@ void EmitCSyms::emitSymImp() {
string funcname = de ? "__Vdeserialize" : "__Vserialize";
string op = de ? ">>" : "<<";
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
puts("void "+symClassName()+"::"+funcname+"("+classname+"& os) {\n");
puts("void "+symClassName()+"::"+protect(funcname)+"("+classname+"& os) {\n");
puts( "// LOCAL STATE\n");
// __Vm_namep presumably already correct
if (v3Global.opt.trace()) {
@ -570,7 +570,8 @@ void EmitCSyms::emitSymImp() {
it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (!modp->isTop()) {
puts( scopep->nameDotless()+"."+funcname+"(os);\n");
puts(protectIf(scopep->nameDotless(), scopep->protect())
+"."+protect(funcname)+"(os);\n");
}
}
puts("}\n");
@ -593,10 +594,10 @@ void EmitCSyms::emitSymImp() {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (modp->isTop()) {
} else {
puts(string(" ")+comma+" "+scopep->nameDotless());
puts(string(" ")+comma+" "+protect(scopep->nameDotless()));
puts("(Verilated::catName(topp->name(),");
// The "." is added by catName
putsQuoted(scopep->prettyName());
putsQuoted(protectWordsIf(scopep->prettyName(), scopep->protect()));
puts("))\n");
comma = ',';
++m_numStmts;
@ -617,15 +618,16 @@ void EmitCSyms::emitSymImp() {
arrow.replace(pos, 1, "->");
}
if (arrow.substr(0, 5) == "TOP->") arrow.replace(0, 5, "TOPp->");
ofp()->printf("%-30s ", arrow.c_str());
string arrowProt = protectWordsIf(arrow, scopep->protect());
ofp()->printf("%-30s ", arrowProt.c_str());
puts(" = &");
puts(scopep->nameDotless()+";\n");
puts(protectIf(scopep->nameDotless(), scopep->protect())+";\n");
++m_numStmts;
}
}
puts("// Setup each module's pointer back to symbol table (for public functions)\n");
puts("TOPp->__Vconfigure(this, true);\n");
puts("TOPp->"+protect("__Vconfigure")+"(this, true);\n");
for (std::vector<ScopeModPair>::iterator it = m_scopes.begin(); it != m_scopes.end(); ++it) {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (!modp->isTop()) {
@ -633,7 +635,8 @@ void EmitCSyms::emitSymImp() {
// first is used by AstCoverDecl's call to __vlCoverInsert
bool first = !modp->user1();
modp->user1(true);
puts(scopep->nameDotless()+".__Vconfigure(this, "
puts(protectIf(scopep->nameDotless(), scopep->protect())
+"."+protect("__Vconfigure")+"(this, "
+(first?"true":"false")
+");\n");
++m_numStmts;
@ -644,10 +647,11 @@ void EmitCSyms::emitSymImp() {
puts("// Setup scopes\n");
for (ScopeNames::iterator it = m_scopeNames.begin(); it != m_scopeNames.end(); ++it) {
checkSplit(false);
puts("__Vscope_"+it->second.m_symName+".configure(this,name(),");
putsQuoted(it->second.m_prettyName);
puts(protect("__Vscope_"+it->second.m_symName)
+".configure(this, name(), ");
putsQuoted(protectWordsIf(it->second.m_prettyName, true));
puts(", ");
putsQuoted(scopeDecodeIdentifier(it->second.m_prettyName));
putsQuoted(protect(scopeDecodeIdentifier(it->second.m_prettyName)));
puts(", VerilatedScope::"+it->second.m_type+");\n");
++m_numStmts;
}
@ -661,7 +665,7 @@ void EmitCSyms::emitSymImp() {
if (it->first == "TOP") continue;
name = name.replace(0, 4, ""); // Remove the "TOP."
if ((name.find(".") == string::npos) && (it->second.m_type == "SCOPE_MODULE")) {
puts("__Vhier.add(0, &__Vscope_" + it->second.m_symName + ");\n");
puts("__Vhier.add(0, &"+protect("__Vscope_"+it->second.m_symName)+");\n");
}
}
@ -676,8 +680,8 @@ void EmitCSyms::emitSymImp() {
UASSERT(from != m_scopeNames.end(), fromname+" not in m_scopeNames");
UASSERT(to != m_scopeNames.end(), toname+" not in m_scopeNames");
puts("__Vhier.add(");
puts("&__Vscope_"+from->second.m_symName+", ");
puts("&__Vscope_"+to->second.m_symName+");\n");
puts("&"+protect("__Vscope_"+from->second.m_symName)+", ");
puts("&"+protect("__Vscope_"+to->second.m_symName)+");\n");
}
}
puts("\n");
@ -695,12 +699,12 @@ void EmitCSyms::emitSymImp() {
AstNodeModule* modp = it->second.m_modp;
if (funcp->dpiExport()) {
checkSplit(true);
puts("__Vscope_"+scopep->scopeSymName()+".exportInsert(__Vfinal,");
putsQuoted(funcp->cname());
puts(protect("__Vscope_"+scopep->scopeSymName())+".exportInsert(__Vfinal, ");
putsQuoted(funcp->cname()); // Not protected - user asked for import/export
puts(", (void*)(&");
puts(modClassName(modp));
puts("::");
puts(funcp->name());
puts(funcp->nameProtect());
puts("));\n");
++m_numStmts;
}
@ -738,17 +742,17 @@ void EmitCSyms::emitSymImp() {
if (pdim>1 || udim>1) {
puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays
}
puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,");
putsQuoted(it->second.m_varBasePretty);
puts(protect("__Vscope_"+it->second.m_scopeName)+".varInsert(__Vfinal,");
putsQuoted(protect(it->second.m_varBasePretty));
puts(", &(");
if (modp->isTop()) {
puts(scopep->nameDotless());
puts("p->");
puts(protectIf(scopep->nameDotless()+"p", scopep->protect()));
puts("->");
} else {
puts(scopep->nameDotless());
puts(protectIf(scopep->nameDotless(), scopep->protect()));
puts(".");
}
puts(varp->name());
puts(varp->nameProtect());
puts("), ");
puts(varp->vlEnumType()); // VLVT_UINT32 etc
puts(",");
@ -796,13 +800,15 @@ void EmitCSyms::emitDpiHdr() {
AstCFunc* nodep = *it;
if (nodep->dpiExportWrapper()) {
if (!firstExp++) puts("\n// DPI EXPORTS\n");
puts("// DPI export at "+nodep->fileline()->ascii()+"\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+");\n");
puts("// DPI export"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->nameProtect()
+"("+cFuncArgs(nodep)+");\n");
}
else if (nodep->dpiImport()) {
if (!firstImp++) puts("\n// DPI IMPORTS\n");
puts("// DPI import at "+nodep->fileline()->ascii()+"\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+");\n");
puts("// DPI import"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n");
puts("extern "+nodep->rtnTypeVoid()+" "+nodep->nameProtect()
+"("+cFuncArgs(nodep)+");\n");
}
}
@ -846,7 +852,7 @@ void EmitCSyms::emitDpiImp() {
puts("#ifndef _VL_DPIDECL_"+nodep->name()+"\n");
puts("#define _VL_DPIDECL_"+nodep->name()+"\n");
puts(nodep->rtnTypeVoid()+" "+nodep->name()+"("+cFuncArgs(nodep)+") {\n");
puts("// DPI Export at "+nodep->fileline()->ascii()+"\n");
puts("// DPI export"+ifNoProtect(" at "+nodep->fileline()->ascii())+"\n");
puts("return "+topClassName()+"::"+nodep->name()+"(");
string args;
for (AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {

View File

@ -88,6 +88,7 @@ public:
INCABSPATH, // Include has absolute path
INFINITELOOP, // Infinite loop
INITIALDLY, // Initial delayed statement
INSECURE, // Insecure options
LITENDIAN, // Little bit endian vector
MODDUP, // Duplicate module
MULTIDRIVEN, // Driven from multiple blocks
@ -145,7 +146,7 @@ public:
"ENDLABEL", "GENCLK",
"IFDEPTH", "IGNOREDRETURN",
"IMPERFECTSCH", "IMPLICIT", "IMPORTSTAR", "IMPURE",
"INCABSPATH", "INFINITELOOP", "INITIALDLY",
"INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE",
"LITENDIAN", "MODDUP",
"MULTIDRIVEN", "MULTITOP",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY", "PROCASSWIRE",

View File

@ -917,3 +917,124 @@ void V3OutFile::putsForceIncs() {
puts("#include \""+*it+"\"\n");
}
}
//######################################################################
// VIdProtect
class VIdProtectImp {
// MEMBERS
typedef std::map<string,string> IdMap;
IdMap m_nameMap; // Map of old name into new name
typedef vl_unordered_set<std::string> IdSet;
IdSet m_newIdSet; // Which new names exist
protected:
// CONSTRUCTORS
friend class VIdProtect;
static VIdProtectImp& singleton() { static VIdProtectImp s; return s; }
public:
VIdProtectImp() {
passthru("this");
passthru("TOPp");
passthru("vlTOPp");
passthru("vlSymsp");
}
~VIdProtectImp() {}
// METHODS
string passthru(const string& old) {
if (!v3Global.opt.protectIds()) return old;
IdMap::iterator it = m_nameMap.find(old);
if (it != m_nameMap.end()) {
// No way to go back and correct the older crypt name
UASSERT(old == it->second, "Passthru request for '"
+old+"' after already --protect-ids of it.");
}
else {
m_nameMap.insert(make_pair(old, old));
m_newIdSet.insert(old);
}
return old;
}
string protectIf(const string& old, bool doIt) {
if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old;
IdMap::iterator it = m_nameMap.find(old);
if (it != m_nameMap.end()) return it->second;
else {
string out;
if (v3Global.opt.debugProtect()) {
// This lets us see the symbol being protected to debug cases
// where e.g. the definition is protect() but reference is
// missing a protect()
out = "PS"+old;
} else {
VHashSha256 digest (v3Global.opt.protectKeyDefaulted());
digest.insert(old);
// Add "PS" prefix (Protect Symbols) as cannot start symbol with number
out = "PS"+digest.digestSymbol();
// See if we can shrink the digest symbol to something smaller
for (size_t len = 6; len < out.size() - 3; len += 3) {
string tryout = out.substr(0, len);
if (m_newIdSet.find(tryout) == m_newIdSet.end()) {
out = tryout;
break;
}
}
}
m_nameMap.insert(make_pair(old, out));
m_newIdSet.insert(out);
return out;
}
}
string protectWordsIf(const string& old, bool doIt) {
// Split at " " (for traces), "." (for scopes), or "->" (for scopes)
if (!(doIt && v3Global.opt.protectIds())) return old;
string out;
string::size_type start = 0;
// space, ., ->
while (1) {
// When C++11, use find_if and lambda
string::size_type pos = string::npos;
string separator = "";
trySep(old, start, " ", pos/*ref*/, separator/*ref*/);
trySep(old, start, ".", pos/*ref*/, separator/*ref*/);
trySep(old, start, "->", pos/*ref*/, separator/*ref*/);
if (pos == string::npos) break;
out += protectIf(old.substr(start, pos-start), true) + separator;
start = pos + separator.length();
}
out += protectIf(old.substr(start), true);
return out;
}
void writeMapFile(const string& filename) const {
V3OutXmlFile of (filename);
of.putsHeader();
of.puts("<!-- DESCR" "IPTION: Verilator output: XML representation of netlist -->\n");
of.puts("<verilator_id_map>\n");
{
for (IdMap::const_iterator it = m_nameMap.begin(); it != m_nameMap.end(); ++it) {
of.puts("<map from=\""+it->second+"\" to=\""+it->first+"\"/>\n");
}
}
of.puts("</verilator_id_map>\n");
}
private:
void trySep(const string& old, string::size_type start, const string& trySep,
string::size_type& posr, string& separatorr) {
string::size_type trypos = old.find(trySep, start);
if (trypos != string::npos) {
if (posr == string::npos || (posr > trypos)) {
posr = trypos;
separatorr = trySep;
}
}
}
};
string VIdProtect::protectIf(const string& old, bool doIt) {
return VIdProtectImp::singleton().protectIf(old, doIt);
}
string VIdProtect::protectWordsIf(const string& old, bool doIt) {
return VIdProtectImp::singleton().protectWordsIf(old, doIt);
}
void VIdProtect::writeMapFile(const string& filename) {
VIdProtectImp::singleton().writeMapFile(filename);
}

View File

@ -182,9 +182,6 @@ private:
virtual void putcOutput(char chr) { fputc(chr, m_fp); }
};
//######################################################################
// V3OutCFile: A class for abstracting out SystemC/C++ details
class V3OutCFile : public V3OutFile {
int m_private;
public:
@ -250,4 +247,21 @@ public:
void puts(const string& strg) { putsNoTracking(strg); }
};
//============================================================================
// VIdProtect: Hash identifier names in output files to protect them
class VIdProtectImp;
class VIdProtect {
public:
// METHODS
// Rename to a new encoded string (unless earlier passthru'ed)
static string protect(const string& old) { return protectIf(old, true); }
static string protectIf(const string& old, bool doIt=true);
// Rename words to a new encoded string
static string protectWordsIf(const string& old, bool doIt=true);
// Write map of renames to output file
static void writeMapFile(const string& filename);
};
#endif // Guard

View File

@ -112,6 +112,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
newmodp->addNext(oldmodp);
newmodp->level(1);
newmodp->modPublic(true);
newmodp->protect(false);
rootp->addModulep(newmodp);
// TODO the module creation above could be done after linkcells, but
@ -192,6 +193,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
AstVar* varp = oldvarp->cloneTree(false);
varp->name(name);
varp->protect(false);
newmodp->addStmtp(varp);
varp->sigPublic(true); // User needs to be able to get to it...
if (oldvarp->isIO()) {

View File

@ -29,6 +29,7 @@
#include "V3Global.h"
#include "V3Name.h"
#include "V3Ast.h"
#include "V3File.h"
#include "V3LanguageWords.h"
#include <algorithm>

View File

@ -534,6 +534,25 @@ void V3Options::notify() {
&& !cdc()) {
v3fatal("verilator: Need --cc, --sc, --cdc, --lint-only, --xml_only or --E option");
}
if (protectIds()) {
FileLine* cmdfl = new FileLine(FileLine::commandLineFilename());
if (allPublic()) {
// We always call protect() on names, we don't check if public or not
// Hence any external references wouldn't be able to find the refed public object.
cmdfl->v3error("Unsupported: Using --protect-ids with --public\n"
+V3Error::warnMore()+"... Suggest remove --public.");
}
if (trace()) {
cmdfl->v3warn(INSECURE,
"Using --protect-ids with --trace may expose private design details\n"
+V3Error::warnMore()+"... Suggest remove --trace.");
}
if (vpi()) {
cmdfl->v3warn(INSECURE,
"Using --protect-ids with --vpi may expose private design details\n"
+V3Error::warnMore()+"... Suggest remove --vpi.");
}
}
}
//######################################################################
@ -545,6 +564,16 @@ string V3Options::version() {
return ver;
}
string V3Options::protectKeyDefaulted() {
if (m_protectKey.empty()) {
// Create a key with a human-readable symbol-like name.
// This conversion drops ~2 bits of entropy out of 256, shouldn't matter.
VHashSha256 digest (V3Os::trueRandom(32));
m_protectKey = digest.digestSymbol();
}
return m_protectKey;
}
void V3Options::throwSigsegv() {
#if !(defined(VL_CPPCHECK) || defined(__clang_analyzer__))
char* zp=NULL; *zp=0; // Intentional core dump, ignore warnings here
@ -687,6 +716,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-debug-leak", flag/*ref*/)) { m_debugLeak = flag; }
else if ( onoff (sw, "-debug-nondeterminism", flag/*ref*/)){ m_debugNondeterminism = flag; }
else if ( onoff (sw, "-debug-partition", flag/*ref*/)){ m_debugPartition = flag; } // Undocumented
else if ( onoff (sw, "-debug-protect", flag/*ref*/)){ m_debugProtect = flag; } // Undocumented
else if ( onoff (sw, "-debug-self-test", flag/*ref*/)){ m_debugSelfTest = flag; } // Undocumented
else if (!strcmp(sw, "-debug-sigsegv")) { throwSigsegv(); } // Undocumented, see also --debug-abort
else if (!strcmp(sw, "-debug-fatalsrc")) { v3fatalSrc("--debug-fatal-src"); } // Undocumented, see also --debug-abort
@ -709,6 +739,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-prof-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; }
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/)) { m_profCFuncs = flag; } // Undocumented, for backward compat
else if ( onoff (sw, "-prof-threads", flag/*ref*/)) { m_profThreads = flag; }
else if ( onoff (sw, "-protect-ids", flag/*ref*/)) { m_protectIds = flag; }
else if ( onoff (sw, "-public", flag/*ref*/)) { m_public = flag; }
else if ( onoff (sw, "-public-flat-rw", flag/*ref*/) ) { m_publicFlatRW = flag; v3Global.dpi(true); }
else if (!strncmp(sw, "-pvalue+", strlen("-pvalue+"))) { addParameter(string(sw+strlen("-pvalue+")), false); }
@ -1056,6 +1087,9 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
shift; m_prefix = argv[i];
if (m_modPrefix=="") m_modPrefix = m_prefix;
}
else if (!strcmp(sw, "-protect-key") && (i+1)<argc) {
shift; m_protectKey = argv[i];
}
else if (!strcmp(sw, "-no-threads")) { m_threads = 0; } // Undocumented until functional
else if (!strcmp(sw, "-threads") && (i+1)<argc) { // Undocumented until functional
shift; m_threads = atoi(argv[i]);
@ -1290,6 +1324,7 @@ V3Options::V3Options() {
m_debugLeak = true;
m_debugNondeterminism = false;
m_debugPartition = false;
m_debugProtect = false;
m_debugSelfTest = false;
m_decoration = true;
m_dpiHdrOnly = false;
@ -1309,6 +1344,7 @@ V3Options::V3Options() {
m_ppComments = false;
m_profCFuncs = false;
m_profThreads = false;
m_protectIds = false;
m_preprocOnly = false;
m_preprocNoLine = false;
m_public = false;

View File

@ -118,6 +118,7 @@ class V3Options {
bool m_debugLeak; // main switch: --debug-leak
bool m_debugNondeterminism; // main switch: --debug-nondeterminism
bool m_debugPartition; // main switch: --debug-partition
bool m_debugProtect; // main switch: --debug-protect
bool m_debugSelfTest; // main switch: --debug-self-test
bool m_decoration; // main switch: --decoration
bool m_dpiHdrOnly; // main switch: --dpi-hdr-only
@ -134,6 +135,7 @@ class V3Options {
bool m_ppComments; // main switch: --pp-comments
bool m_profCFuncs; // main switch: --prof-cfuncs
bool m_profThreads; // main switch: --prof-threads
bool m_protectIds; // main switch: --protect-ids
bool m_public; // main switch: --public
bool m_publicFlatRW; // main switch: --public-flat-rw
bool m_relativeCFuncs; // main switch: --relative-cfuncs
@ -188,6 +190,7 @@ class V3Options {
string m_modPrefix; // main switch: --mod-prefix
string m_pipeFilter; // main switch: --pipe-filter
string m_prefix; // main switch: --prefix
string m_protectKey; // main switch: --protect-key
string m_topModule; // main switch: --top-module
string m_unusedRegexp; // main switch: --unused-regexp
string m_xAssign; // main switch: --x-assign
@ -288,6 +291,7 @@ class V3Options {
bool debugLeak() const { return m_debugLeak; }
bool debugNondeterminism() const { return m_debugNondeterminism; }
bool debugPartition() const { return m_debugPartition; }
bool debugProtect() const { return m_debugProtect; }
bool debugSelfTest() const { return m_debugSelfTest; }
bool decoration() const { return m_decoration; }
bool dpiHdrOnly() const { return m_dpiHdrOnly; }
@ -310,6 +314,7 @@ class V3Options {
bool ppComments() const { return m_ppComments; }
bool profCFuncs() const { return m_profCFuncs; }
bool profThreads() const { return m_profThreads; }
bool protectIds() const { return m_protectIds; }
bool allPublic() const { return m_public; }
bool publicFlatRW() const { return m_publicFlatRW; }
bool lintOnly() const { return m_lintOnly; }
@ -351,6 +356,8 @@ class V3Options {
string modPrefix() const { return m_modPrefix; }
string pipeFilter() const { return m_pipeFilter; }
string prefix() const { return m_prefix; }
string protectKey() const { return m_protectKey; }
string protectKeyDefaulted(); // Set default key if not set by user
string topModule() const { return m_topModule; }
string unusedRegexp() const { return m_unusedRegexp; }
string xAssign() const { return m_xAssign; }

View File

@ -31,6 +31,7 @@
#include <cstdarg>
#include <dirent.h>
#include <fcntl.h>
#include <fstream>
#include <iomanip>
#include <memory>
#include <sys/stat.h>
@ -218,6 +219,18 @@ vluint64_t V3Os::rand64(vluint64_t* statep) {
return result;
}
string V3Os::trueRandom(size_t size) {
string data; data.reserve(size);
std::ifstream is ("/dev/urandom", std::ios::in | std::ios::binary);
char bytes[size];
if (!is.read(bytes, size)) {
v3fatal("Could not open /dev/urandom, no source of randomness. Try specifing a key instead.");
return "";
}
data.append(bytes, size);
return data;
}
//######################################################################
// METHODS (performance)

View File

@ -56,6 +56,7 @@ public:
// METHODS (random)
static vluint64_t rand64(vluint64_t* statep);
static string trueRandom(size_t size);
// METHODS (performance)
static uint64_t timeUsecs(); ///< Return wall time since epoch in microseconds, or 0 if not implemented

View File

@ -711,6 +711,7 @@ private:
dpip->entryPoint(true);
dpip->isStatic(true);
dpip->dpiExportWrapper(true);
dpip->protect(false);
dpip->cname(nodep->cname());
// Add DPI reference to top, since it's a global function
m_topScopep->scopep()->addActivep(dpip);
@ -733,7 +734,8 @@ private:
// If the find fails, it will throw an error
stmt += "const VerilatedScope* __Vscopep = Verilated::dpiScope();\n";
// If dpiScope is fails and is null; the exportFind function throws and error
string cbtype = v3Global.opt.prefix()+"__Vcb_"+nodep->cname()+"_t";
string cbtype = VIdProtect::protect(v3Global.opt.prefix()
+"__Vcb_"+nodep->cname()+"_t");
stmt += cbtype+" __Vcb = ("+cbtype+")(VerilatedScope::exportFind(__Vscopep, __Vfuncnum));\n"; // Can't use static_cast
// If __Vcb is null the exportFind function throws and error
dpip->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
@ -741,7 +743,8 @@ private:
// Convert input/inout DPI arguments to Internal types
string args;
args += "("+v3Global.opt.prefix()+"__Syms*)(__Vscopep->symsp())"; // Upcast w/o overhead
args += ("("+EmitCBaseVisitor::symClassName()
+"*)(__Vscopep->symsp())"); // Upcast w/o overhead
AstNode* argnodesp = NULL;
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
@ -755,6 +758,9 @@ private:
args = "";
}
AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp);
// No information exposure; is already visible in import/export func template
outvscp->varp()->protect(false);
portp->protect(false);
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp,
portp->isWritable());
argnodesp = argnodesp->addNextNull(refp);
@ -775,6 +781,8 @@ private:
args="";
}
AstVarScope* outvscp = createFuncVar(dpip, portp->name()+"__Vcvt", portp);
// No information exposure; is already visible in import/export func template
outvscp->varp()->protect(false);
AstVarRef* refp = new AstVarRef(portp->fileline(), outvscp, portp->isWritable());
argnodesp = argnodesp->addNextNull(refp);
}
@ -826,6 +834,7 @@ private:
dpip->entryPoint(false);
dpip->funcPublic(true);
dpip->isStatic(false);
dpip->protect(false);
dpip->pure(nodep->pure());
dpip->dpiImport(true);
// Add DPI reference to top, since it's a global function
@ -952,6 +961,7 @@ private:
// Convert output/inout arguments back to internal type
for (AstNode* stmtp = cfuncp->argsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* portp = VN_CAST(stmtp, Var)) {
portp->protect(false); // No additional exposure - already part of shown proto
if (portp->isIO() && (portp->isWritable() || portp->isFuncReturn())
&& !portp->isDpiOpenArray()) {
AstVarScope* portvscp = VN_CAST(portp->user2p(), VarScope); // Remembered when we created it earlier
@ -984,6 +994,7 @@ private:
rtnvarp = portp;
rtnvarp->funcLocal(true);
rtnvarp->name(rtnvarp->name()+"__Vfuncrtn"); // Avoid conflict with DPI function name
if (nodep->dpiImport() || nodep->dpiExport()) rtnvarp->protect(false);
}
if (nodep->dpiImport()) {
@ -1245,6 +1256,11 @@ private:
if (nodep->dpiImport()) modes++;
if (nodep->dpiExport()) modes++;
if (nodep->taskPublic()) modes++;
if (v3Global.opt.protectIds() && nodep->taskPublic()) {
// We always call protect() on names, we don't check if public or not
// Hence any external references wouldn't be able to find the refed public object.
nodep->v3error("Unsupported: Using --protect-ids with public function");
}
if (modes > 1) nodep->v3error("Cannot mix DPI import, DPI export and/or public on same function: "
<<nodep->prettyNameQ());

View File

@ -643,6 +643,9 @@ int main(int argc, char** argv, char** env) {
V3File::writeTimes(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()
+"__verFiles.dat", argString);
}
if (v3Global.opt.protectIds()) {
VIdProtect::writeMapFile(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__idmap.xml");
}
// Final writing shouldn't throw warnings, but...
V3Error::abortIfWarnings();

View File

@ -81,7 +81,9 @@ static void checkResult(bool p, const char *msg_fail) {
// Main function instantiates the model and steps through the test.
int main() {
Vt_dpi_accessors *dut = new Vt_dpi_accessors ("dut");
svSetScope(svGetScopeFromName("dut.t"));
svScope scope = svGetScopeFromName("dut.t");
if (!scope) vl_fatal(__FILE__, __LINE__, "dut", "No svGetScopeFromName result");
svSetScope(scope);
// evaluate the model with no signal changes to get the initial blocks
// executed.

52
test_regress/t/t_protect_ids.pl Executable file
View File

@ -0,0 +1,52 @@
#!/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.
scenarios(vlt_all => 1);
# Use --debug-protect to assist debug
# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first
foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp"
." $Self->{obj_dir}/*_PS*.h"
." $Self->{obj_dir}/*.d" )) {
print "rm $filename\n" if $Self->{verbose};
unlink $filename;
}
compile(
verilator_flags2 => ["--protect-ids",
"--trace",
"--coverage",
"-Wno-INSECURE",
"t/t_protect_ids_c.cpp"],
);
execute(
check_finished => 1,
);
# 'to="PS"' indicates means we probably mis-protected something already protected
# Use --debug-protect to assist debugging these
file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__idmap.xml", qr/to="PS/);
if ($Self->{vlt_all}) {
# Check for secret in any outputs
my $any;
foreach my $filename (glob $Self->{obj_dir}."/*.[ch]*") {
if ($filename =~ /secret/) {
$Self->error("Secret found in a filename: ".$filename);
}
file_grep_not($filename, qr/secret/);
$any = 1;
}
$any or $Self->error("No outputs found");
}
ok(1);
1;

View File

@ -0,0 +1,61 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
secret_sub secret_inst (.*);
secret_other secret_inst2 (.*);
endmodule
module secret_sub
(
input clk);
// verilator no_inline_module
integer secret_cyc;
real secret_cyc_r;
integer secret_o;
real secret_r;
export "DPI-C" task dpix_a_task;
task dpix_a_task(input int i, output int o); o = i + 1; endtask
import "DPI-C" context task dpii_a_task(input int i, output int o);
export "DPI-C" function dpix_a_func;
function int dpix_a_func(input int i); return i + 2; endfunction
import "DPI-C" context function int dpii_a_func(input int i);
// Test loop
always @ (posedge clk) begin
secret_cyc_r = $itor(secret_cyc)/10.0 - 5.0;
secret_cyc <= dpii_a_func(secret_cyc);
secret_r += 1.0 + $cos(secret_cyc_r);
dpix_a_task(secret_cyc, secret_o);
if (secret_cyc==90) begin
$write("*-* All Finished *-*\n");
end
end
endmodule
module secret_other
(
input clk);
integer secret_cyc;
always @ (posedge clk) begin
secret_cyc <= secret_cyc + 1;
if (secret_cyc==99) begin
$finish;
end
end
endmodule

View File

@ -0,0 +1,8 @@
%Error: Unsupported: Using --protect-ids with --public
... Suggest remove --public.
%Warning-INSECURE: Using --protect-ids with --trace may expose private design details
... Suggest remove --trace.
... Use "/* verilator lint_off INSECURE */" and lint_on around source to disable this message.
%Warning-INSECURE: Using --protect-ids with --vpi may expose private design details
... Suggest remove --vpi.
%Error: Exiting due to

View File

@ -0,0 +1,23 @@
#!/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.
scenarios(vlt => 1);
compile(
verilator_flags2 => ["--protect-ids",
"--trace",
"--public",
"--vpi",
],
fails => 1,
expect_filename => $Self->{golden_filename},
);
ok(1);
1;

View File

@ -0,0 +1,7 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2019 by Wilson Snyder.
module t (/*AUTOARG*/);
endmodule

View File

@ -0,0 +1,51 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2009-2009 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 <cstdio>
#include <cstring>
#include "svdpi.h"
//======================================================================
#if defined(VERILATOR)
# ifdef T_PROTECT_IDS_KEY
# include "Vt_protect_ids_key__Dpi.h"
# else
# include "Vt_protect_ids__Dpi.h"
# endif
#elif defined(VCS)
# include "../vc_hdrs.h"
#elif defined(CADENCE)
# define NEED_EXTERNS
#else
# error "Unknown simulator for DPI test"
#endif
#ifdef NEED_EXTERNS
# error "Not supported"
#endif
//======================================================================
int dpii_a_func(int i) {
int o = dpix_a_func(i);
return o;
}
int dpii_a_task(int i, int* op) {
int o = 0;
(void)dpix_a_task(i, op);
return 0;
}

View File

@ -0,0 +1,42 @@
<?xml version="1.0" ?>
<!-- DESCRIPTION: Verilator output: XML representation of netlist -->
<verilator_id_map>
<map from="PSbKTb" to="TOP__t__DOT__secret_inst"/>
<map from="TOPp" to="TOPp"/>
<map from="PSbvpV" to="Vt_protect_ids_key__Vcb_dpix_a_func_t"/>
<map from="PSkBNa" to="Vt_protect_ids_key__Vcb_dpix_a_task_t"/>
<map from="PS49FI" to="_Syms"/>
<map from="PSA0ET" to="__PVT__secret_cyc"/>
<map from="PS7KZL" to="__PVT__secret_cyc_r"/>
<map from="PShnzQ" to="__PVT__secret_r"/>
<map from="PS39wi" to="__PVT__t__DOT__secret_inst"/>
<map from="PSgHnb" to="__Vclklast__TOP__clk"/>
<map from="PSTDrn" to="__Vconfigure"/>
<map from="PSAer0" to="__Vdly__secret_cyc"/>
<map from="PSswQ3" to="__Vdly__t__DOT__secret_inst2__DOT__secret_cyc"/>
<map from="PSH9UL" to="__Vdpiexp_dpix_a_func_TOP__t__DOT__secret_inst"/>
<map from="PSabB6" to="__Vdpiexp_dpix_a_task_TOP__t__DOT__secret_inst"/>
<map from="PS8F1t" to="__Vdpiimwrap_dpii_a_func_TOP__t__DOT__secret_inst"/>
<map from="PSBPcq" to="__Vdpiimwrap_dpii_a_task_TOP__t__DOT__secret_inst"/>
<map from="PSY85C" to="__Vfunc_dpii_a_func__0__Vfuncout"/>
<map from="PSUcyn" to="__Vscope_t__secret_inst"/>
<map from="PS27AG" to="__Vtask_dpix_a_task__1__i"/>
<map from="PSgcfL" to="_change_request"/>
<map from="PSNQUa" to="_ctor_var_reset"/>
<map from="PSeP2H" to="_eval"/>
<map from="PS8Ytd" to="_eval_debug_assertions"/>
<map from="PSGiE1" to="_eval_initial"/>
<map from="PSCvUR" to="_eval_initial_loop"/>
<map from="PSrrKr" to="_eval_settle"/>
<map from="PSVBHr" to="_sequent__TOP__1"/>
<map from="PSJVjb" to="_sequent__TOP__t__DOT__secret_inst__1"/>
<map from="PSnkZP" to="clk"/>
<map from="PSLGUV" to="secret_inst"/>
<map from="PSCwHq" to="secret_sub"/>
<map from="PSwmbl" to="t"/>
<map from="PS4YQ7" to="t/t_protect_ids.v"/>
<map from="PSkXXg" to="t__DOT__secret_inst2__DOT__secret_cyc"/>
<map from="this" to="this"/>
<map from="vlSymsp" to="vlSymsp"/>
<map from="vlTOPp" to="vlTOPp"/>
</verilator_id_map>

View File

@ -0,0 +1,27 @@
#!/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.
scenarios(vlt => 1);
top_filename("t/t_protect_ids.v");
compile(
verilator_flags2 => ["--protect-ids --protect-key MY_KEY",
"t/t_protect_ids_c.cpp"],
);
execute(
check_finished => 1,
);
# Since using a named key, we can check for always identical map
files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__idmap.xml", $Self->{golden_filename});
ok(1);
1;