clang-format remaining sources. No functional change.
This commit is contained in:
parent
1b94e3b0e2
commit
f3308d236b
|
|
@ -456,6 +456,12 @@ analyzer-include:
|
|||
-rm -rf examples/*/obj*
|
||||
scan-build $(MAKE) -k examples
|
||||
|
||||
CLANGFORMAT = clang-format
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
|
||||
clang-format:
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H)
|
||||
|
||||
ftp: info
|
||||
|
||||
install-msg:
|
||||
|
|
|
|||
|
|
@ -1,236 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# clang-format is used to standardize the indentation of the internal C++
|
||||
# code.
|
||||
#
|
||||
# For the most part clang-format changes provide good consistency, the two
|
||||
# main exceptions being the indentation of preprocessor directives, and
|
||||
# tables of statements. Reformatting is generally performed only before
|
||||
# other large changes are to be made to a file.
|
||||
#
|
||||
# "##" files commented out below are not yet clang-format clean.
|
||||
# "#" files commented out hit a clang-format limitation with ifdefs.
|
||||
|
||||
clang-format -i examples/make_hello_c/sim_main.cpp
|
||||
clang-format -i examples/make_hello_sc/sc_main.cpp
|
||||
#clang-format -i examples/make_protect_lib/sim_main.cpp
|
||||
clang-format -i examples/make_tracing_c/sim_main.cpp
|
||||
clang-format -i examples/make_tracing_sc/sc_main.cpp
|
||||
clang-format -i include/*.cpp
|
||||
clang-format -i include/*.h
|
||||
clang-format -i include/verilated_config.h.in
|
||||
clang-format -i nodist/fuzzer/wrapper.cpp
|
||||
clang-format -i src/V3Active.cpp
|
||||
clang-format -i src/V3Active.h
|
||||
clang-format -i src/V3ActiveTop.cpp
|
||||
clang-format -i src/V3ActiveTop.h
|
||||
clang-format -i src/V3Assert.cpp
|
||||
clang-format -i src/V3Assert.h
|
||||
clang-format -i src/V3AssertPre.cpp
|
||||
clang-format -i src/V3AssertPre.h
|
||||
##clang-format -i src/V3Ast.cpp
|
||||
##clang-format -i src/V3Ast.h
|
||||
clang-format -i src/V3AstConstOnly.h
|
||||
##clang-format -i src/V3AstNodes.cpp
|
||||
##clang-format -i src/V3AstNodes.h
|
||||
##clang-format -i src/V3Begin.cpp
|
||||
clang-format -i src/V3Begin.h
|
||||
clang-format -i src/V3Branch.cpp
|
||||
clang-format -i src/V3Branch.h
|
||||
##clang-format -i src/V3Broken.cpp
|
||||
clang-format -i src/V3Broken.h
|
||||
##clang-format -i src/V3CCtors.cpp
|
||||
clang-format -i src/V3CCtors.h
|
||||
clang-format -i src/V3CUse.cpp
|
||||
clang-format -i src/V3CUse.h
|
||||
##clang-format -i src/V3Case.cpp
|
||||
clang-format -i src/V3Case.h
|
||||
##clang-format -i src/V3Cast.cpp
|
||||
clang-format -i src/V3Cast.h
|
||||
##clang-format -i src/V3Cdc.cpp
|
||||
clang-format -i src/V3Cdc.h
|
||||
##clang-format -i src/V3Changed.cpp
|
||||
clang-format -i src/V3Changed.h
|
||||
clang-format -i src/V3Class.cpp
|
||||
clang-format -i src/V3Class.h
|
||||
##clang-format -i src/V3Clean.cpp
|
||||
clang-format -i src/V3Clean.h
|
||||
##clang-format -i src/V3Clock.cpp
|
||||
clang-format -i src/V3Clock.h
|
||||
##clang-format -i src/V3Combine.cpp
|
||||
clang-format -i src/V3Combine.h
|
||||
clang-format -i src/V3Config.cpp
|
||||
clang-format -i src/V3Config.h
|
||||
##clang-format -i src/V3Const.cpp
|
||||
clang-format -i src/V3Const.h
|
||||
clang-format -i src/V3Coverage.cpp
|
||||
clang-format -i src/V3Coverage.h
|
||||
clang-format -i src/V3CoverageJoin.cpp
|
||||
clang-format -i src/V3CoverageJoin.h
|
||||
##clang-format -i src/V3Dead.cpp
|
||||
clang-format -i src/V3Dead.h
|
||||
##clang-format -i src/V3Delayed.cpp
|
||||
clang-format -i src/V3Delayed.h
|
||||
clang-format -i src/V3Depth.cpp
|
||||
clang-format -i src/V3Depth.h
|
||||
clang-format -i src/V3DepthBlock.cpp
|
||||
clang-format -i src/V3DepthBlock.h
|
||||
clang-format -i src/V3Descope.cpp
|
||||
clang-format -i src/V3Descope.h
|
||||
##clang-format -i src/V3EmitC.cpp
|
||||
clang-format -i src/V3EmitC.h
|
||||
##clang-format -i src/V3EmitCBase.h
|
||||
clang-format -i src/V3EmitCInlines.cpp
|
||||
##clang-format -i src/V3EmitCMake.cpp
|
||||
clang-format -i src/V3EmitCMake.h
|
||||
clang-format -i src/V3EmitCSyms.cpp
|
||||
##clang-format -i src/V3EmitMk.cpp
|
||||
clang-format -i src/V3EmitMk.h
|
||||
##clang-format -i src/V3EmitV.cpp
|
||||
clang-format -i src/V3EmitV.h
|
||||
##clang-format -i src/V3EmitXml.cpp
|
||||
clang-format -i src/V3EmitXml.h
|
||||
##clang-format -i src/V3Error.cpp
|
||||
##clang-format -i src/V3Error.h
|
||||
##clang-format -i src/V3Expand.cpp
|
||||
clang-format -i src/V3Expand.h
|
||||
##clang-format -i src/V3File.cpp
|
||||
##clang-format -i src/V3File.h
|
||||
##clang-format -i src/V3FileLine.cpp
|
||||
##clang-format -i src/V3FileLine.h
|
||||
##clang-format -i src/V3Gate.cpp
|
||||
clang-format -i src/V3Gate.h
|
||||
##clang-format -i src/V3GenClk.cpp
|
||||
clang-format -i src/V3GenClk.h
|
||||
clang-format -i src/V3Global.cpp
|
||||
clang-format -i src/V3Global.h
|
||||
##clang-format -i src/V3Graph.cpp
|
||||
clang-format -i src/V3Graph.h
|
||||
##clang-format -i src/V3GraphAcyc.cpp
|
||||
##clang-format -i src/V3GraphAlg.cpp
|
||||
clang-format -i src/V3GraphAlg.h
|
||||
clang-format -i src/V3GraphDfa.cpp
|
||||
clang-format -i src/V3GraphDfa.h
|
||||
clang-format -i src/V3GraphPathChecker.cpp
|
||||
clang-format -i src/V3GraphPathChecker.h
|
||||
clang-format -i src/V3GraphStream.h
|
||||
##clang-format -i src/V3GraphTest.cpp
|
||||
##clang-format -i src/V3Hashed.cpp
|
||||
clang-format -i src/V3Hashed.h
|
||||
##clang-format -i src/V3Inline.cpp
|
||||
clang-format -i src/V3Inline.h
|
||||
##clang-format -i src/V3Inst.cpp
|
||||
clang-format -i src/V3Inst.h
|
||||
clang-format -i src/V3InstrCount.cpp
|
||||
clang-format -i src/V3InstrCount.h
|
||||
clang-format -i src/V3LangCode.h
|
||||
clang-format -i src/V3LanguageWords.h
|
||||
##clang-format -i src/V3Life.cpp
|
||||
clang-format -i src/V3Life.h
|
||||
##clang-format -i src/V3LifePost.cpp
|
||||
clang-format -i src/V3LifePost.h
|
||||
##clang-format -i src/V3LinkCells.cpp
|
||||
clang-format -i src/V3LinkCells.h
|
||||
##clang-format -i src/V3LinkDot.cpp
|
||||
clang-format -i src/V3LinkDot.h
|
||||
##clang-format -i src/V3LinkJump.cpp
|
||||
clang-format -i src/V3LinkJump.h
|
||||
clang-format -i src/V3LinkLValue.cpp
|
||||
clang-format -i src/V3LinkLValue.h
|
||||
##clang-format -i src/V3LinkLevel.cpp
|
||||
clang-format -i src/V3LinkLevel.h
|
||||
##clang-format -i src/V3LinkParse.cpp
|
||||
clang-format -i src/V3LinkParse.h
|
||||
##clang-format -i src/V3LinkResolve.cpp
|
||||
clang-format -i src/V3LinkResolve.h
|
||||
clang-format -i src/V3List.h
|
||||
clang-format -i src/V3Localize.cpp
|
||||
clang-format -i src/V3Localize.h
|
||||
clang-format -i src/V3Name.cpp
|
||||
clang-format -i src/V3Name.h
|
||||
##clang-format -i src/V3Number.cpp
|
||||
##clang-format -i src/V3Number.h
|
||||
clang-format -i src/V3Number_test.cpp
|
||||
clang-format -i src/V3Options.cpp
|
||||
clang-format -i src/V3Options.h
|
||||
##clang-format -i src/V3Order.cpp
|
||||
clang-format -i src/V3Order.h
|
||||
clang-format -i src/V3OrderGraph.h
|
||||
clang-format -i src/V3Os.cpp
|
||||
clang-format -i src/V3Os.h
|
||||
##clang-format -i src/V3Param.cpp
|
||||
clang-format -i src/V3Param.h
|
||||
clang-format -i src/V3Parse.h
|
||||
##clang-format -i src/V3ParseGrammar.cpp
|
||||
##clang-format -i src/V3ParseImp.cpp
|
||||
##clang-format -i src/V3ParseImp.h
|
||||
clang-format -i src/V3ParseLex.cpp
|
||||
clang-format -i src/V3ParseSym.h
|
||||
##clang-format -i src/V3Partition.cpp
|
||||
clang-format -i src/V3Partition.h
|
||||
clang-format -i src/V3PartitionGraph.h
|
||||
clang-format -i src/V3PreLex.h
|
||||
##clang-format -i src/V3PreProc.cpp
|
||||
clang-format -i src/V3PreProc.h
|
||||
clang-format -i src/V3PreShell.cpp
|
||||
clang-format -i src/V3PreShell.h
|
||||
##clang-format -i src/V3Premit.cpp
|
||||
clang-format -i src/V3Premit.h
|
||||
##clang-format -i src/V3ProtectLib.cpp
|
||||
clang-format -i src/V3ProtectLib.h
|
||||
clang-format -i src/V3Reloop.cpp
|
||||
clang-format -i src/V3Reloop.h
|
||||
##clang-format -i src/V3Scope.cpp
|
||||
clang-format -i src/V3Scope.h
|
||||
clang-format -i src/V3Scoreboard.cpp
|
||||
clang-format -i src/V3Scoreboard.h
|
||||
clang-format -i src/V3SenTree.h
|
||||
##clang-format -i src/V3Simulate.h
|
||||
##clang-format -i src/V3Slice.cpp
|
||||
clang-format -i src/V3Slice.h
|
||||
##clang-format -i src/V3Split.cpp
|
||||
clang-format -i src/V3Split.h
|
||||
##clang-format -i src/V3SplitAs.cpp
|
||||
clang-format -i src/V3SplitAs.h
|
||||
##clang-format -i src/V3SplitVar.cpp
|
||||
clang-format -i src/V3SplitVar.h
|
||||
clang-format -i src/V3Stats.cpp
|
||||
clang-format -i src/V3Stats.h
|
||||
clang-format -i src/V3StatsReport.cpp
|
||||
clang-format -i src/V3String.cpp
|
||||
clang-format -i src/V3String.h
|
||||
##clang-format -i src/V3Subst.cpp
|
||||
clang-format -i src/V3Subst.h
|
||||
clang-format -i src/V3SymTable.h
|
||||
##clang-format -i src/V3TSP.cpp
|
||||
clang-format -i src/V3TSP.h
|
||||
##clang-format -i src/V3Table.cpp
|
||||
clang-format -i src/V3Table.h
|
||||
##clang-format -i src/V3Task.cpp
|
||||
clang-format -i src/V3Task.h
|
||||
clang-format -i src/V3Trace.cpp
|
||||
clang-format -i src/V3Trace.h
|
||||
clang-format -i src/V3TraceDecl.cpp
|
||||
clang-format -i src/V3TraceDecl.h
|
||||
##clang-format -i src/V3Tristate.cpp
|
||||
clang-format -i src/V3Tristate.h
|
||||
##clang-format -i src/V3Undriven.cpp
|
||||
clang-format -i src/V3Undriven.h
|
||||
##clang-format -i src/V3Unknown.cpp
|
||||
clang-format -i src/V3Unknown.h
|
||||
##clang-format -i src/V3Unroll.cpp
|
||||
clang-format -i src/V3Unroll.h
|
||||
##clang-format -i src/V3Width.cpp
|
||||
clang-format -i src/V3Width.h
|
||||
clang-format -i src/V3WidthCommit.h
|
||||
##clang-format -i src/V3WidthSel.cpp
|
||||
clang-format -i src/Verilator.cpp
|
||||
clang-format -i src/VlcBucket.h
|
||||
clang-format -i src/VlcMain.cpp
|
||||
clang-format -i src/VlcOptions.h
|
||||
clang-format -i src/VlcPoint.h
|
||||
clang-format -i src/VlcSource.h
|
||||
clang-format -i src/VlcTest.h
|
||||
clang-format -i src/VlcTop.cpp
|
||||
clang-format -i src/VlcTop.h
|
||||
clang-format -i src/config_build.h.in
|
||||
|
|
@ -364,7 +364,7 @@ private:
|
|||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4, " ALW " << nodep << endl);
|
||||
// if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
|
|
@ -376,7 +376,7 @@ private:
|
|||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4, " ALWPub " << nodep << endl);
|
||||
// if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
|
|
|
|||
|
|
@ -322,7 +322,7 @@ private:
|
|||
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), outvarp, true), inp);
|
||||
alwaysp->addStmtp(assp);
|
||||
// if (debug()>-9) assp->dumpTree(cout, "-ass: ");
|
||||
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
|
||||
invarp = outvarp;
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
||||
}
|
||||
|
|
|
|||
490
src/V3Ast.cpp
490
src/V3Ast.cpp
|
|
@ -51,7 +51,6 @@ bool AstUser5InUse::s_userBusy = false;
|
|||
|
||||
int AstNodeDType::s_uniqueNum = 0;
|
||||
|
||||
|
||||
//######################################################################
|
||||
// V3AstType
|
||||
|
||||
|
|
@ -102,15 +101,16 @@ AstNode* AstNode::abovep() const {
|
|||
string AstNode::encodeName(const string& namein) {
|
||||
// Encode signal name raw from parser, then not called again on same signal
|
||||
string out;
|
||||
for (string::const_iterator pos = namein.begin(); pos!=namein.end(); ++pos) {
|
||||
if ((pos==namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
|
||||
: isalnum(pos[0])) {
|
||||
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
|
||||
if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
|
||||
: isalnum(pos[0])) {
|
||||
out += pos[0];
|
||||
} else if (pos[0]=='_') {
|
||||
if (pos[1]=='_') {
|
||||
out += "_"; out += "__05F"; // hex(_) = 0x5F
|
||||
} else if (pos[0] == '_') {
|
||||
if (pos[1] == '_') {
|
||||
out += "_";
|
||||
out += "__05F"; // hex(_) = 0x5F
|
||||
++pos;
|
||||
if (pos==namein.end()) break;
|
||||
if (pos == namein.end()) break;
|
||||
} else {
|
||||
out += pos[0];
|
||||
}
|
||||
|
|
@ -120,7 +120,8 @@ string AstNode::encodeName(const string& namein) {
|
|||
// We also do *NOT* use __DOT__ etc, as we search for those
|
||||
// in some replacements, and don't want to mangle the user's names.
|
||||
unsigned val = pos[0] & 0xff; // Mask to avoid sign extension
|
||||
char hex[10]; sprintf(hex, "__0%02X", val);
|
||||
char hex[10];
|
||||
sprintf(hex, "__0%02X", val);
|
||||
out += hex;
|
||||
}
|
||||
}
|
||||
|
|
@ -133,34 +134,26 @@ string AstNode::encodeName(const string& namein) {
|
|||
|
||||
string AstNode::encodeNumber(vlsint64_t num) {
|
||||
if (num < 0) {
|
||||
return "__02D"+cvtToStr(-num); // 2D=-
|
||||
return "__02D" + cvtToStr(-num); // 2D=-
|
||||
} else {
|
||||
return cvtToStr(num);
|
||||
}
|
||||
}
|
||||
|
||||
string AstNode::nameProtect() const {
|
||||
return VIdProtect::protectIf(name(), protect());
|
||||
}
|
||||
string AstNode::origNameProtect() const {
|
||||
return VIdProtect::protectIf(origName(), protect());
|
||||
}
|
||||
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
|
||||
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
|
||||
|
||||
string AstNode::shortName() const {
|
||||
string pretty = name();
|
||||
string::size_type pos;
|
||||
while ((pos = pretty.find("__PVT__")) != string::npos) {
|
||||
pretty.replace(pos, 7, "");
|
||||
}
|
||||
while ((pos = pretty.find("__PVT__")) != string::npos) pretty.replace(pos, 7, "");
|
||||
return pretty;
|
||||
}
|
||||
|
||||
string AstNode::dedotName(const string& namein) {
|
||||
string pretty = namein;
|
||||
string::size_type pos;
|
||||
while ((pos = pretty.find("__DOT__")) != string::npos) {
|
||||
pretty.replace(pos, 7, ".");
|
||||
}
|
||||
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, ".");
|
||||
if (pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
||||
return pretty;
|
||||
}
|
||||
|
|
@ -170,12 +163,8 @@ string AstNode::vcdName(const string& namein) {
|
|||
// Dots are reserved for dots the user put in the name
|
||||
string pretty = namein;
|
||||
string::size_type pos;
|
||||
while ((pos = pretty.find("__DOT__")) != string::npos) {
|
||||
pretty.replace(pos, 7, " ");
|
||||
}
|
||||
while ((pos = pretty.find('.')) != string::npos) {
|
||||
pretty.replace(pos, 1, " ");
|
||||
}
|
||||
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " ");
|
||||
while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " ");
|
||||
// Now convert escaped special characters, etc
|
||||
return prettyName(pretty);
|
||||
}
|
||||
|
|
@ -185,38 +174,38 @@ string AstNode::prettyName(const string& namein) {
|
|||
string pretty;
|
||||
pretty = "";
|
||||
pretty.reserve(namein.length());
|
||||
for (const char* pos = namein.c_str(); *pos; ) {
|
||||
if (pos[0]=='-' && pos[1]=='>') { // ->
|
||||
for (const char* pos = namein.c_str(); *pos;) {
|
||||
if (pos[0] == '-' && pos[1] == '>') { // ->
|
||||
pretty += ".";
|
||||
pos += 2;
|
||||
continue;
|
||||
}
|
||||
if (pos[0]=='_' && pos[1]=='_') { // Short-circuit
|
||||
if (0==strncmp(pos, "__BRA__", 7)) {
|
||||
if (pos[0] == '_' && pos[1] == '_') { // Short-circuit
|
||||
if (0 == strncmp(pos, "__BRA__", 7)) {
|
||||
pretty += "[";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (0==strncmp(pos, "__KET__", 7)) {
|
||||
if (0 == strncmp(pos, "__KET__", 7)) {
|
||||
pretty += "]";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (0==strncmp(pos, "__DOT__", 7)) {
|
||||
if (0 == strncmp(pos, "__DOT__", 7)) {
|
||||
pretty += ".";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (0==strncmp(pos, "__PVT__", 7)) {
|
||||
if (0 == strncmp(pos, "__PVT__", 7)) {
|
||||
pretty += "";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (pos[0]=='_' && pos[1]=='_' && pos[2]=='0'
|
||||
&& isxdigit(pos[3]) && isxdigit(pos[4])) {
|
||||
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3])
|
||||
&& isxdigit(pos[4])) {
|
||||
char value = 0;
|
||||
value += 16*(isdigit(pos[3]) ? (pos[3]-'0') : (tolower(pos[3])-'a'+10));
|
||||
value += (isdigit(pos[4]) ? (pos[4]-'0') : (tolower(pos[4])-'a'+10));
|
||||
value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10));
|
||||
value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10));
|
||||
pretty += value;
|
||||
pos += 5;
|
||||
continue;
|
||||
|
|
@ -226,37 +215,37 @@ string AstNode::prettyName(const string& namein) {
|
|||
pretty += pos[0];
|
||||
++pos;
|
||||
}
|
||||
if (pretty[0]=='T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
||||
if (pretty[0]=='T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
|
||||
if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
||||
if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
|
||||
return pretty;
|
||||
}
|
||||
|
||||
string AstNode::prettyTypeName() const {
|
||||
if (name()=="") return typeName();
|
||||
return string(typeName())+" '"+prettyName()+"'";
|
||||
if (name() == "") return typeName();
|
||||
return string(typeName()) + " '" + prettyName() + "'";
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Insertion
|
||||
|
||||
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next) {
|
||||
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next){
|
||||
#ifdef VL_DEBUG
|
||||
// Called on all major tree changers.
|
||||
// Only for use for those really nasty bugs relating to internals
|
||||
// Note this may be null.
|
||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
||||
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
//if (debug()) {
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// // Commenting out the section below may crash, as the tree state
|
||||
// // between edits is not always consistent for printing
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// v3Global.rootp()->dumpTree(cout, "-treeChange: ");
|
||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||
// else this->dumpTree(cout, prefix);
|
||||
// this->checkTree();
|
||||
// v3Global.rootp()->checkTree();
|
||||
//}
|
||||
// Called on all major tree changers.
|
||||
// Only for use for those really nasty bugs relating to internals
|
||||
// Note this may be null.
|
||||
// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
||||
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
// if (debug()) {
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// // Commenting out the section below may crash, as the tree state
|
||||
// // between edits is not always consistent for printing
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// v3Global.rootp()->dumpTree(cout, "-treeChange: ");
|
||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||
// else this->dumpTree(cout, prefix);
|
||||
// this->checkTree();
|
||||
// v3Global.rootp()->checkTree();
|
||||
//}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -276,8 +265,9 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
|
|||
UDEBUGONLY(UASSERT_OBJ(!oldtailp->m_nextp, nodep,
|
||||
"Node had next, but headtail says it shouldn't"););
|
||||
} else {
|
||||
// Though inefficient, we are occasionally passed a addNext in the middle of a list.
|
||||
while (oldtailp->m_nextp != NULL) oldtailp = oldtailp->m_nextp;
|
||||
// Though inefficient, we are occasionally passed an
|
||||
// addNext in the middle of a list.
|
||||
while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp;
|
||||
}
|
||||
}
|
||||
// Link it in
|
||||
|
|
@ -328,15 +318,15 @@ void AstNode::addNextHere(AstNode* newp) {
|
|||
AstNode* oldheadtailp = this->m_headtailp;
|
||||
// (!oldheadtailp) // this was&is middle of list
|
||||
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
|
||||
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not tail
|
||||
// (oldheadtailp && !oldnextp) // this was tail of list, might also
|
||||
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not
|
||||
// tail (oldheadtailp && !oldnextp) // this was tail of list, might also
|
||||
// be head of one-node list
|
||||
//
|
||||
newp->m_headtailp = NULL; // Not at head any longer
|
||||
addlastp->m_headtailp = NULL; // Presume middle of list
|
||||
// newp might happen to be head/tail after all, if so will be set again below
|
||||
if (oldheadtailp) { // else in middle of list, no change
|
||||
if (oldheadtailp==this) { // this was one node
|
||||
if (oldheadtailp == this) { // this was one node
|
||||
this->m_headtailp = addlastp; // Was head/tail, now a tail
|
||||
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
|
||||
} else if (!oldnextp) { // this was tail
|
||||
|
|
@ -404,26 +394,38 @@ void AstNode::setOp4p(AstNode* newp) {
|
|||
|
||||
void AstNode::addOp1p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp1p");
|
||||
if (!m_op1p) { op1p(newp); }
|
||||
else { m_op1p->addNext(newp); }
|
||||
if (!m_op1p) {
|
||||
op1p(newp);
|
||||
} else {
|
||||
m_op1p->addNext(newp);
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::addOp2p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp2p");
|
||||
if (!m_op2p) { op2p(newp); }
|
||||
else { m_op2p->addNext(newp); }
|
||||
if (!m_op2p) {
|
||||
op2p(newp);
|
||||
} else {
|
||||
m_op2p->addNext(newp);
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::addOp3p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp3p");
|
||||
if (!m_op3p) { op3p(newp); }
|
||||
else { m_op3p->addNext(newp); }
|
||||
if (!m_op3p) {
|
||||
op3p(newp);
|
||||
} else {
|
||||
m_op3p->addNext(newp);
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::addOp4p(AstNode* newp) {
|
||||
UASSERT(newp, "Null item passed to addOp4p");
|
||||
if (!m_op4p) { op4p(newp); }
|
||||
else { m_op4p->addNext(newp); }
|
||||
if (!m_op4p) {
|
||||
op4p(newp);
|
||||
} else {
|
||||
m_op4p->addNext(newp);
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::replaceWith(AstNode* newp) {
|
||||
|
|
@ -435,13 +437,13 @@ void AstNode::replaceWith(AstNode* newp) {
|
|||
}
|
||||
|
||||
void AstNRelinker::dump(std::ostream& str) const {
|
||||
str<<" BK="<<reinterpret_cast<uint32_t*>(m_backp);
|
||||
str<<" ITER="<<reinterpret_cast<uint32_t*>(m_iterpp);
|
||||
str<<" CHG="<<(m_chg==RELINK_NEXT?"[NEXT] ":"");
|
||||
str<<(m_chg==RELINK_OP1?"[OP1] ":"");
|
||||
str<<(m_chg==RELINK_OP2?"[OP2] ":"");
|
||||
str<<(m_chg==RELINK_OP3?"[OP3] ":"");
|
||||
str<<(m_chg==RELINK_OP4?"[OP4] ":"");
|
||||
str << " BK=" << reinterpret_cast<uint32_t*>(m_backp);
|
||||
str << " ITER=" << reinterpret_cast<uint32_t*>(m_iterpp);
|
||||
str << " CHG=" << (m_chg == RELINK_NEXT ? "[NEXT] " : "");
|
||||
str << (m_chg == RELINK_OP1 ? "[OP1] " : "");
|
||||
str << (m_chg == RELINK_OP2 ? "[OP2] " : "");
|
||||
str << (m_chg == RELINK_OP3 ? "[OP3] " : "");
|
||||
str << (m_chg == RELINK_OP4 ? "[OP4] " : "");
|
||||
}
|
||||
|
||||
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||
|
|
@ -452,17 +454,24 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
|||
AstNode* backp = oldp->m_backp;
|
||||
if (linkerp) {
|
||||
linkerp->m_oldp = oldp;
|
||||
linkerp->m_backp = backp;
|
||||
linkerp->m_backp = backp;
|
||||
linkerp->m_iterpp = oldp->m_iterpp;
|
||||
if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
||||
else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
||||
else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
||||
else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
||||
else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
||||
else oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
if (backp->m_nextp == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
||||
} else if (backp->m_op1p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
||||
} else if (backp->m_op2p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
||||
} else if (backp->m_op3p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
||||
} else if (backp->m_op4p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
||||
} else {
|
||||
oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
}
|
||||
}
|
||||
if (backp->m_nextp== oldp) {
|
||||
backp->m_nextp= NULL;
|
||||
if (backp->m_nextp == oldp) {
|
||||
backp->m_nextp = NULL;
|
||||
// Old list gets truncated
|
||||
// New list becomes a list upon itself
|
||||
// Most common case is unlinking a entire operand tree
|
||||
|
|
@ -477,12 +486,17 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
|||
// Create new head/tail of extracted list
|
||||
oldp->m_headtailp = oldtailp;
|
||||
oldp->m_headtailp->m_headtailp = oldp;
|
||||
} else if (backp->m_op1p == oldp) {
|
||||
backp->m_op1p = NULL;
|
||||
} else if (backp->m_op2p == oldp) {
|
||||
backp->m_op2p = NULL;
|
||||
} else if (backp->m_op3p == oldp) {
|
||||
backp->m_op3p = NULL;
|
||||
} else if (backp->m_op4p == oldp) {
|
||||
backp->m_op4p = NULL;
|
||||
} else {
|
||||
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
}
|
||||
else if (backp->m_op1p == oldp) backp->m_op1p = NULL;
|
||||
else if (backp->m_op2p == oldp) backp->m_op2p = NULL;
|
||||
else if (backp->m_op3p == oldp) backp->m_op3p = NULL;
|
||||
else if (backp->m_op4p == oldp) backp->m_op4p = NULL;
|
||||
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
// Relink
|
||||
oldp->m_backp = NULL;
|
||||
// Iterator fixup
|
||||
|
|
@ -500,32 +514,44 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
|||
AstNode* backp = oldp->m_backp;
|
||||
if (linkerp) {
|
||||
linkerp->m_oldp = oldp;
|
||||
linkerp->m_backp = backp;
|
||||
linkerp->m_backp = backp;
|
||||
linkerp->m_iterpp = oldp->m_iterpp;
|
||||
if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
||||
else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
||||
else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
||||
else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
||||
else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
||||
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
if (backp->m_nextp == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
||||
} else if (backp->m_op1p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
||||
} else if (backp->m_op2p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
||||
} else if (backp->m_op3p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
||||
} else if (backp->m_op4p == oldp) {
|
||||
linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
||||
} else {
|
||||
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
}
|
||||
}
|
||||
if (backp->m_nextp== oldp) {
|
||||
if (backp->m_nextp == oldp) {
|
||||
// This node gets removed from middle (or tail) of list
|
||||
// Not head, since then oldp wouldn't be a next of backp...
|
||||
backp->m_nextp= oldp->m_nextp;
|
||||
backp->m_nextp = oldp->m_nextp;
|
||||
if (backp->m_nextp) backp->m_nextp->m_backp = backp;
|
||||
// If it was a tail, back becomes new tail
|
||||
if (oldp->m_headtailp) {
|
||||
backp->m_headtailp = oldp->m_headtailp;
|
||||
backp->m_headtailp->m_headtailp = backp;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (backp->m_op1p == oldp) backp->m_op1p = oldp->m_nextp;
|
||||
else if (backp->m_op2p == oldp) backp->m_op2p = oldp->m_nextp;
|
||||
else if (backp->m_op3p == oldp) backp->m_op3p = oldp->m_nextp;
|
||||
else if (backp->m_op4p == oldp) backp->m_op4p = oldp->m_nextp;
|
||||
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
} else {
|
||||
if (backp->m_op1p == oldp) {
|
||||
backp->m_op1p = oldp->m_nextp;
|
||||
} else if (backp->m_op2p == oldp) {
|
||||
backp->m_op2p = oldp->m_nextp;
|
||||
} else if (backp->m_op3p == oldp) {
|
||||
backp->m_op3p = oldp->m_nextp;
|
||||
} else if (backp->m_op4p == oldp) {
|
||||
backp->m_op4p = oldp->m_nextp;
|
||||
} else {
|
||||
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||
}
|
||||
if (oldp->m_nextp) {
|
||||
AstNode* newheadp = oldp->m_nextp;
|
||||
newheadp->m_backp = backp;
|
||||
|
|
@ -545,13 +571,19 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
|||
}
|
||||
|
||||
void AstNode::relink(AstNRelinker* linkerp) {
|
||||
if (debug()>8) { UINFO(0," EDIT: relink: "); dumpPtrs(); }
|
||||
if (debug() > 8) {
|
||||
UINFO(0, " EDIT: relink: ");
|
||||
dumpPtrs();
|
||||
}
|
||||
AstNode* newp = this;
|
||||
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
|
||||
UASSERT(!newp->backp(), "New node already linked?");
|
||||
newp->editCountInc();
|
||||
|
||||
if (debug()>8) { linkerp->dump(cout); cout<<endl; }
|
||||
if (debug() > 8) {
|
||||
linkerp->dump(cout);
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
AstNode* backp = linkerp->m_backp;
|
||||
this->debugTreeChange("-relinkNew: ", __LINE__, true);
|
||||
|
|
@ -563,9 +595,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
|||
case AstNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break;
|
||||
case AstNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break;
|
||||
case AstNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break;
|
||||
default:
|
||||
this->v3fatalSrc("Relink of node without any link to change.");
|
||||
break;
|
||||
default: this->v3fatalSrc("Relink of node without any link to change."); break;
|
||||
}
|
||||
// Relink
|
||||
newp->m_backp = backp;
|
||||
|
|
@ -595,10 +625,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
|
|||
// Insert the whole old list following the new node's list.
|
||||
// Thus a unlink without next, followed by relink, gives the same list.
|
||||
AstNode* newlistlastp = newp->m_headtailp;
|
||||
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp!=newp), newp,
|
||||
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp,
|
||||
"Headtailp tail isn't at the tail");
|
||||
AstNode* oldlistlastp = pointpr->m_headtailp;
|
||||
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp!=pointpr), newp,
|
||||
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp,
|
||||
"Old headtailp tail isn't at the tail");
|
||||
// Next links
|
||||
newlistlastp->m_nextp = pointpr;
|
||||
|
|
@ -650,7 +680,7 @@ AstNode* AstNode::cloneTreeIterList() {
|
|||
AstNode* newheadp = NULL;
|
||||
AstNode* newtailp = NULL;
|
||||
// Audited to make sure this is never NULL
|
||||
for (AstNode* oldp = this; oldp; oldp=oldp->m_nextp) {
|
||||
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
|
||||
AstNode* newp = oldp->cloneTreeIter();
|
||||
newp->m_headtailp = NULL;
|
||||
newp->m_backp = newtailp;
|
||||
|
|
@ -701,7 +731,7 @@ void AstNode::deleteNode() {
|
|||
#else
|
||||
!v3Global.opt.debugLeak()
|
||||
#endif
|
||||
) {
|
||||
) {
|
||||
delete this;
|
||||
}
|
||||
// Else leak massively, so each pointer is unique
|
||||
|
|
@ -711,7 +741,7 @@ void AstNode::deleteNode() {
|
|||
void AstNode::deleteTreeIter() {
|
||||
// private: Delete list of nodes. Publicly call deleteTree() instead.
|
||||
// Audited to make sure this is never NULL
|
||||
for (AstNode* nodep=this, *nnextp; nodep; nodep=nnextp) {
|
||||
for (AstNode *nodep = this, *nnextp; nodep; nodep = nnextp) {
|
||||
nnextp = nodep->m_nextp;
|
||||
// MUST be depth first!
|
||||
if (nodep->m_op1p) nodep->m_op1p->deleteTreeIter();
|
||||
|
|
@ -789,26 +819,25 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
|
|||
// there's no lower level reason yet though the back must exist.
|
||||
AstNode* nodep = this;
|
||||
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
|
||||
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep,
|
||||
"iterateAndNext node has no back");
|
||||
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep, "iterateAndNext node has no back");
|
||||
#endif
|
||||
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
|
||||
while (nodep) { // effectively: if (!this) return; // Callers rely on this
|
||||
while (nodep) { // effectively: if (!this) return; // Callers rely on this
|
||||
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
|
||||
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
|
||||
AstNode* niterp = nodep; // Pointer may get stomped via m_iterpp if the node is edited
|
||||
// Desirable check, but many places where multiple iterations are OK
|
||||
// UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss edits");
|
||||
// Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
|
||||
// UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss
|
||||
// edits"); Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
|
||||
// cppcheck-suppress nullPointer
|
||||
niterp->m_iterpp = &niterp;
|
||||
niterp->accept(v);
|
||||
// accept may do a replaceNode and change niterp on us...
|
||||
// niterp maybe NULL, so need cast if printing
|
||||
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
|
||||
// if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
|
||||
// <<" now into "<<cvtToHex(niterp)<<endl);
|
||||
if (!niterp) return; // Perhaps node deleted inside accept
|
||||
niterp->m_iterpp = NULL;
|
||||
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
|
||||
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
|
||||
nodep = niterp;
|
||||
} else { // Unchanged node, just continue loop
|
||||
nodep = niterp->m_nextp;
|
||||
|
|
@ -822,8 +851,11 @@ void AstNode::iterateListBackwards(AstNVisitor& v) {
|
|||
while (nodep) {
|
||||
// Edits not supported: nodep->m_iterpp = &nodep;
|
||||
nodep->accept(v);
|
||||
if (nodep->backp()->m_nextp == nodep) nodep = nodep->backp();
|
||||
else nodep = NULL; // else: backp points up the tree.
|
||||
if (nodep->backp()->m_nextp == nodep) {
|
||||
nodep = nodep->backp();
|
||||
} else {
|
||||
nodep = NULL;
|
||||
} // else: backp points up the tree.
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -861,7 +893,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||
// track, then delete it on completion
|
||||
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
||||
{
|
||||
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced
|
||||
VL_DO_DANGLING(tempp->stmtsp()->accept(v),
|
||||
nodep); // nodep to null as may be replaced
|
||||
}
|
||||
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
||||
|
|
@ -869,11 +902,17 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||
// Use back to determine who's pointing at us (IE assume new node
|
||||
// grafts into same place as old one)
|
||||
AstNode** nextnodepp = NULL;
|
||||
if (this->m_backp->m_op1p == this) nextnodepp = &(this->m_backp->m_op1p);
|
||||
else if (this->m_backp->m_op2p == this) nextnodepp = &(this->m_backp->m_op2p);
|
||||
else if (this->m_backp->m_op3p == this) nextnodepp = &(this->m_backp->m_op3p);
|
||||
else if (this->m_backp->m_op4p == this) nextnodepp = &(this->m_backp->m_op4p);
|
||||
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
|
||||
if (this->m_backp->m_op1p == this) {
|
||||
nextnodepp = &(this->m_backp->m_op1p);
|
||||
} else if (this->m_backp->m_op2p == this) {
|
||||
nextnodepp = &(this->m_backp->m_op2p);
|
||||
} else if (this->m_backp->m_op3p == this) {
|
||||
nextnodepp = &(this->m_backp->m_op3p);
|
||||
} else if (this->m_backp->m_op4p == this) {
|
||||
nextnodepp = &(this->m_backp->m_op4p);
|
||||
} else if (this->m_backp->m_nextp == this) {
|
||||
nextnodepp = &(this->m_backp->m_nextp);
|
||||
}
|
||||
UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself");
|
||||
{
|
||||
VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced
|
||||
|
|
@ -887,10 +926,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||
|
||||
void AstNode::cloneRelinkTree() {
|
||||
// private: Cleanup clone() operation on whole tree. Publicly call cloneTree() instead.
|
||||
for (AstNode* nodep=this; nodep; nodep = nodep->m_nextp) {
|
||||
if (m_dtypep && m_dtypep->clonep()) {
|
||||
m_dtypep = m_dtypep->clonep();
|
||||
}
|
||||
for (AstNode* nodep = this; nodep; nodep = nodep->m_nextp) {
|
||||
if (m_dtypep && m_dtypep->clonep()) m_dtypep = m_dtypep->clonep();
|
||||
nodep->cloneRelink();
|
||||
if (nodep->m_op1p) nodep->m_op1p->cloneRelinkTree();
|
||||
if (nodep->m_op2p) nodep->m_op2p->cloneRelinkTree();
|
||||
|
|
@ -912,37 +949,34 @@ bool AstNode::gateTreeIter() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p,
|
||||
bool ignNext, bool gateOnly) {
|
||||
bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
|
||||
bool gateOnly) {
|
||||
// private: Return true if the two trees are identical
|
||||
if (!node1p && !node2p) return true;
|
||||
if (!node1p || !node2p) return false;
|
||||
if (node1p->type() != node2p->type()
|
||||
|| node1p->dtypep() != node2p->dtypep()
|
||||
|| !node1p->same(node2p)
|
||||
|| (gateOnly && !node1p->isGateOptimizable())) {
|
||||
if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep()
|
||||
|| !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) {
|
||||
return false;
|
||||
}
|
||||
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly)
|
||||
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly)
|
||||
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly)
|
||||
&& sameTreeIter(node1p->m_op4p, node2p->m_op4p, false, gateOnly)
|
||||
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly))
|
||||
);
|
||||
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly)));
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Static utilities
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
|
||||
return os<<std::hex<<std::setw(2)<<std::setfill('0')<<rhs.depth()
|
||||
<<"_"<<std::setw(6)<<std::setfill('0')<<rhs.hshval();
|
||||
return os << std::hex << std::setw(2) << std::setfill('0') << rhs.depth() << "_"
|
||||
<< std::setw(6) << std::setfill('0') << rhs.hshval();
|
||||
}
|
||||
|
||||
V3Hash::V3Hash(const string& name) {
|
||||
uint32_t val = 0;
|
||||
for (string::const_iterator it = name.begin(); it!=name.end(); ++it) {
|
||||
val = val*31 + *it;
|
||||
for (string::const_iterator it = name.begin(); it != name.end(); ++it) {
|
||||
val = val * 31 + *it;
|
||||
}
|
||||
setBoth(1, val);
|
||||
}
|
||||
|
|
@ -955,7 +989,7 @@ void AstNode::checkTreeIter(AstNode* backp) {
|
|||
UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent");
|
||||
if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) {
|
||||
// Termops have a short-circuited iterateChildren, so check usage
|
||||
UASSERT_OBJ(!(op1p()||op2p()||op3p()||op4p()), this,
|
||||
UASSERT_OBJ(!(op1p() || op2p() || op3p() || op4p()), this,
|
||||
"Terminal operation with non-terminals");
|
||||
}
|
||||
if (m_op1p) m_op1p->checkTreeIterList(this);
|
||||
|
|
@ -969,9 +1003,9 @@ void AstNode::checkTreeIterList(AstNode* backp) {
|
|||
// Audited to make sure this is never NULL
|
||||
AstNode* headp = this;
|
||||
AstNode* tailp = this;
|
||||
for (AstNode* nodep=headp; nodep; nodep=nodep->nextp()) {
|
||||
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
|
||||
nodep->checkTreeIter(backp);
|
||||
UASSERT_OBJ(headp==this || !nextp(), this,
|
||||
UASSERT_OBJ(headp == this || !nextp(), this,
|
||||
"Headtailp should be null in middle of lists");
|
||||
tailp = nodep;
|
||||
backp = nodep;
|
||||
|
|
@ -993,12 +1027,14 @@ void AstNode::checkTree() {
|
|||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
|
||||
dumpGdbHeader(); // LCOV_EXCL_LINE
|
||||
cout<<" "; dump(cout); cout<<endl; // LCOV_EXCL_LINE
|
||||
cout << " ";
|
||||
dump(cout);
|
||||
cout << endl; // LCOV_EXCL_LINE
|
||||
}
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
|
||||
dumpPtrs(cout); // LCOV_EXCL_LINE
|
||||
cout<<" Fileline = "<<fileline()<<endl; // LCOV_EXCL_LINE
|
||||
cout << " Fileline = " << fileline() << endl; // LCOV_EXCL_LINE
|
||||
}
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
|
||||
|
|
@ -1007,7 +1043,8 @@ void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
|
|||
}
|
||||
// cppcheck-suppress unusedFunction // Debug only
|
||||
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
|
||||
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
|
||||
string filename
|
||||
= filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
|
||||
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
|
|
@ -1021,45 +1058,53 @@ void AstNode::checkIter() const {
|
|||
}
|
||||
|
||||
void AstNode::dumpPtrs(std::ostream& os) const {
|
||||
os<<"This="<<typeName()<<" "<<cvtToHex(this);
|
||||
os<<" back="<<cvtToHex(backp());
|
||||
if (nextp()) os<<" next="<<cvtToHex(nextp());
|
||||
if (m_headtailp==this) os<<" headtail=this";
|
||||
else os<<" headtail="<<cvtToHex(m_headtailp);
|
||||
if (op1p()) os<<" op1p="<<cvtToHex(op1p());
|
||||
if (op2p()) os<<" op2p="<<cvtToHex(op2p());
|
||||
if (op3p()) os<<" op3p="<<cvtToHex(op3p());
|
||||
if (op4p()) os<<" op4p="<<cvtToHex(op4p());
|
||||
if (user1p()) os<<" user1p="<<cvtToHex(user1p());
|
||||
if (user2p()) os<<" user2p="<<cvtToHex(user2p());
|
||||
if (user3p()) os<<" user3p="<<cvtToHex(user3p());
|
||||
if (user4p()) os<<" user4p="<<cvtToHex(user4p());
|
||||
if (user5p()) os<<" user5p="<<cvtToHex(user5p());
|
||||
if (m_iterpp) {
|
||||
os<<" iterpp="<<cvtToHex(m_iterpp);
|
||||
os<<"*="<<cvtToHex(*m_iterpp);
|
||||
os << "This=" << typeName() << " " << cvtToHex(this);
|
||||
os << " back=" << cvtToHex(backp());
|
||||
if (nextp()) os << " next=" << cvtToHex(nextp());
|
||||
if (m_headtailp == this) {
|
||||
os << " headtail=this";
|
||||
} else {
|
||||
os << " headtail=" << cvtToHex(m_headtailp);
|
||||
}
|
||||
os<<endl;
|
||||
if (op1p()) os << " op1p=" << cvtToHex(op1p());
|
||||
if (op2p()) os << " op2p=" << cvtToHex(op2p());
|
||||
if (op3p()) os << " op3p=" << cvtToHex(op3p());
|
||||
if (op4p()) os << " op4p=" << cvtToHex(op4p());
|
||||
if (user1p()) os << " user1p=" << cvtToHex(user1p());
|
||||
if (user2p()) os << " user2p=" << cvtToHex(user2p());
|
||||
if (user3p()) os << " user3p=" << cvtToHex(user3p());
|
||||
if (user4p()) os << " user4p=" << cvtToHex(user4p());
|
||||
if (user5p()) os << " user5p=" << cvtToHex(user5p());
|
||||
if (m_iterpp) {
|
||||
os << " iterpp=" << cvtToHex(m_iterpp);
|
||||
os << "*=" << cvtToHex(*m_iterpp);
|
||||
}
|
||||
os << endl;
|
||||
}
|
||||
|
||||
void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const {
|
||||
static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9
|
||||
os<<indent<<" "<<this<<endl;
|
||||
if (debug()>8) { os<<indent<<" "; dumpPtrs(os); }
|
||||
if (s_debugFileline >= 9) {
|
||||
os<<fileline()->warnContextSecondary();
|
||||
os << indent << " " << this << endl;
|
||||
if (debug() > 8) {
|
||||
os << indent << " ";
|
||||
dumpPtrs(os);
|
||||
}
|
||||
if (maxDepth==1) {
|
||||
if (op1p()||op2p()||op3p()||op4p()) { os<<indent<<"1: ...(maxDepth)"<<endl; }
|
||||
if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); }
|
||||
if (maxDepth == 1) {
|
||||
if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; }
|
||||
} else {
|
||||
for (const AstNode* nodep=op1p(); nodep; nodep=nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent+"1:", maxDepth-1); }
|
||||
for (const AstNode* nodep=op2p(); nodep; nodep=nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent+"2:", maxDepth-1); }
|
||||
for (const AstNode* nodep=op3p(); nodep; nodep=nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent+"3:", maxDepth-1); }
|
||||
for (const AstNode* nodep=op4p(); nodep; nodep=nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent+"4:", maxDepth-1); }
|
||||
for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent + "1:", maxDepth - 1);
|
||||
}
|
||||
for (const AstNode* nodep = op2p(); nodep; nodep = nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent + "2:", maxDepth - 1);
|
||||
}
|
||||
for (const AstNode* nodep = op3p(); nodep; nodep = nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent + "3:", maxDepth - 1);
|
||||
}
|
||||
for (const AstNode* nodep = op4p(); nodep; nodep = nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent + "4:", maxDepth - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1073,16 +1118,15 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
|
|||
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
// Not const function as calls checkTree
|
||||
if (doDump) {
|
||||
{ // Write log & close
|
||||
UINFO(2,"Dumping "<<filename<<endl);
|
||||
const vl_unique_ptr<std::ofstream> logsp (V3File::new_ofstream(filename, append));
|
||||
if (logsp->fail()) v3fatal("Can't write "<<filename);
|
||||
*logsp<<"Verilator Tree Dump (format 0x3900) from <e"<<std::dec<<editCountLast()<<">";
|
||||
*logsp<<" to <e"<<std::dec<<editCountGbl()<<">"<<endl;
|
||||
if (editCountGbl()==editCountLast()
|
||||
&& !(v3Global.opt.dumpTree()>=9)) {
|
||||
*logsp<<endl;
|
||||
*logsp<<"No changes since last dump!\n";
|
||||
{ // Write log & close
|
||||
UINFO(2, "Dumping " << filename << endl);
|
||||
const vl_unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
|
||||
if (logsp->fail()) v3fatal("Can't write " << filename);
|
||||
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
|
||||
*logsp << "> to <e" << std::dec << editCountGbl() << ">" << endl;
|
||||
if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) {
|
||||
*logsp << endl;
|
||||
*logsp << "No changes since last dump!\n";
|
||||
} else {
|
||||
dumpTree(*logsp);
|
||||
}
|
||||
|
|
@ -1100,7 +1144,9 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
|||
}
|
||||
|
||||
void AstNode::v3errorEndFatal(std::ostringstream& str) const {
|
||||
v3errorEnd(str); assert(0); VL_UNREACHABLE
|
||||
v3errorEnd(str);
|
||||
assert(0);
|
||||
VL_UNREACHABLE
|
||||
}
|
||||
|
||||
string AstNode::locationStr() const {
|
||||
|
|
@ -1148,12 +1194,12 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
|||
V3Error::v3errorEnd(str, locationStr());
|
||||
} else {
|
||||
std::ostringstream nsstr;
|
||||
nsstr<<str.str();
|
||||
nsstr << str.str();
|
||||
if (debug()) {
|
||||
nsstr<<endl;
|
||||
nsstr<<"-node: ";
|
||||
nsstr << endl;
|
||||
nsstr << "-node: ";
|
||||
const_cast<AstNode*>(this)->dump(nsstr);
|
||||
nsstr<<endl;
|
||||
nsstr << endl;
|
||||
}
|
||||
m_fileline->v3errorEnd(nsstr, locationStr());
|
||||
}
|
||||
|
|
@ -1164,8 +1210,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
|||
|
||||
void AstNode::dtypeChgSigned(bool flag) {
|
||||
UASSERT_OBJ(dtypep(), this, "No dtype when changing to (un)signed");
|
||||
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(),
|
||||
AstNumeric::fromBool(flag));
|
||||
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), AstNumeric::fromBool(flag));
|
||||
}
|
||||
void AstNode::dtypeChgWidth(int width, int widthMin) {
|
||||
UASSERT_OBJ(dtypep(), this,
|
||||
|
|
@ -1178,9 +1223,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
|
|||
// We allow dtypep() to be null, as before/during widthing dtypes are not resolved
|
||||
dtypeSetLogicUnsized(width, widthMin, numeric);
|
||||
} else {
|
||||
if (width==dtypep()->width()
|
||||
&& widthMin==dtypep()->widthMin()
|
||||
&& numeric==dtypep()->numeric()) return; // Correct already
|
||||
if (width == dtypep()->width() && widthMin == dtypep()->widthMin()
|
||||
&& numeric == dtypep()->numeric())
|
||||
return; // Correct already
|
||||
// FUTURE: We may be pointing at a two state data type, and this may
|
||||
// convert it to logic. Since the AstVar remains correct, we
|
||||
// work OK but this assumption may break in the future.
|
||||
|
|
@ -1193,34 +1238,31 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
|
|||
AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const {
|
||||
// For 'simple' types we use the global directory. These are all unsized.
|
||||
// More advanced types land under the module/task/etc
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findBasicDType(fileline(), kwd);
|
||||
return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd);
|
||||
}
|
||||
AstNodeDType* AstNode::findBitDType(int width, int widthMin, AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, width, widthMin, numeric);
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT,
|
||||
width, widthMin, numeric);
|
||||
}
|
||||
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric);
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC,
|
||||
width, widthMin, numeric);
|
||||
}
|
||||
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin,
|
||||
AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric);
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC,
|
||||
range, widthMin, numeric);
|
||||
}
|
||||
AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin,
|
||||
AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, range, widthMin, numeric);
|
||||
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT,
|
||||
range, widthMin, numeric);
|
||||
}
|
||||
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findInsertSameDType(nodep);
|
||||
return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep);
|
||||
}
|
||||
AstNodeDType* AstNode::findVoidDType() const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findVoidDType(fileline());
|
||||
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
|
|
|||
1568
src/V3Ast.h
1568
src/V3Ast.h
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3101
src/V3AstNodes.h
3101
src/V3AstNodes.h
File diff suppressed because it is too large
Load Diff
117
src/V3Begin.cpp
117
src/V3Begin.cpp
|
|
@ -42,14 +42,14 @@
|
|||
class BeginState {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// Entire netlist:
|
||||
// AstNodeFTask::user1 -> bool, 1=processed
|
||||
AstUser1InUse m_inuser1;
|
||||
bool m_anyFuncInBegin;
|
||||
AstUser1InUse m_inuser1;
|
||||
bool m_anyFuncInBegin;
|
||||
|
||||
public:
|
||||
BeginState() {
|
||||
m_anyFuncInBegin = false;
|
||||
}
|
||||
BeginState()
|
||||
: m_anyFuncInBegin(false) {}
|
||||
~BeginState() {}
|
||||
void userMarkChanged(AstNode* nodep) {
|
||||
nodep->user1(true);
|
||||
|
|
@ -63,12 +63,12 @@ public:
|
|||
class BeginVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
BeginState* m_statep; // Current global state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_ifDepth; // Current if depth
|
||||
BeginState* m_statep; // Current global state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_ifDepth; // Current if depth
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -83,11 +83,11 @@ private:
|
|||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
UINFO(8, " " << nodep << endl);
|
||||
// Rename it
|
||||
if (m_unnamedScope != "") {
|
||||
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
||||
UINFO(8," rename to "<<nodep->name()<<endl);
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
UINFO(8, " rename to " << nodep->name() << endl);
|
||||
m_statep->userMarkChanged(nodep);
|
||||
}
|
||||
// BEGIN wrapping a function rename that function, but don't affect
|
||||
|
|
@ -109,28 +109,34 @@ private:
|
|||
}
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
UINFO(8, " " << nodep << endl);
|
||||
string oldScope = m_namedScope;
|
||||
string oldUnnamed = m_unnamedScope;
|
||||
{
|
||||
UINFO(8,"nname "<<m_namedScope<<endl);
|
||||
UINFO(8, "nname " << m_namedScope << endl);
|
||||
if (nodep->name() != "") { // Else unneeded unnamed block
|
||||
// Create data for dotted variable resolution
|
||||
string dottedname = nodep->name() + "__DOT__"; // So always found
|
||||
string::size_type pos;
|
||||
while ((pos=dottedname.find("__DOT__")) != string::npos) {
|
||||
while ((pos = dottedname.find("__DOT__")) != string::npos) {
|
||||
string ident = dottedname.substr(0, pos);
|
||||
dottedname = dottedname.substr(pos+strlen("__DOT__"));
|
||||
dottedname = dottedname.substr(pos + strlen("__DOT__"));
|
||||
if (nodep->name() != "") {
|
||||
if (m_namedScope=="") m_namedScope = ident;
|
||||
else m_namedScope = m_namedScope + "__DOT__"+ident;
|
||||
if (m_namedScope == "") {
|
||||
m_namedScope = ident;
|
||||
} else {
|
||||
m_namedScope = m_namedScope + "__DOT__" + ident;
|
||||
}
|
||||
}
|
||||
if (m_unnamedScope == "") {
|
||||
m_unnamedScope = ident;
|
||||
} else {
|
||||
m_unnamedScope = m_unnamedScope + "__DOT__" + ident;
|
||||
}
|
||||
if (m_unnamedScope=="") m_unnamedScope = ident;
|
||||
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
|
||||
// Create CellInline for dotted var resolution
|
||||
if (!m_ftaskp) {
|
||||
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
|
||||
m_unnamedScope, "__BEGIN__");
|
||||
AstCellInline* inlinep
|
||||
= new AstCellInline(nodep->fileline(), m_unnamedScope, "__BEGIN__");
|
||||
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
|
||||
}
|
||||
}
|
||||
|
|
@ -147,7 +153,11 @@ private:
|
|||
AstNode* addsp = NULL;
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
|
||||
if (addsp) {
|
||||
addsp = addsp->addNextNull(stmtsp);
|
||||
} else {
|
||||
addsp = stmtsp;
|
||||
}
|
||||
}
|
||||
if (addsp) {
|
||||
nodep->replaceWith(addsp);
|
||||
|
|
@ -159,12 +169,15 @@ private:
|
|||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
||||
nodep->name(m_unnamedScope + "__DOT__" + nodep->name());
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
|
||||
else m_modp->addStmtp(nodep);
|
||||
if (m_ftaskp) {
|
||||
m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
|
||||
} else {
|
||||
m_modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
|
|
@ -175,17 +188,20 @@ private:
|
|||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
// Begins under funcs just move into the func
|
||||
if (m_ftaskp) m_ftaskp->addStmtsp(nodep);
|
||||
else m_modp->addStmtp(nodep);
|
||||
if (m_ftaskp) {
|
||||
m_ftaskp->addStmtsp(nodep);
|
||||
} else {
|
||||
m_modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(8," CELL "<<nodep<<endl);
|
||||
UINFO(8, " CELL " << nodep << endl);
|
||||
if (m_namedScope != "") {
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Rename it
|
||||
nodep->name(m_namedScope+"__DOT__"+nodep->name());
|
||||
UINFO(8," rename to "<<nodep->name()<<endl);
|
||||
nodep->name(m_namedScope + "__DOT__" + nodep->name());
|
||||
UINFO(8, " rename to " << nodep->name() << endl);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
m_modp->addStmtp(nodep);
|
||||
|
|
@ -193,10 +209,10 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
UINFO(9, " VARXREF "<<nodep<<endl);
|
||||
UINFO(9, " VARXREF " << nodep << endl);
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "") {
|
||||
nodep->inlinedDots(m_namedScope);
|
||||
UINFO(9, " rescope to "<<nodep<<endl);
|
||||
UINFO(9, " rescope to " << nodep << endl);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
|
|
@ -207,7 +223,7 @@ private:
|
|||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__")+m_namedScope));
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), string("__DOT__") + m_namedScope));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -218,14 +234,15 @@ private:
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
// VISITORS - LINT CHECK
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE { // Note not AstNodeIf; other types don't get covered
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE { // not AstNodeIf; other types not covered
|
||||
// Check IFDEPTH warning - could be in other transform files if desire
|
||||
int prevIfDepth = m_ifDepth;
|
||||
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
|
||||
if (m_ifDepth == -1 || v3Global.opt.ifDepth() < 1) { // Turned off
|
||||
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
|
||||
m_ifDepth = -1;
|
||||
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
|
||||
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
|
||||
nodep->v3warn(IFDEPTH,
|
||||
"Deep 'if' statement; suggest unique/priority to avoid slow logic");
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once
|
||||
m_ifDepth = -1;
|
||||
}
|
||||
|
|
@ -258,14 +275,14 @@ private:
|
|||
// VISITORS
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->taskp()->user1()) { // It was converted
|
||||
UINFO(9, " relinkFTask "<<nodep<<endl);
|
||||
UINFO(9, " relinkFTask " << nodep << endl);
|
||||
nodep->name(nodep->taskp()->name());
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp()->user1()) { // It was converted
|
||||
UINFO(9, " relinVarRef "<<nodep<<endl);
|
||||
UINFO(9, " relinVarRef " << nodep << endl);
|
||||
nodep->name(nodep->varp()->name());
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -273,9 +290,9 @@ private:
|
|||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
// May have changed cell names
|
||||
// TypeTable is always after all modules, so names are stable
|
||||
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
|
||||
UINFO(8, " IFACEREFDTYPE " << nodep << endl);
|
||||
if (nodep->cellp()) nodep->cellName(nodep->cellp()->name());
|
||||
UINFO(8," rename to "<<nodep<<endl);
|
||||
UINFO(8, " rename to " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
//--------------------
|
||||
|
|
@ -283,9 +300,7 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) {
|
||||
iterate(nodep);
|
||||
}
|
||||
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); }
|
||||
virtual ~BeginRelinkVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -293,13 +308,11 @@ public:
|
|||
// Task class functions
|
||||
|
||||
void V3Begin::debeginAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
BeginState state;
|
||||
{ BeginVisitor bvisitor (nodep,&state); }
|
||||
if (state.anyFuncInBegin()) {
|
||||
BeginRelinkVisitor brvisitor (nodep,&state);
|
||||
}
|
||||
{ BeginVisitor bvisitor(nodep, &state); }
|
||||
if (state.anyFuncInBegin()) { BeginRelinkVisitor brvisitor(nodep, &state); }
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,35 +42,35 @@ class BrokenTable : public AstNVisitor {
|
|||
private:
|
||||
// MEMBERS
|
||||
// For each node, we keep if it exists or not.
|
||||
typedef vl_unordered_map<const AstNode*,int> NodeMap; // Performance matters (when --debug)
|
||||
typedef vl_unordered_map<const AstNode*, int> NodeMap; // Performance matters (when --debug)
|
||||
static NodeMap s_nodes; // Set of all nodes that exist
|
||||
// BITMASK
|
||||
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
|
||||
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
|
||||
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
|
||||
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
|
||||
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
|
||||
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
|
||||
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
|
||||
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
|
||||
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
|
||||
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
|
||||
public:
|
||||
// METHODS
|
||||
static void deleted(const AstNode* nodep) {
|
||||
// Called by operator delete on any node - only if VL_LEAK_CHECKS
|
||||
if (debug()>=9) cout<<"-nodeDel: "<<cvtToHex(nodep)<<endl;
|
||||
if (debug() >= 9) cout << "-nodeDel: " << cvtToHex(nodep) << endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
UASSERT_OBJ(!(iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
|
||||
UASSERT_OBJ(!(iter == s_nodes.end() || !(iter->second & FLAG_ALLOCATED)),
|
||||
reinterpret_cast<const AstNode*>(nodep),
|
||||
"Deleting AstNode object that was never tracked or already deleted");
|
||||
if (iter!=s_nodes.end()) s_nodes.erase(iter);
|
||||
if (iter != s_nodes.end()) s_nodes.erase(iter);
|
||||
}
|
||||
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
|
||||
// GCC 4.4.* compiler warning bug, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390
|
||||
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
static void addNewed(const AstNode* nodep) {
|
||||
// Called by operator new on any node - only if VL_LEAK_CHECKS
|
||||
if (debug()>=9) cout<<"-nodeNew: "<<cvtToHex(nodep)<<endl;
|
||||
if (debug() >= 9) cout << "-nodeNew: " << cvtToHex(nodep) << endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
UASSERT_OBJ(!(iter !=s_nodes.end() && (iter->second & FLAG_ALLOCATED)),
|
||||
nodep, "Newing AstNode object that is already allocated");
|
||||
UASSERT_OBJ(!(iter != s_nodes.end() && (iter->second & FLAG_ALLOCATED)), nodep,
|
||||
"Newing AstNode object that is already allocated");
|
||||
if (iter == s_nodes.end()) {
|
||||
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
|
||||
s_nodes.insert(make_pair(nodep, flags));
|
||||
|
|
@ -80,9 +80,9 @@ public:
|
|||
// Called by BrokenCheckVisitor when each node entered/exited
|
||||
if (!okIfLinkedTo(nodep)) return;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter!=s_nodes.end()) {
|
||||
if (iter != s_nodes.end()) {
|
||||
iter->second &= ~FLAG_UNDER_NOW;
|
||||
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||
}
|
||||
}
|
||||
static void addInTree(AstNode* nodep, bool linkable) {
|
||||
|
|
@ -103,7 +103,7 @@ public:
|
|||
UASSERT_OBJ(!(iter->second & FLAG_IN_TREE), nodep,
|
||||
"AstNode is already in tree at another location");
|
||||
}
|
||||
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
|
||||
int or_flags = FLAG_IN_TREE | (linkable ? FLAG_LINKABLE : 0);
|
||||
if (iter == s_nodes.end()) {
|
||||
s_nodes.insert(make_pair(nodep, or_flags));
|
||||
} else {
|
||||
|
|
@ -149,12 +149,12 @@ public:
|
|||
}
|
||||
}
|
||||
static void doneWithTree() {
|
||||
for (int backs=0; backs<2; backs++) { // Those with backp() are probably under one leaking without
|
||||
for (int backs = 0; backs < 2;
|
||||
backs++) { // Those with backp() are probably under one leaking without
|
||||
for (NodeMap::iterator it = s_nodes.begin(); it != s_nodes.end(); ++it) {
|
||||
if ((it->second & FLAG_ALLOCATED)
|
||||
&& !(it->second & FLAG_IN_TREE)
|
||||
if ((it->second & FLAG_ALLOCATED) && !(it->second & FLAG_IN_TREE)
|
||||
&& !(it->second & FLAG_LEAKED)
|
||||
&& (it->first->backp() ? backs==1 : backs==0)) {
|
||||
&& (it->first->backp() ? backs == 1 : backs == 0)) {
|
||||
// Use only AstNode::dump instead of the virtual one, as there
|
||||
// may be varp() and other cross links that are bad.
|
||||
if (v3Global.opt.debugCheck()) {
|
||||
|
|
@ -163,11 +163,12 @@ public:
|
|||
// watch AstNode::s_editCntGbl==####
|
||||
// run
|
||||
// bt
|
||||
std::cerr<<"%Error: LeakedNode"<<(it->first->backp()?"Back: ":": ");
|
||||
AstNode* rawp = const_cast<AstNode*>
|
||||
(static_cast<const AstNode*>(it->first));
|
||||
std::cerr << "%Error: LeakedNode"
|
||||
<< (it->first->backp() ? "Back: " : ": ");
|
||||
AstNode* rawp
|
||||
= const_cast<AstNode*>(static_cast<const AstNode*>(it->first));
|
||||
rawp->AstNode::dump(std::cerr);
|
||||
std::cerr<<endl;
|
||||
std::cerr << endl;
|
||||
V3Error::incErrors();
|
||||
}
|
||||
it->second |= FLAG_LEAKED;
|
||||
|
|
@ -175,6 +176,7 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
BrokenTable() {}
|
||||
|
|
@ -213,9 +215,7 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenMarkVisitor(AstNetlist* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~BrokenMarkVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -226,27 +226,27 @@ class BrokenCheckVisitor : public AstNVisitor {
|
|||
private:
|
||||
void checkWidthMin(const AstNode* nodep) {
|
||||
UASSERT_OBJ(nodep->width() == nodep->widthMin()
|
||||
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
|
||||
|| v3Global.widthMinUsage() != VWidthMinUsage::MATCHES_WIDTH,
|
||||
nodep, "Width != WidthMin");
|
||||
}
|
||||
void processAndIterate(AstNode* nodep) {
|
||||
BrokenTable::setUnder(nodep, true);
|
||||
const char* whyp = nodep->broken();
|
||||
UASSERT_OBJ(!whyp, nodep,
|
||||
"Broken link in node (or something without maybePointedTo): "<<whyp);
|
||||
"Broken link in node (or something without maybePointedTo): " << whyp);
|
||||
if (nodep->dtypep()) {
|
||||
UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep,
|
||||
"Broken link in node->dtypep() to "<<cvtToHex(nodep->dtypep()));
|
||||
"Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
|
||||
UASSERT_OBJ(VN_IS(nodep->dtypep(), NodeDType), nodep,
|
||||
"Non-dtype link in node->dtypep() to "<<cvtToHex(nodep->dtypep()));
|
||||
"Non-dtype link in node->dtypep() to " << cvtToHex(nodep->dtypep()));
|
||||
}
|
||||
if (v3Global.assertDTypesResolved()) {
|
||||
if (nodep->hasDType()) {
|
||||
UASSERT_OBJ(nodep->dtypep(), nodep,
|
||||
"No dtype on node with hasDType(): "<<nodep->prettyTypeName());
|
||||
"No dtype on node with hasDType(): " << nodep->prettyTypeName());
|
||||
} else {
|
||||
UASSERT_OBJ(!nodep->dtypep(), nodep,
|
||||
"DType on node without hasDType(): "<<nodep->prettyTypeName());
|
||||
"DType on node without hasDType(): " << nodep->prettyTypeName());
|
||||
}
|
||||
UASSERT_OBJ(!nodep->getChildDTypep(), nodep,
|
||||
"childDTypep() non-null on node after should have removed");
|
||||
|
|
@ -258,8 +258,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
processAndIterate(nodep);
|
||||
UASSERT_OBJ(!(v3Global.assertDTypesResolved()
|
||||
&& nodep->brokeLhsMustBeLvalue()
|
||||
UASSERT_OBJ(!(v3Global.assertDTypesResolved() && nodep->brokeLhsMustBeLvalue()
|
||||
&& VN_IS(nodep->lhsp(), NodeVarRef)
|
||||
&& !VN_CAST(nodep->lhsp(), NodeVarRef)->lvalue()),
|
||||
nodep, "Assignment LHS is not an lvalue");
|
||||
|
|
@ -268,11 +267,10 @@ private:
|
|||
// Process not just iterate
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~BrokenCheckVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -280,27 +278,21 @@ public:
|
|||
// Broken class functions
|
||||
|
||||
void V3Broken::brokenAll(AstNetlist* nodep) {
|
||||
//UINFO(9,__FUNCTION__<<": "<<endl);
|
||||
// UINFO(9, __FUNCTION__ << ": " << endl);
|
||||
static bool inBroken = false;
|
||||
if (VL_UNCOVERABLE(inBroken)) {
|
||||
// A error called by broken can recurse back into broken; avoid this
|
||||
UINFO(1,"Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
|
||||
UINFO(1, "Broken called under broken, skipping recursion.\n"); // LCOV_EXCL_LINE
|
||||
} else {
|
||||
inBroken = true;
|
||||
BrokenTable::prepForTree();
|
||||
BrokenMarkVisitor mvisitor (nodep);
|
||||
BrokenCheckVisitor cvisitor (nodep);
|
||||
BrokenMarkVisitor mvisitor(nodep);
|
||||
BrokenCheckVisitor cvisitor(nodep);
|
||||
BrokenTable::doneWithTree();
|
||||
inBroken = false;
|
||||
}
|
||||
}
|
||||
|
||||
void V3Broken::addNewed(AstNode* nodep) {
|
||||
BrokenTable::addNewed(nodep);
|
||||
}
|
||||
void V3Broken::deleted(AstNode* nodep) {
|
||||
BrokenTable::deleted(nodep);
|
||||
}
|
||||
bool V3Broken::isAllocated(AstNode* nodep) {
|
||||
return BrokenTable::isAllocated(nodep);
|
||||
}
|
||||
void V3Broken::addNewed(AstNode* nodep) { BrokenTable::addNewed(nodep); }
|
||||
void V3Broken::deleted(AstNode* nodep) { BrokenTable::deleted(nodep); }
|
||||
bool V3Broken::isAllocated(AstNode* nodep) { return BrokenTable::isAllocated(nodep); }
|
||||
|
|
|
|||
|
|
@ -39,25 +39,24 @@
|
|||
|
||||
class V3CCtorsVisitor {
|
||||
private:
|
||||
string m_basename;
|
||||
string m_argsp;
|
||||
string m_callargsp;
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_tlFuncp; // Top level function being built
|
||||
AstCFunc* m_funcp; // Current function
|
||||
int m_numStmts; // Number of statements output
|
||||
int m_funcNum; // Function number being built
|
||||
string m_basename;
|
||||
string m_argsp;
|
||||
string m_callargsp;
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_tlFuncp; // Top level function being built
|
||||
AstCFunc* m_funcp; // Current function
|
||||
int m_numStmts; // Number of statements output
|
||||
int m_funcNum; // Function number being built
|
||||
|
||||
public:
|
||||
AstCFunc* builtFuncp() const { return m_tlFuncp; }
|
||||
void add(AstNode* nodep) {
|
||||
if (v3Global.opt.outputSplitCFuncs()
|
||||
&& v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||
if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||
m_funcp = NULL;
|
||||
}
|
||||
if (!m_funcp) {
|
||||
m_funcp = new AstCFunc(m_modp->fileline(),
|
||||
m_basename+"_"+cvtToStr(++m_funcNum), NULL, "void");
|
||||
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum),
|
||||
NULL, "void");
|
||||
m_funcp->isStatic(false);
|
||||
m_funcp->declPrivate(true);
|
||||
m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
|
||||
|
|
@ -75,9 +74,8 @@ public:
|
|||
m_numStmts += 1;
|
||||
}
|
||||
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename,
|
||||
const string& argsp="", const string& callargsp="",
|
||||
const string& stmt="") {
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, const string& argsp = "",
|
||||
const string& callargsp = "", const string& stmt = "") {
|
||||
m_basename = basename;
|
||||
m_argsp = argsp;
|
||||
m_callargsp = callargsp;
|
||||
|
|
@ -89,13 +87,12 @@ public:
|
|||
m_tlFuncp->isStatic(false);
|
||||
m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path
|
||||
m_tlFuncp->argTypes(m_argsp);
|
||||
if (stmt != "") {
|
||||
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
}
|
||||
if (stmt != "") { m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); }
|
||||
m_funcp = m_tlFuncp;
|
||||
m_modp->addStmtp(m_tlFuncp);
|
||||
}
|
||||
~V3CCtorsVisitor() {}
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(V3CCtorsVisitor);
|
||||
};
|
||||
|
|
@ -122,15 +119,16 @@ void V3CCtors::evalAsserts() {
|
|||
if (varp->isWide()) {
|
||||
newp = new AstWordSel(
|
||||
varp->fileline(), newp,
|
||||
new AstConst(varp->fileline(), varp->widthWords()-1));
|
||||
new AstConst(varp->fileline(), varp->widthWords() - 1));
|
||||
}
|
||||
uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
|
||||
newp = new AstAnd(varp->fileline(), newp,
|
||||
new AstConst(varp->fileline(), AstConst::WidthedValue(),
|
||||
storedWidth, value));
|
||||
AstNodeIf* ifp = new AstIf(varp->fileline(), newp,
|
||||
new AstCStmt(varp->fileline(),
|
||||
"Verilated::overWidthError(\""+varp->prettyName()+"\");"));
|
||||
AstNodeIf* ifp = new AstIf(
|
||||
varp->fileline(), newp,
|
||||
new AstCStmt(varp->fileline(), "Verilated::overWidthError(\""
|
||||
+ varp->prettyName() + "\");"));
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
newp = ifp;
|
||||
funcp->addStmtsp(newp);
|
||||
|
|
@ -142,10 +140,10 @@ void V3CCtors::evalAsserts() {
|
|||
}
|
||||
|
||||
void V3CCtors::cctorsAll() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
evalAsserts();
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp();
|
||||
modp; modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
// Process each module in turn
|
||||
AstCFunc* varResetFuncp;
|
||||
{
|
||||
|
|
@ -158,8 +156,7 @@ void V3CCtors::cctorsAll() {
|
|||
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(np, Var)) {
|
||||
if (!varp->isIfaceParent() && !varp->isIfaceRef()
|
||||
&& !varp->noReset()) {
|
||||
if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) {
|
||||
var_reset.add(new AstCReset(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true)));
|
||||
}
|
||||
|
|
@ -168,10 +165,8 @@ void V3CCtors::cctorsAll() {
|
|||
}
|
||||
if (v3Global.opt.coverage()) {
|
||||
V3CCtorsVisitor configure_coverage(
|
||||
modp, "_configure_coverage",
|
||||
EmitCBaseVisitor::symClassVar() + ", bool first",
|
||||
"vlSymsp, first",
|
||||
"if (false && vlSymsp && first) {} // Prevent unused\n");
|
||||
modp, "_configure_coverage", EmitCBaseVisitor::symClassVar() + ", bool first",
|
||||
"vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n");
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) {
|
||||
AstNode* backp = coverp->backp();
|
||||
|
|
|
|||
218
src/V3Case.cpp
218
src/V3Case.cpp
|
|
@ -45,9 +45,9 @@
|
|||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
|
||||
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
|
||||
#define CASE_BARF 999999 // Magic width when non-constant
|
||||
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
|
||||
#define CASE_OVERLAP_WIDTH 16 // Maximum width we can check for overlaps in
|
||||
#define CASE_BARF 999999 // Magic width when non-constant
|
||||
#define CASE_ENCODER_GROUP_DEPTH 8 // Levels of priority to be ORed together in top IF tree
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -64,8 +64,8 @@ private:
|
|||
}
|
||||
// Detect multiple defaults
|
||||
bool hitDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (itemp->isDefault()) {
|
||||
if (hitDefault) {
|
||||
itemp->v3error("Multiple default statements in case statement.");
|
||||
|
|
@ -78,8 +78,8 @@ private:
|
|||
{
|
||||
m_caseExprp = nodep;
|
||||
iterate(nodep->exprp());
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
iterateAndNextNull(itemp->condsp());
|
||||
}
|
||||
m_caseExprp = NULL;
|
||||
|
|
@ -89,16 +89,20 @@ private:
|
|||
// See also neverItem
|
||||
if (m_caseExprp && nodep->num().isFourState()) {
|
||||
if (VN_IS(m_caseExprp, GenCase)) {
|
||||
nodep->v3error("Use of x/? constant in generate case statement, (no such thing as 'generate casez')");
|
||||
nodep->v3error("Use of x/? constant in generate case statement, "
|
||||
"(no such thing as 'generate casez')");
|
||||
} else if (VN_IS(m_caseExprp, Case) && VN_CAST(m_caseExprp, Case)->casex()) {
|
||||
// Don't sweat it, we already complained about casex in general
|
||||
} else if (VN_IS(m_caseExprp, Case) && (VN_CAST(m_caseExprp, Case)->casez()
|
||||
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
|
||||
} else if (VN_IS(m_caseExprp, Case)
|
||||
&& (VN_CAST(m_caseExprp, Case)->casez()
|
||||
|| VN_CAST(m_caseExprp, Case)->caseInside())) {
|
||||
if (nodep->num().isUnknown()) {
|
||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, (perhaps intended ?/z in constant)");
|
||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, "
|
||||
"(perhaps intended ?/z in constant)");
|
||||
}
|
||||
} else {
|
||||
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, (perhaps intended casex/casez)");
|
||||
nodep->v3warn(CASEWITHX, "Use of x/? constant in case statement, "
|
||||
"(perhaps intended casex/casez)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -121,17 +125,18 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared each Case
|
||||
// AstIf::user3() -> bool. Set true to indicate clone not needed
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
VDouble0 m_statCaseFast; // Statistic tracking
|
||||
VDouble0 m_statCaseSlow; // Statistic tracking
|
||||
|
||||
// Per-CASE
|
||||
int m_caseWidth; // Width of valueItems
|
||||
int m_caseItems; // Number of caseItem unique values
|
||||
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
AstNode* m_valueItem[1<<CASE_OVERLAP_WIDTH]; // For each possible value, the case branch we need
|
||||
int m_caseWidth; // Width of valueItems
|
||||
int m_caseItems; // Number of caseItem unique values
|
||||
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
// For each possible value, the case branch we need
|
||||
AstNode* m_valueItem[1 << CASE_OVERLAP_WIDTH];
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -141,9 +146,9 @@ private:
|
|||
bool opaque = false;
|
||||
m_caseItems = 0;
|
||||
m_caseNoOverlapsAllCovered = true;
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
if (icondp->width() > width) width = icondp->width();
|
||||
if (icondp->isDouble()) opaque = true;
|
||||
if (!VN_IS(icondp, Const)) width = CASE_BARF; // Can't parse; not a constant
|
||||
|
|
@ -151,38 +156,39 @@ private:
|
|||
}
|
||||
}
|
||||
m_caseWidth = width;
|
||||
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
|
||||
if (width == 0 || width > CASE_OVERLAP_WIDTH || opaque) {
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
return false; // Too wide for analysis
|
||||
}
|
||||
UINFO(8,"Simple case statement: "<<nodep<<endl);
|
||||
UINFO(8, "Simple case statement: " << nodep << endl);
|
||||
// Zero list of items for each value
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) m_valueItem[i] = NULL;
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) m_valueItem[i] = NULL;
|
||||
// Now pick up the values for each assignment
|
||||
// We can cheat and use uint32_t's because we only support narrow case's
|
||||
bool bitched = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
//if (debug()>=9) icondp->dumpTree(cout, " caseitem: ");
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
// if (debug() >= 9) icondp->dumpTree(cout, " caseitem: ");
|
||||
AstConst* iconstp = VN_CAST(icondp, Const);
|
||||
UASSERT_OBJ(iconstp, nodep, "above 'can't parse' should have caught this");
|
||||
if (neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
} else {
|
||||
V3Number nummask (itemp, iconstp->width());
|
||||
V3Number nummask(itemp, iconstp->width());
|
||||
nummask.opBitsNonX(iconstp->num());
|
||||
uint32_t mask = nummask.toUInt();
|
||||
V3Number numval (itemp, iconstp->width());
|
||||
V3Number numval(itemp, iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
uint32_t val = numval.toUInt();
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
|
||||
uint32_t val = numval.toUInt();
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
if ((i & mask) == val) {
|
||||
if (!m_valueItem[i]) {
|
||||
m_valueItem[i] = itemp;
|
||||
} else if (!itemp->ignoreOverlap() && !bitched) {
|
||||
icondp->v3warn(CASEOVERLAP, "Case values overlap (example pattern 0x"
|
||||
<<std::hex<<i<<")");
|
||||
icondp->v3warn(CASEOVERLAP,
|
||||
"Case values overlap (example pattern 0x"
|
||||
<< std::hex << i << ")");
|
||||
bitched = true;
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
}
|
||||
|
|
@ -192,15 +198,16 @@ private:
|
|||
}
|
||||
// Defaults were moved to last in the caseitem list by V3LinkDot
|
||||
if (itemp->isDefault()) { // Case statement's default... Fill the table
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
if (!m_valueItem[i]) m_valueItem[i] = itemp;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
if (!m_valueItem[i]) {
|
||||
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered (example pattern 0x"
|
||||
<<std::hex<<i<<")");
|
||||
nodep->v3warn(CASEINCOMPLETE, "Case values incompletely covered "
|
||||
"(example pattern 0x"
|
||||
<< std::hex << i << ")");
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -213,24 +220,23 @@ private:
|
|||
|
||||
// Convert valueItem from AstCaseItem* to the expression
|
||||
// Not done earlier, as we may now have a NULL because it's just a ";" NOP branch
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
m_valueItem[i] = VN_CAST(m_valueItem[i], CaseItem)->bodysp();
|
||||
}
|
||||
return true; // All is fine
|
||||
}
|
||||
|
||||
AstNode* replaceCaseFastRecurse(AstNode* cexprp, int msb, uint32_t upperValue) {
|
||||
if (msb<0) {
|
||||
if (msb < 0) {
|
||||
// There's no space for a IF. We know upperValue is thus down to a specific
|
||||
// exact value, so just return the tree value
|
||||
// Note can't clone here, as we're going to check for equivalence above
|
||||
return m_valueItem[upperValue];
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Make left and right subtrees
|
||||
// cexpr[msb:lsb] == 1
|
||||
AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | 0);
|
||||
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb-1, upperValue | (1UL<<msb));
|
||||
AstNode* tree0p = replaceCaseFastRecurse(cexprp, msb - 1, upperValue | 0);
|
||||
AstNode* tree1p = replaceCaseFastRecurse(cexprp, msb - 1, upperValue | (1UL << msb));
|
||||
|
||||
if (tree0p == tree1p) {
|
||||
// Same logic on both sides, so we can just return one of 'em
|
||||
|
|
@ -238,11 +244,12 @@ private:
|
|||
}
|
||||
// We could have a "checkerboard" with A B A B, we can use the same IF on both edges
|
||||
bool same = true;
|
||||
for (uint32_t a=upperValue,
|
||||
b=(upperValue|(1UL<<msb));
|
||||
a < (upperValue|(1UL<<msb));
|
||||
a++, b++) {
|
||||
if (m_valueItem[a] != m_valueItem[b]) { same = false; break; }
|
||||
for (uint32_t a = upperValue, b = (upperValue | (1UL << msb));
|
||||
a < (upperValue | (1UL << msb)); a++, b++) {
|
||||
if (m_valueItem[a] != m_valueItem[b]) {
|
||||
same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (same) {
|
||||
VL_DO_DANGLING(tree1p->deleteTree(), tree1p);
|
||||
|
|
@ -256,14 +263,12 @@ private:
|
|||
if (tree1p && !tree1p->user3()) tree1p = tree1p->cloneTree(true);
|
||||
|
||||
// Alternate scheme if we ever do multiple bits at a time:
|
||||
//V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
|
||||
//AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
|
||||
// V3Number nummask (cexprp, cexprp->width(), (1UL<<msb));
|
||||
// AstNode* and1p = new AstAnd(cexprp->fileline(), cexprp->cloneTree(false),
|
||||
// new AstConst(cexprp->fileline(), nummask));
|
||||
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false),
|
||||
msb, 1);
|
||||
AstNode* eqp = new AstNeq(cexprp->fileline(),
|
||||
new AstConst(cexprp->fileline(), 0),
|
||||
and1p);
|
||||
AstNode* and1p = new AstSel(cexprp->fileline(), cexprp->cloneTree(false), msb, 1);
|
||||
AstNode* eqp
|
||||
= new AstNeq(cexprp->fileline(), new AstConst(cexprp->fileline(), 0), and1p);
|
||||
AstIf* ifp = new AstIf(cexprp->fileline(), eqp, tree1p, tree0p);
|
||||
ifp->user3(1); // So we don't bother to clone it
|
||||
return ifp;
|
||||
|
|
@ -276,10 +281,10 @@ private:
|
|||
// IF(msb-1, 01, 00))
|
||||
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
||||
|
||||
if (debug()>=9) {
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); ++i) {
|
||||
if (debug() >= 9) {
|
||||
for (uint32_t i = 0; i < (1UL << m_caseWidth); ++i) {
|
||||
if (AstNode* itemp = m_valueItem[i]) {
|
||||
UINFO(9,"Value "<<std::hex<<i<<" "<<itemp<<endl);
|
||||
UINFO(9, "Value " << std::hex << i << " " << itemp << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,15 +293,18 @@ private:
|
|||
replaceCaseParallel(nodep, m_caseNoOverlapsAllCovered);
|
||||
|
||||
AstNode::user3ClearTree();
|
||||
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth-1, 0UL);
|
||||
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth - 1, 0UL);
|
||||
// Case expressions can't be linked twice, so clone them
|
||||
if (ifrootp && !ifrootp->user3()) ifrootp = ifrootp->cloneTree(true);
|
||||
|
||||
if (ifrootp) nodep->replaceWith(ifrootp);
|
||||
else nodep->unlinkFrBack();
|
||||
if (ifrootp) {
|
||||
nodep->replaceWith(ifrootp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
VL_DO_DANGLING(cexprp->deleteTree(), cexprp);
|
||||
if (debug()>=9) ifrootp->dumpTree(cout, " _simp: ");
|
||||
if (debug() >= 9) ifrootp->dumpTree(cout, " _simp: ");
|
||||
}
|
||||
|
||||
void replaceCaseComplicated(AstCase* nodep) {
|
||||
|
|
@ -307,9 +315,10 @@ private:
|
|||
AstNode* cexprp = nodep->exprp()->unlinkFrBack();
|
||||
// We'll do this in two stages. First stage, convert the conditions to
|
||||
// the appropriate IF AND terms.
|
||||
if (debug()>=9) nodep->dumpTree(cout, " _comp_IN: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_IN: ");
|
||||
bool hadDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->condsp()) {
|
||||
// Default clause. Just make true, we'll optimize it away later
|
||||
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
|
||||
|
|
@ -318,7 +327,7 @@ private:
|
|||
// Expressioned clause
|
||||
AstNode* icondNextp = NULL;
|
||||
AstNode* ifexprp = NULL; // If expression to test
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondNextp) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondNextp) {
|
||||
icondNextp = icondp->nextp();
|
||||
icondp->unlinkFrBack();
|
||||
|
||||
|
|
@ -326,7 +335,8 @@ private:
|
|||
AstConst* iconstp = VN_CAST(icondp, Const);
|
||||
if (iconstp && neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp);
|
||||
VL_DANGLING(iconstp);
|
||||
// For simplicity, make expression that is not equal, and let later
|
||||
// optimizations remove it
|
||||
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
|
||||
|
|
@ -336,16 +346,17 @@ private:
|
|||
irangep->rhsp()->unlinkFrBack());
|
||||
} else if (iconstp && iconstp->num().isFourState()
|
||||
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
|
||||
V3Number nummask (itemp, iconstp->width());
|
||||
V3Number nummask(itemp, iconstp->width());
|
||||
nummask.opBitsNonX(iconstp->num());
|
||||
V3Number numval (itemp, iconstp->width());
|
||||
V3Number numval(itemp, iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* and2p = new AstAnd(itemp->fileline(),
|
||||
new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp); VL_DANGLING(iconstp);
|
||||
VL_DO_DANGLING(icondp->deleteTree(), icondp);
|
||||
VL_DANGLING(iconstp);
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
|
||||
|
|
@ -367,11 +378,10 @@ private:
|
|||
if (!hadDefault) {
|
||||
// If there was no default, add a empty one, this greatly simplifies below code
|
||||
// and constant propagation will just eliminate it for us later.
|
||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()),
|
||||
NULL));
|
||||
nodep->addItemsp(new AstCaseItem(
|
||||
nodep->fileline(), new AstConst(nodep->fileline(), AstConst::LogicTrue()), NULL));
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout, " _comp_COND: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: ");
|
||||
// Now build the IF statement tree
|
||||
// The tree can be quite huge. Pull ever group of 8 out, and make a OR tree.
|
||||
// This reduces the depth for the bottom elements, at the cost of
|
||||
|
|
@ -382,46 +392,56 @@ private:
|
|||
AstNode* grouprootp = NULL;
|
||||
AstIf* groupnextp = NULL;
|
||||
AstIf* itemnextp = NULL;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
AstNode* istmtsp = itemp->bodysp(); // Maybe null -- no action.
|
||||
if (istmtsp) istmtsp->unlinkFrBackWithNext();
|
||||
// Expressioned clause
|
||||
AstNode* ifexprp = itemp->condsp()->unlinkFrBack();
|
||||
{ // Prepare for next group
|
||||
{ // Prepare for next group
|
||||
if (++depth > CASE_ENCODER_GROUP_DEPTH) depth = 1;
|
||||
if (depth == 1) { // First group or starting new group
|
||||
itemnextp = NULL;
|
||||
AstIf* newp = new AstIf(itemp->fileline(),
|
||||
ifexprp->cloneTree(true), NULL, NULL);
|
||||
if (groupnextp) groupnextp->addElsesp(newp);
|
||||
else grouprootp = newp;
|
||||
AstIf* newp
|
||||
= new AstIf(itemp->fileline(), ifexprp->cloneTree(true), NULL, NULL);
|
||||
if (groupnextp) {
|
||||
groupnextp->addElsesp(newp);
|
||||
} else {
|
||||
grouprootp = newp;
|
||||
}
|
||||
groupnextp = newp;
|
||||
} else { // Continue group, modify if condition to OR in this new condition
|
||||
AstNode* condp = groupnextp->condp()->unlinkFrBack();
|
||||
groupnextp->condp(new AstOr(ifexprp->fileline(),
|
||||
condp,
|
||||
ifexprp->cloneTree(true)));
|
||||
groupnextp->condp(
|
||||
new AstOr(ifexprp->fileline(), condp, ifexprp->cloneTree(true)));
|
||||
}
|
||||
}
|
||||
{ // Make the new lower IF and attach in the tree
|
||||
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
|
||||
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
|
||||
{ // Make the new lower IF and attach in the tree
|
||||
AstNode* itemexprp = ifexprp;
|
||||
VL_DANGLING(ifexprp);
|
||||
if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition
|
||||
VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp);
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
|
||||
if (itemnextp) itemnextp->addElsesp(newp);
|
||||
else groupnextp->addIfsp(newp); // First in a new group
|
||||
if (itemnextp) {
|
||||
itemnextp->addElsesp(newp);
|
||||
} else {
|
||||
groupnextp->addIfsp(newp); // First in a new group
|
||||
}
|
||||
itemnextp = newp;
|
||||
}
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout, " _comp_TREE: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " _comp_TREE: ");
|
||||
// Handle any assertions
|
||||
replaceCaseParallel(nodep, false);
|
||||
// Replace the CASE... with IF...
|
||||
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
|
||||
if (grouprootp) nodep->replaceWith(grouprootp);
|
||||
else nodep->unlinkFrBack();
|
||||
if (debug() >= 9 && grouprootp) grouprootp->dumpTree(cout, " _new: ");
|
||||
if (grouprootp) {
|
||||
nodep->replaceWith(grouprootp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
|
|
@ -451,7 +471,7 @@ private:
|
|||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
V3Case::caseLint(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (debug()>=9) nodep->dumpTree(cout, " case_old: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " case_old: ");
|
||||
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
|
||||
// It's a simple priority encoder or complete statement
|
||||
// we can make a tree of statements to avoid extra comparisons
|
||||
|
|
@ -471,9 +491,7 @@ public:
|
|||
m_caseWidth = 0;
|
||||
m_caseItems = 0;
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
for (uint32_t i=0; i<(1UL<<CASE_OVERLAP_WIDTH); ++i) {
|
||||
m_valueItem[i] = NULL;
|
||||
}
|
||||
for (uint32_t i = 0; i < (1UL << CASE_OVERLAP_WIDTH); ++i) m_valueItem[i] = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CaseVisitor() {
|
||||
|
|
@ -486,13 +504,11 @@ public:
|
|||
// Case class functions
|
||||
|
||||
void V3Case::caseAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
CaseVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CaseVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
void V3Case::caseLint(AstNodeCase* nodep) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
CaseLintVisitor visitor (nodep);
|
||||
UINFO(4, __FUNCTION__ << ": " << endl);
|
||||
CaseLintVisitor visitor(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNode::user() // bool. Indicates node is of known size
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
|
||||
|
|
@ -63,26 +63,30 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void insertCast(AstNode* nodep, int needsize) { // We'll insert ABOVE passed node
|
||||
UINFO(4," NeedCast "<<nodep<<endl);
|
||||
UINFO(4, " NeedCast " << nodep << endl);
|
||||
AstNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
//
|
||||
AstCCast* castp = new AstCCast(nodep->fileline(), nodep, needsize, nodep->widthMin());
|
||||
relinkHandle.relink(castp);
|
||||
//if (debug()>8) castp->dumpTree(cout, "-castins: ");
|
||||
// if (debug() > 8) castp->dumpTree(cout, "-castins: ");
|
||||
//
|
||||
ensureLower32Cast(castp);
|
||||
nodep->user1(1); // Now must be of known size
|
||||
}
|
||||
int castSize(AstNode* nodep) {
|
||||
if (nodep->isQuad()) return VL_QUADSIZE;
|
||||
else if (nodep->width() <= 8) return 8;
|
||||
else if (nodep->width() <= 16) return 16;
|
||||
else return VL_IDATASIZE;
|
||||
if (nodep->isQuad()) {
|
||||
return VL_QUADSIZE;
|
||||
} else if (nodep->width() <= 8) {
|
||||
return 8;
|
||||
} else if (nodep->width() <= 16) {
|
||||
return 16;
|
||||
} else {
|
||||
return VL_IDATASIZE;
|
||||
}
|
||||
}
|
||||
void ensureCast(AstNode* nodep) {
|
||||
if (castSize(nodep->backp()) != castSize(nodep)
|
||||
|| !nodep->user1()) {
|
||||
if (castSize(nodep->backp()) != castSize(nodep) || !nodep->user1()) {
|
||||
insertCast(nodep, castSize(nodep->backp()));
|
||||
}
|
||||
}
|
||||
|
|
@ -91,8 +95,7 @@ private:
|
|||
// really needs to be CAST(uint64(CAST(uint32(x))).
|
||||
// Otherwise a (uint64)(a>b) would return wrong value, as
|
||||
// less than has nondeterministic signedness.
|
||||
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
|
||||
&& !VN_IS(nodep->lhsp(), CCast)) {
|
||||
if (nodep->isQuad() && !nodep->lhsp()->isQuad() && !VN_IS(nodep->lhsp(), CCast)) {
|
||||
insertCast(nodep->lhsp(), VL_IDATASIZE);
|
||||
}
|
||||
}
|
||||
|
|
@ -114,16 +117,13 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1()
|
||||
| nodep->rhsp()->user1());
|
||||
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1()
|
||||
| nodep->rhsp()->user1()
|
||||
| nodep->thsp()->user1());
|
||||
nodep->user1(nodep->lhsp()->user1() | nodep->rhsp()->user1() | nodep->thsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) ensureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) ensureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) ensureCast(nodep->thsp());
|
||||
|
|
@ -136,7 +136,7 @@ private:
|
|||
virtual void visit(AstNegate* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->lhsp()->widthMin()==1) {
|
||||
if (nodep->lhsp()->widthMin() == 1) {
|
||||
// We want to avoid a GCC "converting of negative value" warning
|
||||
// from our expansion of
|
||||
// out = {32{a<b}} => out = - (a<b)
|
||||
|
|
@ -146,11 +146,8 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->lvalue()
|
||||
&& !VN_IS(nodep->backp(), CCast)
|
||||
&& VN_IS(nodep->backp(), NodeMath)
|
||||
&& !VN_IS(nodep->backp(), ArraySel)
|
||||
&& nodep->backp()->width()
|
||||
if (!nodep->lvalue() && !VN_IS(nodep->backp(), CCast) && VN_IS(nodep->backp(), NodeMath)
|
||||
&& !VN_IS(nodep->backp(), ArraySel) && nodep->backp()->width()
|
||||
&& castSize(nodep) != castSize(nodep->varp())) {
|
||||
// Cast vars to IData first, else below has upper bits wrongly set
|
||||
// CData x=3; out = (QData)(x<<30);
|
||||
|
|
@ -187,9 +184,7 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CastVisitor(AstNetlist* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~CastVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -197,9 +192,7 @@ public:
|
|||
// Cast class functions
|
||||
|
||||
void V3Cast::castAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
CastVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CastVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
368
src/V3Cdc.cpp
368
src/V3Cdc.cpp
|
|
@ -40,7 +40,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
||||
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
||||
|
||||
//######################################################################
|
||||
|
||||
|
|
@ -53,18 +53,23 @@ public:
|
|||
// Graph support classes
|
||||
|
||||
class CdcEitherVertex : public V3GraphVertex {
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstSenTree* m_srcDomainp;
|
||||
AstSenTree* m_dstDomainp;
|
||||
bool m_srcDomainSet:1;
|
||||
bool m_dstDomainSet:1;
|
||||
bool m_asyncPath:1;
|
||||
bool m_srcDomainSet : 1;
|
||||
bool m_dstDomainSet : 1;
|
||||
bool m_asyncPath : 1;
|
||||
|
||||
public:
|
||||
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
|
||||
: V3GraphVertex(graphp), m_scopep(scopep), m_nodep(nodep)
|
||||
, m_srcDomainp(NULL), m_dstDomainp(NULL)
|
||||
, m_srcDomainSet(false), m_dstDomainSet(false)
|
||||
: V3GraphVertex(graphp)
|
||||
, m_scopep(scopep)
|
||||
, m_nodep(nodep)
|
||||
, m_srcDomainp(NULL)
|
||||
, m_dstDomainp(NULL)
|
||||
, m_srcDomainSet(false)
|
||||
, m_dstDomainSet(false)
|
||||
, m_asyncPath(false) {}
|
||||
virtual ~CdcEitherVertex() {}
|
||||
// ACCESSORS
|
||||
|
|
@ -85,18 +90,22 @@ public:
|
|||
|
||||
class CdcVarVertex : public CdcEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
int m_cntAsyncRst;
|
||||
bool m_fromFlop;
|
||||
int m_cntAsyncRst;
|
||||
bool m_fromFlop;
|
||||
|
||||
public:
|
||||
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: CdcEitherVertex(graphp, scopep, varScp)
|
||||
, m_varScp(varScp), m_cntAsyncRst(0), m_fromFlop(false) {}
|
||||
, m_varScp(varScp)
|
||||
, m_cntAsyncRst(0)
|
||||
, m_fromFlop(false) {}
|
||||
virtual ~CdcVarVertex() {}
|
||||
// ACCESSORS
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const { return (cvtToHex(m_varScp)+" "+varScp()->name()); }
|
||||
virtual string name() const { return (cvtToHex(m_varScp) + " " + varScp()->name()); }
|
||||
virtual string dotColor() const {
|
||||
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; }
|
||||
return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue";
|
||||
}
|
||||
int cntAsyncRst() const { return m_cntAsyncRst; }
|
||||
void cntAsyncRst(int flag) { m_cntAsyncRst = flag; }
|
||||
bool fromFlop() const { return m_fromFlop; }
|
||||
|
|
@ -104,19 +113,26 @@ public:
|
|||
};
|
||||
|
||||
class CdcLogicVertex : public CdcEitherVertex {
|
||||
bool m_hazard:1;
|
||||
bool m_isFlop:1;
|
||||
bool m_hazard : 1;
|
||||
bool m_isFlop : 1;
|
||||
|
||||
public:
|
||||
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
|
||||
: CdcEitherVertex(graphp, scopep, nodep)
|
||||
, m_hazard(false), m_isFlop(false)
|
||||
{ srcDomainp(sensenodep); dstDomainp(sensenodep); }
|
||||
, m_hazard(false)
|
||||
, m_isFlop(false) {
|
||||
srcDomainp(sensenodep);
|
||||
dstDomainp(sensenodep);
|
||||
}
|
||||
virtual ~CdcLogicVertex() {}
|
||||
// ACCESSORS
|
||||
virtual string name() const { return (cvtToHex(nodep())+"@"+scopep()->prettyName()); }
|
||||
virtual string name() const { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); }
|
||||
virtual string dotColor() const { return hazard() ? "black" : "yellow"; }
|
||||
bool hazard() const { return m_hazard; }
|
||||
void setHazard(AstNode* nodep) { m_hazard = true; nodep->user3(true); }
|
||||
void setHazard(AstNode* nodep) {
|
||||
m_hazard = true;
|
||||
nodep->user3(true);
|
||||
}
|
||||
void clearHazard() { m_hazard = false; }
|
||||
bool isFlop() const { return m_isFlop; }
|
||||
void isFlop(bool flag) { m_isFlop = flag; }
|
||||
|
|
@ -127,16 +143,19 @@ public:
|
|||
class CdcDumpVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// Entire netlist:
|
||||
// {statement}Node::user3 -> bool, indicating not hazard
|
||||
std::ofstream* m_ofp; // Output file
|
||||
string m_prefix;
|
||||
string m_prefix;
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
*m_ofp<<m_prefix;
|
||||
if (nodep->user3()) *m_ofp<<" %%";
|
||||
else *m_ofp<<" ";
|
||||
*m_ofp<<nodep->prettyTypeName()<<" "<<endl;
|
||||
*m_ofp << m_prefix;
|
||||
if (nodep->user3()) {
|
||||
*m_ofp << " %%";
|
||||
} else {
|
||||
*m_ofp << " ";
|
||||
}
|
||||
*m_ofp << nodep->prettyTypeName() << " " << endl;
|
||||
string lastPrefix = m_prefix;
|
||||
m_prefix = lastPrefix + "1:";
|
||||
iterateAndNextNull(nodep->op1p());
|
||||
|
|
@ -163,19 +182,20 @@ public:
|
|||
|
||||
class CdcWidthVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
int m_maxLineno;
|
||||
size_t m_maxFilenameLen;
|
||||
int m_maxLineno;
|
||||
size_t m_maxFilenameLen;
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Keeping line+filename lengths separate is much faster than calling ascii().length()
|
||||
if (nodep->fileline()->lineno() >= m_maxLineno) {
|
||||
m_maxLineno = nodep->fileline()->lineno()+1;
|
||||
m_maxLineno = nodep->fileline()->lineno() + 1;
|
||||
}
|
||||
if (nodep->fileline()->filename().length() >= m_maxFilenameLen) {
|
||||
m_maxFilenameLen = nodep->fileline()->filename().length()+1;
|
||||
m_maxFilenameLen = nodep->fileline()->filename().length() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CdcWidthVisitor(AstNode* nodep) {
|
||||
|
|
@ -201,32 +221,32 @@ public:
|
|||
class CdcVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// Entire netlist:
|
||||
// AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet
|
||||
// AstVarScope::user2 -> bool Used in sensitivity list
|
||||
// {statement}Node::user1p -> CdcLogicVertex* for this statement
|
||||
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
|
||||
AstScope* m_scopep; // Current scope being processed
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstSenTree* m_domainp; // Current sentree
|
||||
bool m_inDly; // In delayed assign
|
||||
int m_inSenItem; // Number of senitems
|
||||
string m_ofFilename; // Output filename
|
||||
std::ofstream* m_ofp; // Output file
|
||||
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth; // Characters in longest fileline
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
|
||||
AstScope* m_scopep; // Current scope being processed
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstSenTree* m_domainp; // Current sentree
|
||||
bool m_inDly; // In delayed assign
|
||||
int m_inSenItem; // Number of senitems
|
||||
string m_ofFilename; // Output filename
|
||||
std::ofstream* m_ofp; // Output file
|
||||
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth; // Characters in longest fileline
|
||||
|
||||
// METHODS
|
||||
void iterateNewStmt(AstNode* nodep) {
|
||||
if (m_scopep) {
|
||||
UINFO(4," STMT "<<nodep<<endl);
|
||||
UINFO(4, " STMT " << nodep << endl);
|
||||
m_logicVertexp = new CdcLogicVertex(&m_graph, m_scopep, nodep, m_domainp);
|
||||
if (m_domainp && m_domainp->hasClocked()) { // To/from a flop
|
||||
m_logicVertexp->isFlop(true);
|
||||
|
|
@ -238,7 +258,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_logicVertexp = NULL;
|
||||
|
||||
if (0 && debug()>=9) {
|
||||
if (0 && debug() >= 9) {
|
||||
UINFO(9, "Trace Logic:\n");
|
||||
nodep->dumpTree(cout, "-log1: ");
|
||||
}
|
||||
|
|
@ -248,15 +268,15 @@ private:
|
|||
CdcVarVertex* makeVarVertex(AstVarScope* varscp) {
|
||||
CdcVarVertex* vertexp = reinterpret_cast<CdcVarVertex*>(varscp->user1p());
|
||||
if (!vertexp) {
|
||||
UINFO(6,"New vertex "<<varscp<<endl);
|
||||
UINFO(6, "New vertex " << varscp << endl);
|
||||
vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp);
|
||||
varscp->user1p(vertexp);
|
||||
if (varscp->varp()->isUsedClock()) {}
|
||||
if (varscp->varp()->isPrimaryIO()) {
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are now
|
||||
// This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(),
|
||||
varscp->varp(), NULL);
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are
|
||||
// now This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* ioVertexp
|
||||
= new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
|
||||
if (varscp->varp()->isWritable()) {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
} else {
|
||||
|
|
@ -266,10 +286,10 @@ private:
|
|||
}
|
||||
if (m_inSenItem) {
|
||||
varscp->user2(true); // It's like a clock...
|
||||
// TODO: In the future we could mark it here and do normal clock tree glitch checks also
|
||||
// TODO: In the future mark it here and do normal clock tree glitch checks also
|
||||
} else if (varscp->user2()) { // It was detected in a sensitivity list earlier
|
||||
// And now it's used as logic. So must be a reset.
|
||||
vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1);
|
||||
vertexp->cntAsyncRst(vertexp->cntAsyncRst() + 1);
|
||||
}
|
||||
return vertexp;
|
||||
}
|
||||
|
|
@ -279,9 +299,9 @@ private:
|
|||
nodep->v3warnCode(code, msg);
|
||||
if (!told_file) {
|
||||
told_file = 1;
|
||||
std::cerr<<V3Error::msgPrefix()<<" See details in "<<m_ofFilename<<endl;
|
||||
std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl;
|
||||
}
|
||||
*m_ofp<<"%Warning-"<<code.ascii()<<": "<<nodep->fileline()<<" "<<msg<<endl;
|
||||
*m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl;
|
||||
}
|
||||
|
||||
void setNodeHazard(AstNode* nodep) {
|
||||
|
|
@ -291,28 +311,34 @@ private:
|
|||
// an issue until we find a hitting flop.
|
||||
// Furthermore, a module like a "Or" module would only get flagged
|
||||
// once, even though the signals feeding it are radically different.
|
||||
if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though)
|
||||
if (!m_domainp || m_domainp->hasCombo()) {
|
||||
// Source flop logic in a posedge block is OK for reset (not async though)
|
||||
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
|
||||
UINFO(8,"Set hazard "<<nodep<<endl);
|
||||
UINFO(8, "Set hazard " << nodep << endl);
|
||||
m_logicVertexp->setHazard(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string spaces(int level) { string out; while (level--) out += " "; return out; } // LCOV_EXCL_LINE
|
||||
string spaces(int level) {
|
||||
string out;
|
||||
while (level--) out += " ";
|
||||
return out;
|
||||
} // LCOV_EXCL_LINE
|
||||
|
||||
string pad(unsigned column, const string& in) {
|
||||
string out = in;
|
||||
while (out.length()<column) out += ' ';
|
||||
while (out.length() < column) out += ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
void analyze() {
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
//if (debug()>6) m_graph.dump();
|
||||
if (debug()>6) m_graph.dumpDotFilePrefixed("cdc_pre");
|
||||
UINFO(3, __FUNCTION__ << ": " << endl);
|
||||
// if (debug() > 6) m_graph.dump();
|
||||
if (debug() > 6) m_graph.dumpDotFilePrefixed("cdc_pre");
|
||||
//
|
||||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
|
||||
m_graph.removeRedundantEdges(
|
||||
&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
|
||||
//
|
||||
m_graph.dumpDotFilePrefixed("cdc_simp");
|
||||
//
|
||||
|
|
@ -321,7 +347,7 @@ private:
|
|||
|
||||
int filelineWidth() {
|
||||
if (!m_filelineWidth) {
|
||||
CdcWidthVisitor visitor (v3Global.rootp());
|
||||
CdcWidthVisitor visitor(v3Global.rootp());
|
||||
m_filelineWidth = visitor.maxWidth();
|
||||
}
|
||||
return m_filelineWidth;
|
||||
|
|
@ -334,15 +360,15 @@ private:
|
|||
// Find all async reset wires, and trace backwards
|
||||
// userClearVertices is very slow, so we use a generation count instead
|
||||
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (vvertexp->cntAsyncRst()) {
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
UINFO(8, " Trace One async: "<<vvertexp<<endl);
|
||||
UINFO(8, " Trace One async: " << vvertexp << endl);
|
||||
// Twice, as we need to detect, then propagate
|
||||
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
|
||||
if (markp) { // Mark is non-NULL if something bad on this path
|
||||
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
|
||||
UINFO(9, " Trace One bad! " << vvertexp << endl);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
traceAsyncRecurse(vvertexp, true);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
|
|
@ -356,11 +382,11 @@ private:
|
|||
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
|
||||
// First pass: Return vertex of any hazardous stuff attached, or NULL if OK
|
||||
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
|
||||
if (vertexp->user()>=m_userGeneration) return NULL; // Processed - prevent loop
|
||||
if (vertexp->user() >= m_userGeneration) return NULL; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
CdcEitherVertex* mark_outp = NULL;
|
||||
UINFO(9," Trace: "<<vertexp<<endl);
|
||||
UINFO(9, " Trace: " << vertexp << endl);
|
||||
|
||||
// Clear out in prep for marking next path
|
||||
if (!mark) vertexp->asyncPath(false);
|
||||
|
|
@ -369,8 +395,7 @@ private:
|
|||
// Any logic considered bad, at the moment, anyhow
|
||||
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
|
||||
// And keep tracing back so the user can understand what's up
|
||||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
if (mark) vvertexp->asyncPath(true);
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryInish()) {
|
||||
|
|
@ -403,62 +428,60 @@ private:
|
|||
|
||||
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
|
||||
AstNode* nodep = vertexp->varScp();
|
||||
*m_ofp<<"\n";
|
||||
*m_ofp<<"\n";
|
||||
*m_ofp << "\n";
|
||||
*m_ofp << "\n";
|
||||
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
if (!eToVertexp) targetp = eToVertexp;
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (vvertexp->isFlop() // IE the target flop that is upsetting us
|
||||
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And this signal feeds an async reset line
|
||||
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line
|
||||
targetp = eToVertexp;
|
||||
//UINFO(9," targetasync "<<targetp->name()<<" "<<" from "<<vertexp->name()<<endl);
|
||||
// UINFO(9," targetasync "<<targetp->name()<<" "<<" from
|
||||
// "<<vertexp->name()<<endl);
|
||||
break;
|
||||
}
|
||||
} // else it might be random logic that's not relevant
|
||||
}
|
||||
//UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
|
||||
// UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
|
||||
warnAndFile(markp->nodep(), V3ErrorCode::CDCRSTLOGIC,
|
||||
"Logic in path that feeds async reset, via signal: "+nodep->prettyNameQ());
|
||||
"Logic in path that feeds async reset, via signal: " + nodep->prettyNameQ());
|
||||
dumpAsyncRecurse(targetp, "", " ", 0);
|
||||
}
|
||||
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix,
|
||||
const string& sep, int level) {
|
||||
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep,
|
||||
int level) {
|
||||
// level=0 is special, indicates to dump destination flop
|
||||
// Return true if printed anything
|
||||
// If mark, also mark the output even if nothing hazardous below
|
||||
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
|
||||
if (vertexp->user() >= m_userGeneration) return false; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
if (!vertexp->asyncPath() && level!=0) return false; // Not part of path
|
||||
if (!vertexp->asyncPath() && level != 0) return false; // Not part of path
|
||||
|
||||
// Other logic in the path
|
||||
string cont = prefix+sep;
|
||||
string cont = prefix + sep;
|
||||
string nextsep = " ";
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level+1)) {
|
||||
nextsep = " | ";
|
||||
}
|
||||
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | ";
|
||||
}
|
||||
|
||||
// Dump single variable/logic block
|
||||
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
|
||||
AstNode* nodep = vertexp->nodep();
|
||||
string front = pad(filelineWidth(), nodep->fileline()->ascii()+":")+" "+prefix+" +- ";
|
||||
string front
|
||||
= pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- ";
|
||||
if (VN_IS(nodep, VarScope)) {
|
||||
*m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
|
||||
}
|
||||
else {
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" +- ", filelineWidth(),
|
||||
*m_ofp << front << "Variable: " << nodep->prettyName() << endl;
|
||||
} else {
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(),
|
||||
vertexp->srcDomainp(), true);
|
||||
if (debug()) {
|
||||
CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: ");
|
||||
}
|
||||
if (debug()) { CdcDumpVisitor visitor(nodep, m_ofp, front + "DBG: "); }
|
||||
}
|
||||
|
||||
nextsep = " | ";
|
||||
if (level) *m_ofp<<V3OutFile::indentSpaces(filelineWidth())<<" "<<prefix<<nextsep<<"\n";
|
||||
if (level)
|
||||
*m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n";
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Now that we've printed a path with this hazard, don't bother to print any more
|
||||
|
|
@ -479,27 +502,27 @@ private:
|
|||
// module. Disabling flattening though makes us consider each
|
||||
// signal in it's own unique clock domain.
|
||||
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
UINFO(3, __FUNCTION__ << ": " << endl);
|
||||
|
||||
// Trace all sources and sinks
|
||||
for (int traceDests=0; traceDests<2; ++traceDests) {
|
||||
UINFO(9, " Trace Direction "<<(traceDests?"dst":"src")<<endl);
|
||||
for (int traceDests = 0; traceDests < 2; ++traceDests) {
|
||||
UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl);
|
||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
UINFO(9, " Trace One edge: "<<vvertexp<<endl);
|
||||
UINFO(9, " Trace One edge: " << vvertexp << endl);
|
||||
edgeDomainRecurse(vvertexp, traceDests, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc_edges.txt";
|
||||
const vl_unique_ptr<std::ofstream> ofp (V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatal("Can't write "<<filename);
|
||||
*ofp<<"Edge Report for "<<v3Global.opt.prefix()<<endl;
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt";
|
||||
const vl_unique_ptr<std::ofstream> ofp(V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatal("Can't write " << filename);
|
||||
*ofp << "Edge Report for " << v3Global.opt.prefix() << endl;
|
||||
|
||||
std::deque<string> report; // Sort output by name
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
{
|
||||
|
|
@ -511,46 +534,50 @@ private:
|
|||
// Module name - doesn't work due to flattening having lost the original
|
||||
// so we assume the modulename matches the filebasename
|
||||
string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
|
||||
os<<" "<<std::setw(20)<<fname;
|
||||
os<<" "<<std::setw(8)<<what;
|
||||
os<<" "<<std::setw(40)<<vvertexp->varScp()->prettyName();
|
||||
os<<" SRC=";
|
||||
if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
|
||||
os<<" DST=";
|
||||
if (vvertexp->dstDomainp()) V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
|
||||
os<<std::setw(0);
|
||||
os<<endl;
|
||||
os << " " << std::setw(20) << fname;
|
||||
os << " " << std::setw(8) << what;
|
||||
os << " " << std::setw(40) << vvertexp->varScp()->prettyName();
|
||||
os << " SRC=";
|
||||
if (vvertexp->srcDomainp()) {
|
||||
V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
|
||||
}
|
||||
os << " DST=";
|
||||
if (vvertexp->dstDomainp()) {
|
||||
V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
|
||||
}
|
||||
os << std::setw(0);
|
||||
os << endl;
|
||||
report.push_back(os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
stable_sort(report.begin(), report.end());
|
||||
for (std::deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
|
||||
for (std::deque<string>::iterator it = report.begin(); it != report.end(); ++it) {
|
||||
*ofp << *it;
|
||||
}
|
||||
}
|
||||
|
||||
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
||||
// Scan back to inputs/outputs, flops, and compute clock domain information
|
||||
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
|
||||
if (vertexp->user()>=m_userGeneration) return; // Mid-Processed - prevent loop
|
||||
UINFO(8, spaces(level) << " Tracein " << vertexp << endl);
|
||||
if (vertexp->user() >= m_userGeneration) return; // Mid-Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
// Variables from flops already are domained
|
||||
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed
|
||||
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) {
|
||||
return;
|
||||
} // Fully computed
|
||||
|
||||
typedef std::set<AstSenTree*> SenSet;
|
||||
SenSet senouts; // List of all sensitivities for new signal
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (vvertexp) {} // Unused
|
||||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
} else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
// If primary I/O, give it domain of the input
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) {
|
||||
senouts.insert(
|
||||
new AstSenTree(varp->fileline(),
|
||||
new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
senouts.insert(new AstSenTree(
|
||||
varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -558,23 +585,24 @@ private:
|
|||
if (traceDests) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = static_cast<CdcEitherVertex*>(edgep->top());
|
||||
edgeDomainRecurse(eToVertexp, traceDests, level+1);
|
||||
edgeDomainRecurse(eToVertexp, traceDests, level + 1);
|
||||
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
|
||||
}
|
||||
} else {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = static_cast<CdcEitherVertex*>(edgep->fromp());
|
||||
edgeDomainRecurse(eFromVertexp, traceDests, level+1);
|
||||
edgeDomainRecurse(eFromVertexp, traceDests, level + 1);
|
||||
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert list of senses into one sense node
|
||||
AstSenTree* senoutp = NULL;
|
||||
bool senedited = false;
|
||||
for (SenSet::iterator it=senouts.begin(); it!=senouts.end(); ++it) {
|
||||
if (!senoutp) senoutp = *it;
|
||||
else {
|
||||
bool senedited = false;
|
||||
for (SenSet::iterator it = senouts.begin(); it != senouts.end(); ++it) {
|
||||
if (!senoutp) {
|
||||
senoutp = *it;
|
||||
} else {
|
||||
if (!senedited) {
|
||||
senedited = true;
|
||||
senoutp = senoutp->cloneTree(true);
|
||||
|
|
@ -583,22 +611,26 @@ private:
|
|||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
if (senedited) {
|
||||
senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree);
|
||||
}
|
||||
if (senedited) { senoutp = VN_CAST(V3Const::constifyExpensiveEdit(senoutp), SenTree); }
|
||||
if (traceDests) {
|
||||
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->dstDomainp(senoutp);
|
||||
if (debug()>=9) {
|
||||
UINFO(9,spaces(level)+" Tracedst "<<vertexp);
|
||||
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
|
||||
if (debug() >= 9) {
|
||||
UINFO(9, spaces(level) + " Tracedst " << vertexp);
|
||||
if (senoutp) {
|
||||
V3EmitV::verilogForTree(senoutp, cout);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->srcDomainp(senoutp);
|
||||
if (debug()>=9) {
|
||||
UINFO(9,spaces(level)+" Tracesrc "<<vertexp);
|
||||
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
|
||||
if (debug() >= 9) {
|
||||
UINFO(9, spaces(level) + " Tracesrc " << vertexp);
|
||||
if (senoutp) {
|
||||
V3EmitV::verilogForTree(senoutp, cout);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -613,7 +645,7 @@ private:
|
|||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -621,10 +653,11 @@ private:
|
|||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4," BLOCK "<<nodep<<endl);
|
||||
UINFO(4, " BLOCK " << nodep << endl);
|
||||
AstNode::user2ClearTree();
|
||||
m_domainp = nodep->sensesp();
|
||||
if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
|
||||
if (!m_domainp || m_domainp->hasCombo()
|
||||
|| m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
m_domainp = NULL;
|
||||
|
|
@ -636,7 +669,7 @@ private:
|
|||
AstVarScope* varscp = nodep->varScopep();
|
||||
UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
CdcVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
UINFO(5, " VARREF to " << varscp << endl);
|
||||
// We use weight of one for normal edges,
|
||||
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
|
||||
// When simplify we'll take the MAX weight
|
||||
|
|
@ -649,10 +682,10 @@ private:
|
|||
}
|
||||
} else {
|
||||
if (varvertexp->cntAsyncRst()) {
|
||||
//UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
// UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, CDC_WEIGHT_ASYNC);
|
||||
} else {
|
||||
//UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
// UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -670,38 +703,24 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
// CDC doesn't care about public variables
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is dealt with as logic
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { iterateNewStmt(nodep); }
|
||||
|
||||
// Math that shouldn't cause us to clear hazard
|
||||
virtual void visit(AstConst*) VL_OVERRIDE {}
|
||||
virtual void visit(AstReplicate* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNot* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstReplicate* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstConcat* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNot* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
if (!VN_IS(nodep->lsbp(), Const)) setNodeHazard(nodep);
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -738,15 +757,16 @@ public:
|
|||
m_filelineWidth = 0;
|
||||
|
||||
// Make report of all signal names and what clock edges they have
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
|
||||
string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt";
|
||||
m_ofp = V3File::new_ofstream(filename);
|
||||
if (m_ofp->fail()) v3fatal("Can't write "<<filename);
|
||||
if (m_ofp->fail()) v3fatal("Can't write " << filename);
|
||||
m_ofFilename = filename;
|
||||
*m_ofp<<"CDC Report for "<<v3Global.opt.prefix()<<endl;
|
||||
*m_ofp<<"Each dump below traces logic from inputs/source flops to destination flop(s).\n";
|
||||
*m_ofp<<"First source logic is listed, then a variable that logic generates,\n";
|
||||
*m_ofp<<"repeating recursively forwards to the destination flop(s).\n";
|
||||
*m_ofp<<"%% Indicates the operator considered potentially hazardous.\n";
|
||||
*m_ofp << "CDC Report for " << v3Global.opt.prefix() << endl;
|
||||
*m_ofp
|
||||
<< "Each dump below traces logic from inputs/source flops to destination flop(s).\n";
|
||||
*m_ofp << "First source logic is listed, then a variable that logic generates,\n";
|
||||
*m_ofp << "repeating recursively forwards to the destination flop(s).\n";
|
||||
*m_ofp << "%% Indicates the operator considered potentially hazardous.\n";
|
||||
|
||||
iterate(nodep);
|
||||
analyze();
|
||||
|
|
@ -766,6 +786,6 @@ public:
|
|||
// Cdc class functions
|
||||
|
||||
void V3Cdc::cdcAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CdcVisitor visitor (nodep);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
CdcVisitor visitor(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,12 +43,12 @@
|
|||
class ChangedState {
|
||||
public:
|
||||
// STATE
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp; // Change function we're building
|
||||
AstCFunc* m_tlChgFuncp; // Top level change function we're building
|
||||
int m_numStmts; // Number of statements added to m_chgFuncp
|
||||
int m_funcNum; // Number of change functions emitted
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp; // Change function we're building
|
||||
AstCFunc* m_tlChgFuncp; // Top level change function we're building
|
||||
int m_numStmts; // Number of statements added to m_chgFuncp
|
||||
int m_funcNum; // Number of change functions emitted
|
||||
|
||||
ChangedState() {
|
||||
m_topModp = NULL;
|
||||
|
|
@ -67,9 +67,9 @@ public:
|
|||
return;
|
||||
}
|
||||
if (!m_chgFuncp || v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||
m_chgFuncp = new AstCFunc(m_scopetopp->fileline(),
|
||||
"_change_request_" + cvtToStr(++m_funcNum),
|
||||
m_scopetopp, "QData");
|
||||
m_chgFuncp
|
||||
= new AstCFunc(m_scopetopp->fileline(), "_change_request_" + cvtToStr(++m_funcNum),
|
||||
m_scopetopp, "QData");
|
||||
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_chgFuncp->symProlog(true);
|
||||
m_chgFuncp->declPrivate(true);
|
||||
|
|
@ -89,9 +89,9 @@ public:
|
|||
// we want and is similar to the logic already in use inside
|
||||
// V3EmitC, however, it also means that verbose logging may
|
||||
// miss to print change detect variables.
|
||||
AstNode* newp = new AstCReturn(m_scopetopp->fileline(),
|
||||
new AstLogOr(m_scopetopp->fileline(), callp,
|
||||
returnp->lhsp()->unlinkFrBack()));
|
||||
AstNode* newp = new AstCReturn(
|
||||
m_scopetopp->fileline(),
|
||||
new AstLogOr(m_scopetopp->fileline(), callp, returnp->lhsp()->unlinkFrBack()));
|
||||
returnp->replaceWith(newp);
|
||||
VL_DO_DANGLING(returnp->deleteTree(), returnp);
|
||||
}
|
||||
|
|
@ -106,57 +106,57 @@ public:
|
|||
class ChangedInsertVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
|
||||
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
|
||||
AstNode* m_varEqnp; // Original var's equation to get var value
|
||||
AstNode* m_newLvEqnp; // New var's equation to read value
|
||||
AstNode* m_newRvEqnp; // New var's equation to set value
|
||||
uint32_t m_detects; // # detects created
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
|
||||
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
|
||||
AstNode* m_varEqnp; // Original var's equation to get var value
|
||||
AstNode* m_newLvEqnp; // New var's equation to read value
|
||||
AstNode* m_newRvEqnp; // New var's equation to set value
|
||||
uint32_t m_detects; // # detects created
|
||||
|
||||
// CONSTANTS
|
||||
enum MiscConsts {
|
||||
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
|
||||
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
|
||||
// Ok to increase this, but may result in much slower model
|
||||
};
|
||||
|
||||
void newChangeDet() {
|
||||
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "
|
||||
<<cvtToStr(DETECTARRAY_MAX_INDEXES)
|
||||
<<" array indexes (probably with UNOPTFLAT warning suppressed): "
|
||||
<<m_vscp->prettyName()<<endl
|
||||
<<m_vscp->warnMore()
|
||||
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased"<<endl);
|
||||
m_vscp->v3warn(E_DETECTARRAY,
|
||||
"Unsupported: Can't detect more than "
|
||||
<< cvtToStr(DETECTARRAY_MAX_INDEXES)
|
||||
<< " array indexes (probably with UNOPTFLAT warning suppressed): "
|
||||
<< m_vscp->prettyName() << endl
|
||||
<< m_vscp->warnMore()
|
||||
<< "... Could recompile with DETECTARRAY_MAX_INDEXES increased"
|
||||
<< endl);
|
||||
return;
|
||||
}
|
||||
m_statep->maybeCreateChgFuncp();
|
||||
|
||||
AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(),
|
||||
m_varEqnp->cloneTree(true),
|
||||
AstChangeDet* changep = new AstChangeDet(m_vscp->fileline(), m_varEqnp->cloneTree(true),
|
||||
m_newRvEqnp->cloneTree(true), false);
|
||||
m_statep->m_chgFuncp->addStmtsp(changep);
|
||||
AstAssign* initp = new AstAssign(m_vscp->fileline(),
|
||||
m_newLvEqnp->cloneTree(true),
|
||||
AstAssign* initp = new AstAssign(m_vscp->fileline(), m_newLvEqnp->cloneTree(true),
|
||||
m_varEqnp->cloneTree(true));
|
||||
m_statep->m_chgFuncp->addFinalsp(initp);
|
||||
EmitCBaseCounterVisitor visitor(initp);
|
||||
m_statep->m_numStmts += visitor.count();
|
||||
}
|
||||
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE { //
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPackArrayDType* nodep) VL_OVERRIDE { //
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstUnpackArrayDType* nodep) VL_OVERRIDE {
|
||||
for (int index=0; index < nodep->elementsConst(); ++index) {
|
||||
for (int index = 0; index < nodep->elementsConst(); ++index) {
|
||||
AstNode* origVEp = m_varEqnp;
|
||||
AstNode* origNLEp = m_newLvEqnp;
|
||||
AstNode* origNREp = m_newRvEqnp;
|
||||
|
||||
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
|
||||
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
|
||||
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
|
||||
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
|
||||
|
||||
|
|
@ -166,7 +166,7 @@ private:
|
|||
m_newLvEqnp->deleteTree();
|
||||
m_newRvEqnp->deleteTree();
|
||||
|
||||
m_varEqnp = origVEp;
|
||||
m_varEqnp = origVEp;
|
||||
m_newLvEqnp = origNLEp;
|
||||
m_newRvEqnp = origNREp;
|
||||
}
|
||||
|
|
@ -177,17 +177,18 @@ private:
|
|||
} else {
|
||||
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-class-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
|
||||
" (probably with UNOPTFLAT warning suppressed): "
|
||||
<<m_vscp->varp()->prettyNameQ());
|
||||
" (probably with UNOPTFLAT warning suppressed): "
|
||||
<< m_vscp->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (debug()) nodep->dumpTree(cout, "-DETECTARRAY-general-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable"
|
||||
" (probably with UNOPTFLAT warning suppressed): "
|
||||
<<m_vscp->varp()->prettyNameQ());
|
||||
" (probably with UNOPTFLAT warning suppressed): "
|
||||
<< m_vscp->varp()->prettyNameQ());
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
|
||||
|
|
@ -196,19 +197,19 @@ public:
|
|||
m_detects = 0;
|
||||
{
|
||||
AstVar* varp = m_vscp->varp();
|
||||
string newvarname = ("__Vchglast__"+m_vscp->scopep()->nameDotless()
|
||||
+"__"+varp->shortName());
|
||||
string newvarname
|
||||
= ("__Vchglast__" + m_vscp->scopep()->nameDotless() + "__" + varp->shortName());
|
||||
// Create: VARREF(_last)
|
||||
// ASSIGN(VARREF(_last), VARREF(var))
|
||||
// ...
|
||||
// CHANGEDET(VARREF(_last), VARREF(var))
|
||||
AstVar* newvarp = new AstVar(varp->fileline(), AstVarType::MODULETEMP,
|
||||
newvarname, varp);
|
||||
AstVar* newvarp
|
||||
= new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
|
||||
m_statep->m_topModp->addStmtp(newvarp);
|
||||
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
|
||||
m_statep->m_scopetopp->addVarp(m_newvscp);
|
||||
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
|
||||
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
|
||||
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
|
||||
}
|
||||
|
|
@ -229,41 +230,38 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstVarScope::user1() -> bool. True indicates processed
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void genChangeDet(AstVarScope* vscp) {
|
||||
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: "<<vscp->prettyNameQ());
|
||||
ChangedInsertVisitor visitor (vscp, m_statep);
|
||||
vscp->v3warn(IMPERFECTSCH, "Imperfect scheduling of variable: " << vscp->prettyNameQ());
|
||||
ChangedInsertVisitor visitor(vscp, m_statep);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
if (nodep->isTop()) {
|
||||
m_statep->m_topModp = nodep;
|
||||
}
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
if (nodep->isTop()) m_statep->m_topModp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," TS "<<nodep<<endl);
|
||||
UINFO(4, " TS " << nodep << endl);
|
||||
// Clearing
|
||||
AstNode::user1ClearTree();
|
||||
// Create the change detection function
|
||||
AstScope* scopep = nodep->scopep();
|
||||
UASSERT_OBJ(scopep, nodep,
|
||||
"No scope found on top level, perhaps you have no statements?");
|
||||
UASSERT_OBJ(scopep, nodep, "No scope found on top level, perhaps you have no statements?");
|
||||
m_statep->m_scopetopp = scopep;
|
||||
|
||||
// Create a wrapper change detection function that calls each change detection function
|
||||
m_statep->m_tlChgFuncp = new AstCFunc(nodep->fileline(),
|
||||
"_change_request", scopep, "QData");
|
||||
m_statep->m_tlChgFuncp
|
||||
= new AstCFunc(nodep->fileline(), "_change_request", scopep, "QData");
|
||||
m_statep->m_tlChgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_statep->m_tlChgFuncp->symProlog(true);
|
||||
m_statep->m_tlChgFuncp->declPrivate(true);
|
||||
|
|
@ -277,10 +275,8 @@ private:
|
|||
}
|
||||
virtual void visit(AstVarScope* nodep) VL_OVERRIDE {
|
||||
if (nodep->isCircular()) {
|
||||
UINFO(8," CIRC "<<nodep<<endl);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
genChangeDet(nodep);
|
||||
}
|
||||
UINFO(8, " CIRC " << nodep << endl);
|
||||
if (!nodep->user1SetOnce()) genChangeDet(nodep);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
|
|
@ -300,10 +296,10 @@ public:
|
|||
// Changed class functions
|
||||
|
||||
void V3Changed::changedAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
ChangedState state;
|
||||
ChangedVisitor visitor (nodep, &state);
|
||||
ChangedVisitor visitor(nodep, &state);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,9 +43,9 @@ private:
|
|||
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
|
||||
// AstNode::user2() -> bool. True indicates widthMin has been propagated
|
||||
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// TYPES
|
||||
enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
||||
|
|
@ -57,10 +57,14 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// Width resetting
|
||||
int cppWidth(AstNode* nodep) {
|
||||
if (nodep->width() <= VL_IDATASIZE) return VL_IDATASIZE;
|
||||
else if (nodep->width() <= VL_QUADSIZE) return VL_QUADSIZE;
|
||||
else return nodep->widthWords() * VL_EDATASIZE;
|
||||
int cppWidth(AstNode* nodep) {
|
||||
if (nodep->width() <= VL_IDATASIZE) {
|
||||
return VL_IDATASIZE;
|
||||
} else if (nodep->width() <= VL_QUADSIZE) {
|
||||
return VL_QUADSIZE;
|
||||
} else {
|
||||
return nodep->widthWords() * VL_EDATASIZE;
|
||||
}
|
||||
}
|
||||
void setCppWidth(AstNode* nodep) {
|
||||
nodep->user2(true); // Don't resize it again
|
||||
|
|
@ -82,7 +86,8 @@ private:
|
|||
}
|
||||
void computeCppWidth(AstNode* nodep) {
|
||||
if (!nodep->user2() && nodep->hasDType()) {
|
||||
if (VN_IS(nodep, Var) || VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|
||||
if (VN_IS(nodep, Var)
|
||||
|| VN_IS(nodep, NodeDType) // Don't want to change variable widths!
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), DynArrayDType)
|
||||
|| VN_IS(nodep->dtypep()->skipRefp(), ClassRefDType)
|
||||
|
|
@ -96,39 +101,33 @@ private:
|
|||
}
|
||||
|
||||
// Store the clean state in the userp on each node
|
||||
void setCleanState(AstNode* nodep, CleanState clean) {
|
||||
nodep->user1(clean);
|
||||
}
|
||||
CleanState getCleanState(AstNode* nodep) {
|
||||
return static_cast<CleanState>(nodep->user1());
|
||||
}
|
||||
void setCleanState(AstNode* nodep, CleanState clean) { nodep->user1(clean); }
|
||||
CleanState getCleanState(AstNode* nodep) { return static_cast<CleanState>(nodep->user1()); }
|
||||
bool isClean(AstNode* nodep) {
|
||||
CleanState clstate = getCleanState(nodep);
|
||||
if (clstate==CS_CLEAN) return true;
|
||||
if (clstate==CS_DIRTY) return false;
|
||||
nodep->v3fatalSrc("Unknown clean state on node: "+nodep->prettyTypeName());
|
||||
if (clstate == CS_CLEAN) return true;
|
||||
if (clstate == CS_DIRTY) return false;
|
||||
nodep->v3fatalSrc("Unknown clean state on node: " + nodep->prettyTypeName());
|
||||
return false;
|
||||
}
|
||||
void setClean(AstNode* nodep, bool isClean) {
|
||||
computeCppWidth(nodep); // Just to be sure it's in widthMin
|
||||
bool wholeUint = (nodep->widthMin() == VL_IDATASIZE
|
||||
|| nodep->widthMin() == VL_QUADSIZE
|
||||
bool wholeUint = (nodep->widthMin() == VL_IDATASIZE || nodep->widthMin() == VL_QUADSIZE
|
||||
|| (nodep->widthMin() % VL_EDATASIZE) == 0);
|
||||
setCleanState(nodep, ((isClean || wholeUint) ? CS_CLEAN : CS_DIRTY));
|
||||
}
|
||||
|
||||
// Operate on nodes
|
||||
void insertClean(AstNode* nodep) { // We'll insert ABOVE passed node
|
||||
UINFO(4," NeedClean "<<nodep<<endl);
|
||||
UINFO(4, " NeedClean " << nodep << endl);
|
||||
AstNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
//
|
||||
computeCppWidth(nodep);
|
||||
V3Number mask (nodep, cppWidth(nodep));
|
||||
V3Number mask(nodep, cppWidth(nodep));
|
||||
mask.setMask(nodep->widthMin());
|
||||
AstNode* cleanp = new AstAnd(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), mask),
|
||||
nodep);
|
||||
AstNode* cleanp
|
||||
= new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), mask), nodep);
|
||||
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
|
||||
relinkHandle.relink(cleanp);
|
||||
}
|
||||
|
|
@ -138,7 +137,7 @@ private:
|
|||
}
|
||||
void ensureCleanAndNext(AstNode* nodep) {
|
||||
// Editing list, careful looping!
|
||||
for (AstNode* exprp = nodep; exprp; ) {
|
||||
for (AstNode* exprp = nodep; exprp;) {
|
||||
AstNode* nextp = exprp->nextp();
|
||||
ensureClean(exprp);
|
||||
exprp = nextp;
|
||||
|
|
@ -149,27 +148,17 @@ private:
|
|||
void operandBiop(AstNodeBiop* nodep) {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
ensureClean(nodep->lhsp());
|
||||
}
|
||||
if (nodep->cleanRhs()) {
|
||||
ensureClean(nodep->rhsp());
|
||||
}
|
||||
//no setClean.. must do it in each user routine.
|
||||
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
||||
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
||||
// no setClean.. must do it in each user routine.
|
||||
}
|
||||
void operandTriop(AstNodeTriop* nodep) {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
ensureClean(nodep->lhsp());
|
||||
}
|
||||
if (nodep->cleanRhs()) {
|
||||
ensureClean(nodep->rhsp());
|
||||
}
|
||||
if (nodep->cleanThs()) {
|
||||
ensureClean(nodep->thsp());
|
||||
}
|
||||
//no setClean.. must do it in each user routine.
|
||||
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
||||
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
||||
if (nodep->cleanThs()) ensureClean(nodep->thsp());
|
||||
// no setClean.. must do it in each user routine.
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
|
@ -184,9 +173,7 @@ private:
|
|||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
ensureClean(nodep->lhsp());
|
||||
}
|
||||
if (nodep->cleanLhs()) ensureClean(nodep->lhsp());
|
||||
setClean(nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
|
|
@ -213,14 +200,12 @@ private:
|
|||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanRhs()) {
|
||||
ensureClean(nodep->rhsp());
|
||||
}
|
||||
if (nodep->cleanRhs()) ensureClean(nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstText* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstText* nodep) VL_OVERRIDE { //
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE { //
|
||||
setClean(nodep, true);
|
||||
}
|
||||
virtual void visit(AstCNew* nodep) VL_OVERRIDE {
|
||||
|
|
@ -236,9 +221,7 @@ private:
|
|||
computeCppWidth(nodep);
|
||||
setClean(nodep, false);
|
||||
// We always clean, as we don't trust those pesky users.
|
||||
if (!VN_IS(nodep->backp(), And)) {
|
||||
insertClean(nodep);
|
||||
}
|
||||
if (!VN_IS(nodep->backp(), And)) insertClean(nodep);
|
||||
ensureCleanAndNext(nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstTraceDecl* nodep) VL_OVERRIDE {
|
||||
|
|
@ -316,9 +299,7 @@ public:
|
|||
// Clean class functions
|
||||
|
||||
void V3Clean::cleanAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
CleanVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CleanVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
150
src/V3Clock.cpp
150
src/V3Clock.cpp
|
|
@ -46,22 +46,22 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared each Module:
|
||||
// AstVarScope::user1p() -> AstVarScope*. Temporary signal that was created.
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstTopScope* m_topScopep; // Current top scope
|
||||
AstScope* m_scopep; // Current scope
|
||||
AstCFunc* m_evalFuncp; // Top eval function we are creating
|
||||
AstCFunc* m_initFuncp; // Top initial function we are creating
|
||||
AstCFunc* m_finalFuncp; // Top final function we are creating
|
||||
AstCFunc* m_settleFuncp; // Top settlement function we are creating
|
||||
AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates.
|
||||
AstIf* m_lastIfp; // Last sensitivity if active to add more under
|
||||
AstMTaskBody* m_mtaskBodyp; // Current mtask body
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstTopScope* m_topScopep; // Current top scope
|
||||
AstScope* m_scopep; // Current scope
|
||||
AstCFunc* m_evalFuncp; // Top eval function we are creating
|
||||
AstCFunc* m_initFuncp; // Top initial function we are creating
|
||||
AstCFunc* m_finalFuncp; // Top final function we are creating
|
||||
AstCFunc* m_settleFuncp; // Top settlement function we are creating
|
||||
AstSenTree* m_lastSenp; // Last sensitivity match, so we can detect duplicates.
|
||||
AstIf* m_lastIfp; // Last sensitivity if active to add more under
|
||||
AstMTaskBody* m_mtaskBodyp; // Current mtask body
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -69,12 +69,14 @@ private:
|
|||
AstVarScope* getCreateLastClk(AstVarScope* vscp) {
|
||||
if (vscp->user1p()) return static_cast<AstVarScope*>(vscp->user1p());
|
||||
AstVar* varp = vscp->varp();
|
||||
if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "
|
||||
<<varp->prettyNameQ());
|
||||
string newvarname = (string("__Vclklast__")
|
||||
+vscp->scopep()->nameDotless()+"__"+varp->name());
|
||||
AstVar* newvarp = new AstVar(vscp->fileline(),
|
||||
AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1);
|
||||
if (!varp->width1()) {
|
||||
varp->v3error(
|
||||
"Unsupported: Clock edge on non-single bit signal: " << varp->prettyNameQ());
|
||||
}
|
||||
string newvarname
|
||||
= (string("__Vclklast__") + vscp->scopep()->nameDotless() + "__" + varp->name());
|
||||
AstVar* newvarp = new AstVar(vscp->fileline(), AstVarType::MODULETEMP, newvarname,
|
||||
VFlagLogicPacked(), 1);
|
||||
newvarp->noReset(true); // Reset by below assign
|
||||
m_modp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
|
||||
|
|
@ -83,18 +85,16 @@ private:
|
|||
// Add init
|
||||
AstNode* fromp = new AstVarRef(newvarp->fileline(), vscp, false);
|
||||
if (v3Global.opt.xInitialEdge()) fromp = new AstNot(fromp->fileline(), fromp);
|
||||
AstNode* newinitp = new AstAssign(vscp->fileline(),
|
||||
new AstVarRef(newvarp->fileline(), newvscp, true),
|
||||
fromp);
|
||||
AstNode* newinitp = new AstAssign(
|
||||
vscp->fileline(), new AstVarRef(newvarp->fileline(), newvscp, true), fromp);
|
||||
addToInitial(newinitp);
|
||||
// At bottom, assign them
|
||||
AstAssign* finalp
|
||||
= new AstAssign(vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
m_evalFuncp->addFinalsp(finalp);
|
||||
//
|
||||
UINFO(4,"New Last: "<<newvscp<<endl);
|
||||
UINFO(4, "New Last: " << newvscp << endl);
|
||||
return newvscp;
|
||||
}
|
||||
AstNode* createSenItemEquation(AstSenItem* nodep) {
|
||||
|
|
@ -106,49 +106,44 @@ private:
|
|||
// HIGHEDGE: var
|
||||
// LOWEDGE: ~var
|
||||
AstNode* newp = NULL;
|
||||
if (nodep->edgeType()==VEdgeType::ET_ILLEGAL) {
|
||||
if (nodep->edgeType() == VEdgeType::ET_ILLEGAL) {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
nodep->v3error("Unsupported: Complicated event expression in sensitive activity list");
|
||||
nodep->v3error(
|
||||
"Unsupported: Complicated event expression in sensitive activity list");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
||||
if (nodep->edgeType() == VEdgeType::ET_POSEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
lastVscp, false)));
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
|
||||
new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), lastVscp, false)));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_NEGEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
newp = new AstAnd(
|
||||
nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_BOTHEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstXor(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
newp = new AstXor(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep->varrefp()->varScopep(), false),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_HIGHEDGE) {
|
||||
newp = new AstVarRef(nodep->fileline(),
|
||||
clkvscp, false);
|
||||
newp = new AstVarRef(nodep->fileline(), clkvscp, false);
|
||||
} else if (nodep->edgeType() == VEdgeType::ET_LOWEDGE) {
|
||||
newp = new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
clkvscp, false));
|
||||
newp = new AstNot(nodep->fileline(), new AstVarRef(nodep->fileline(), clkvscp, false));
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad edge type");
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
AstNode* createSenGateEquation(AstSenGate* nodep) {
|
||||
AstNode* newp = new AstAnd(nodep->fileline(),
|
||||
createSenseEquation(nodep->sensesp()),
|
||||
AstNode* newp = new AstAnd(nodep->fileline(), createSenseEquation(nodep->sensesp()),
|
||||
nodep->rhsp()->cloneTree(true));
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -186,12 +181,12 @@ private:
|
|||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," TOPSCOPE "<<nodep<<endl);
|
||||
UINFO(4, " TOPSCOPE " << nodep << endl);
|
||||
m_topScopep = nodep;
|
||||
m_scopep = nodep->scopep();
|
||||
UASSERT_OBJ(m_scopep, nodep,
|
||||
"No scope found on top level, perhaps you have no statements?");
|
||||
//VV***** We reset all user1p()
|
||||
// VV***** We reset all user1p()
|
||||
AstNode::user1ClearTree();
|
||||
// Make top functions
|
||||
{
|
||||
|
|
@ -223,11 +218,10 @@ private:
|
|||
funcp->isStatic(false);
|
||||
funcp->entryPoint(true);
|
||||
funcp->protect(false);
|
||||
funcp->addInitsp(new AstCStmt
|
||||
(nodep->fileline(),
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline(),
|
||||
EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symClassVar()
|
||||
+ " = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
|
||||
m_scopep->addActivep(funcp);
|
||||
m_finalFuncp = funcp;
|
||||
}
|
||||
|
|
@ -245,13 +239,13 @@ private:
|
|||
// Process the activates
|
||||
iterateChildren(nodep);
|
||||
// Done, clear so we can detect errors
|
||||
UINFO(4," TOPSCOPEDONE "<<nodep<<endl);
|
||||
UINFO(4, " TOPSCOPEDONE " << nodep << endl);
|
||||
clearLastSen();
|
||||
m_topScopep = NULL;
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," MOD "<<nodep<<endl);
|
||||
// UINFO(4, " MOD " << nodep << endl);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
|
|
@ -260,7 +254,7 @@ private:
|
|||
m_modp = origModp;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," SCOPE "<<nodep<<endl);
|
||||
// UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
if (AstNode* movep = nodep->finalClksp()) {
|
||||
|
|
@ -289,24 +283,21 @@ private:
|
|||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
//nodep->dumpTree(cout, "ct:");
|
||||
//COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// nodep->dumpTree(cout, "ct:");
|
||||
// COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
AstNode* incp = nodep->incp()->unlinkFrBack();
|
||||
AstNode* origp = nodep->origp()->unlinkFrBack();
|
||||
AstNode* changep = nodep->changep()->unlinkFrBack();
|
||||
AstIf* newp = new AstIf(nodep->fileline(),
|
||||
new AstXor(nodep->fileline(),
|
||||
origp,
|
||||
changep),
|
||||
AstIf* newp = new AstIf(nodep->fileline(), new AstXor(nodep->fileline(), origp, changep),
|
||||
incp, NULL);
|
||||
// We could add another IF to detect posedges, and only increment if so.
|
||||
// It's another whole branch though versus a potential memory miss.
|
||||
// We'll go with the miss.
|
||||
newp->addIfsp(new AstAssign(nodep->fileline(),
|
||||
changep->cloneTree(false),
|
||||
origp->cloneTree(false)));
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
newp->addIfsp(
|
||||
new AstAssign(nodep->fileline(), changep->cloneTree(false), origp->cloneTree(false)));
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true);
|
||||
|
|
@ -321,7 +312,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
// Link to global function
|
||||
if (nodep->formCallTree()) {
|
||||
UINFO(4, " formCallTree "<<nodep<<endl);
|
||||
UINFO(4, " formCallTree " << nodep << endl);
|
||||
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
|
||||
callp->argTypes("vlSymsp");
|
||||
m_finalFuncp->addStmtsp(callp);
|
||||
|
|
@ -333,13 +324,13 @@ private:
|
|||
pushDeletep(nodep);
|
||||
}
|
||||
void addToEvalLoop(AstNode* stmtsp) {
|
||||
m_evalFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
m_evalFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
}
|
||||
void addToSettleLoop(AstNode* stmtsp) {
|
||||
m_settleFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
m_settleFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
}
|
||||
void addToInitial(AstNode* stmtsp) {
|
||||
m_initFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
m_initFuncp->addStmtsp(stmtsp); // add to top level function
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
// Careful if adding variables here, ACTIVES can be under other ACTIVES
|
||||
|
|
@ -350,13 +341,13 @@ private:
|
|||
UASSERT_OBJ(!nodep->stmtsp(), nodep, "Non-empty lower active");
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else if (m_mtaskBodyp) {
|
||||
UINFO(4," TR ACTIVE "<<nodep<<endl);
|
||||
UINFO(4, " TR ACTIVE " << nodep << endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (nodep->hasClocked()) {
|
||||
UASSERT_OBJ(!nodep->hasInitial(), nodep,
|
||||
"Initial block should not have clock sensitivity");
|
||||
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
|
||||
UINFO(4," sameSenseTree\n");
|
||||
UINFO(4, " sameSenseTree\n");
|
||||
} else {
|
||||
clearLastSen();
|
||||
m_lastSenp = nodep->sensesp();
|
||||
|
|
@ -375,14 +366,14 @@ private:
|
|||
}
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
} else {
|
||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
||||
UINFO(4, " ACTIVE " << nodep << endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (nodep->hasClocked()) {
|
||||
// Remember the latest sensitivity so we can compare it next time
|
||||
UASSERT_OBJ(!nodep->hasInitial(), nodep,
|
||||
"Initial block should not have clock sensitivity");
|
||||
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
|
||||
UINFO(4," sameSenseTree\n");
|
||||
UINFO(4, " sameSenseTree\n");
|
||||
} else {
|
||||
clearLastSen();
|
||||
m_lastSenp = nodep->sensesp();
|
||||
|
|
@ -410,8 +401,7 @@ private:
|
|||
}
|
||||
}
|
||||
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
|
||||
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody);
|
||||
m_mtaskBodyp;
|
||||
for (m_mtaskBodyp = VN_CAST(nodep->op1p(), MTaskBody); m_mtaskBodyp;
|
||||
m_mtaskBodyp = VN_CAST(m_mtaskBodyp->nextp(), MTaskBody)) {
|
||||
clearLastSen();
|
||||
iterate(m_mtaskBodyp);
|
||||
|
|
@ -453,9 +443,7 @@ public:
|
|||
// Clock class functions
|
||||
|
||||
void V3Clock::clockAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
ClockVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ClockVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,22 +75,24 @@ class CombCallVisitor : CombBaseVisitor {
|
|||
// Find all CCALLS of each CFUNC, so that we can later rename them
|
||||
private:
|
||||
// NODE STATE
|
||||
typedef std::multimap<AstCFunc*,AstCCall*> CallMmap;
|
||||
CallMmap m_callMmap; // Associative array of {function}{call}
|
||||
typedef std::multimap<AstCFunc*, AstCCall*> CallMmap;
|
||||
CallMmap m_callMmap; // Associative array of {function}{call}
|
||||
// METHODS
|
||||
public:
|
||||
void replaceFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) {
|
||||
if (oldfuncp==newfuncp) return;
|
||||
if (oldfuncp == newfuncp) return;
|
||||
if (newfuncp) {
|
||||
UINFO(4, " Replace "<<oldfuncp<<" -WITH-> "<<newfuncp<<endl);
|
||||
} else UINFO(4, " Remove "<<oldfuncp<<endl);
|
||||
std::pair <CallMmap::iterator,CallMmap::iterator> eqrange
|
||||
UINFO(4, " Replace " << oldfuncp << " -WITH-> " << newfuncp << endl);
|
||||
} else {
|
||||
UINFO(4, " Remove " << oldfuncp << endl);
|
||||
}
|
||||
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
|
||||
= m_callMmap.equal_range(oldfuncp);
|
||||
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
|
||||
CallMmap::iterator eqit = nextit++;
|
||||
AstCCall* callp = eqit->second;
|
||||
if (!callp->user3()) { // !already done
|
||||
UINFO(4, " Called "<<callp<<endl);
|
||||
UINFO(4, " Called " << callp << endl);
|
||||
UASSERT_OBJ(callp->funcp() == oldfuncp, callp,
|
||||
"Call list broken, points to call w/different func");
|
||||
if (newfuncp) {
|
||||
|
|
@ -108,27 +110,24 @@ public:
|
|||
}
|
||||
}
|
||||
// METHODS
|
||||
void addCall(AstCCall* nodep) {
|
||||
m_callMmap.insert(make_pair(nodep->funcp(), nodep));
|
||||
}
|
||||
void addCall(AstCCall* nodep) { m_callMmap.insert(make_pair(nodep->funcp(), nodep)); }
|
||||
void deleteCall(AstCCall* nodep) {
|
||||
std::pair<CallMmap::iterator,CallMmap::iterator> eqrange
|
||||
std::pair<CallMmap::iterator, CallMmap::iterator> eqrange
|
||||
= m_callMmap.equal_range(nodep->funcp());
|
||||
for (CallMmap::iterator nextit = eqrange.first; nextit != eqrange.second;) {
|
||||
CallMmap::iterator eqit = nextit++;
|
||||
AstCCall* callp = eqit->second;
|
||||
if (callp==nodep) {
|
||||
if (callp == nodep) {
|
||||
m_callMmap.erase(eqit);
|
||||
return;
|
||||
}
|
||||
}
|
||||
nodep->v3fatalSrc("deleteCall node not found in table");
|
||||
}
|
||||
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE {
|
||||
addCall(nodep);
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) VL_OVERRIDE { addCall(nodep); }
|
||||
// Speed things up
|
||||
virtual void visit(AstNodeAssign*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {}
|
||||
|
|
@ -154,11 +153,10 @@ private:
|
|||
nodep->user3(true);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CombMarkVisitor(AstNode* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); }
|
||||
virtual ~CombMarkVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -172,29 +170,30 @@ private:
|
|||
// AstNodeStmt::user() -> bool. True if iterated already
|
||||
// AstCFunc::user3p() -> AstCFunc*, If set, replace ccalls to this func with new func
|
||||
// AstNodeStmt::user3() -> AstNode*. True if to ignore this cell
|
||||
// AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser3InUse m_inuser3;
|
||||
//AstUser4InUse part of V3Hashed
|
||||
// AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is
|
||||
// illegal)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser3InUse m_inuser3;
|
||||
// AstUser4InUse part of V3Hashed
|
||||
|
||||
// STATE
|
||||
typedef enum {STATE_IDLE, STATE_HASH, STATE_DUP} CombineState;
|
||||
VDouble0 m_statCombs; // Statistic tracking
|
||||
CombineState m_state; // Major state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
int m_modNFuncs; // Number of functions made
|
||||
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
|
||||
AstNode* m_walkLast2p; // Final node that is the same in duplicate list
|
||||
V3Hashed m_hashed; // Hash for every node in module
|
||||
typedef enum { STATE_IDLE, STATE_HASH, STATE_DUP } CombineState;
|
||||
VDouble0 m_statCombs; // Statistic tracking
|
||||
CombineState m_state; // Major state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
int m_modNFuncs; // Number of functions made
|
||||
AstNode* m_walkLast1p; // Final node that is the same in duplicate list
|
||||
AstNode* m_walkLast2p; // Final node that is the same in duplicate list
|
||||
V3Hashed m_hashed; // Hash for every node in module
|
||||
|
||||
// METHODS
|
||||
void hashStatement(AstNode* nodep) {
|
||||
// Compute hash on entire tree of this statement
|
||||
m_hashed.hashAndInsert(nodep);
|
||||
//UINFO(9," stmthash "<<hex<<nodep->user4()<<" "<<nodep<<endl);
|
||||
// UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl);
|
||||
}
|
||||
void hashFunctions(AstCFunc* nodep) {
|
||||
// Compute hash of all statement trees in the function
|
||||
|
|
@ -209,11 +208,9 @@ private:
|
|||
for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) {
|
||||
AstNode* node1p = it->second;
|
||||
AstCFunc* oldfuncp = VN_CAST(node1p, CFunc);
|
||||
if (oldfuncp
|
||||
&& oldfuncp->emptyBody()
|
||||
&& !oldfuncp->dontCombine()) {
|
||||
UINFO(5," EmptyFunc "<<std::hex<<V3Hash(oldfuncp->user4p())
|
||||
<<" "<<oldfuncp<<endl);
|
||||
if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) {
|
||||
UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " "
|
||||
<< oldfuncp << endl);
|
||||
// Mark user3p on entire old tree, so we don't process it more
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, NULL);
|
||||
|
|
@ -231,7 +228,7 @@ private:
|
|||
for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) {
|
||||
AstNode* node2p = eqit->second;
|
||||
if (!(eqit->first == hashval)) break;
|
||||
if (node1p==node2p) continue; // Identical iterator
|
||||
if (node1p == node2p) continue; // Identical iterator
|
||||
if (node1p->user3p() || node2p->user3p()) continue; // Already merged
|
||||
if (node1p->sameTree(node2p)) { // walk of tree has same comparison
|
||||
// Replace AstCCall's that point here
|
||||
|
|
@ -243,8 +240,10 @@ private:
|
|||
}
|
||||
}
|
||||
void replaceFuncWFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) {
|
||||
UINFO(5," DupFunc "<<std::hex<<V3Hash(newfuncp->user4p())<<" "<<newfuncp<<endl);
|
||||
UINFO(5," and "<<std::hex<<V3Hash(oldfuncp->user4p())<<" "<<oldfuncp<<endl);
|
||||
UINFO(5, " DupFunc " << std::hex << V3Hash(newfuncp->user4p()) << " " << newfuncp
|
||||
<< endl);
|
||||
UINFO(5, " and " << std::hex << V3Hash(oldfuncp->user4p()) << " " << oldfuncp
|
||||
<< endl);
|
||||
// Mark user3p on entire old tree, so we don't process it more
|
||||
++m_statCombs;
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
|
|
@ -254,12 +253,10 @@ private:
|
|||
}
|
||||
void replaceOnlyCallFunc(AstCCall* nodep) {
|
||||
if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) {
|
||||
//oldfuncp->dumpTree(cout, "MAYDEL: ");
|
||||
if (nodep->nextp()==NULL
|
||||
&& oldfuncp->initsp()==NULL
|
||||
&& oldfuncp->stmtsp()==nodep
|
||||
&& oldfuncp->finalsp()==NULL) {
|
||||
UINFO(9," Function only has call "<<oldfuncp<<endl);
|
||||
// oldfuncp->dumpTree(cout, "MAYDEL: ");
|
||||
if (nodep->nextp() == NULL && oldfuncp->initsp() == NULL && oldfuncp->stmtsp() == nodep
|
||||
&& oldfuncp->finalsp() == NULL) {
|
||||
UINFO(9, " Function only has call " << oldfuncp << endl);
|
||||
m_call.deleteCall(nodep);
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep);
|
||||
|
|
@ -269,18 +266,18 @@ private:
|
|||
|
||||
void walkDupCodeStart(AstNode* node1p) {
|
||||
V3Hash hashval(node1p->user4p());
|
||||
//UINFO(4," STMT "<<hashval<<" "<<node1p<<endl);
|
||||
// UINFO(4," STMT " << hashval << " " << node1p << endl);
|
||||
//
|
||||
int bestDepth = 0; // Best substitution found in the search
|
||||
AstNode* bestNode2p = NULL;
|
||||
AstNode* bestLast1p = NULL;
|
||||
AstNode* bestLast2p = NULL;
|
||||
//
|
||||
std::pair<V3Hashed::iterator,V3Hashed::iterator> eqrange
|
||||
std::pair<V3Hashed::iterator, V3Hashed::iterator> eqrange
|
||||
= m_hashed.mmap().equal_range(hashval);
|
||||
for (V3Hashed::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
|
||||
AstNode* node2p = eqit->second;
|
||||
if (node1p==node2p) continue;
|
||||
if (node1p == node2p) continue;
|
||||
//
|
||||
// We need to mark iteration to prevent matching code inside
|
||||
// code (abab matching in ababab)
|
||||
|
|
@ -288,8 +285,7 @@ private:
|
|||
m_walkLast1p = NULL;
|
||||
m_walkLast2p = NULL;
|
||||
int depth = walkDupCodeNext(node1p, node2p, 1);
|
||||
if (depth>COMBINE_MIN_STATEMENTS
|
||||
&& depth>bestDepth) {
|
||||
if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) {
|
||||
bestDepth = depth;
|
||||
bestNode2p = node2p;
|
||||
bestLast1p = m_walkLast1p;
|
||||
|
|
@ -298,11 +294,15 @@ private:
|
|||
}
|
||||
if (bestDepth) {
|
||||
// Found a replacement
|
||||
UINFO(5," Duplicate of depth "<<bestDepth<<endl);
|
||||
UINFO(5," DupFunc "<<" "<<node1p<<endl);
|
||||
UINFO(5," and "<<" "<<bestNode2p<<endl);
|
||||
UINFO(5," Through "<<" "<<bestLast1p<<endl);
|
||||
UINFO(5," and "<<" "<<bestLast2p<<endl);
|
||||
UINFO(5, " Duplicate of depth " << bestDepth << endl);
|
||||
UINFO(5, " DupFunc "
|
||||
<< " " << node1p << endl);
|
||||
UINFO(5, " and "
|
||||
<< " " << bestNode2p << endl);
|
||||
UINFO(5, " Through "
|
||||
<< " " << bestLast1p << endl);
|
||||
UINFO(5, " and "
|
||||
<< " " << bestLast2p << endl);
|
||||
//
|
||||
walkReplace(node1p, bestNode2p, bestLast1p, bestLast2p);
|
||||
}
|
||||
|
|
@ -314,32 +314,28 @@ private:
|
|||
if (node1p->user3p() || node2p->user3p()) return 0; // Already merged
|
||||
if (!m_hashed.sameNodes(node1p, node2p)) return 0; // walk of tree has same comparison
|
||||
V3Hash hashval(node1p->user4p());
|
||||
//UINFO(9," wdup1 "<<level<<" "<<V3Hash(node1p->user4p())<<" "<<node1p<<endl);
|
||||
//UINFO(9," wdup2 "<<level<<" "<<V3Hash(node2p->user4p())<<" "<<node2p<<endl);
|
||||
// UINFO(9, " wdup1 "<<level<<" "<<V3Hash(node1p->user4p())<<" "<<node1p<<endl);
|
||||
// UINFO(9, " wdup2 "<<level<<" "<<V3Hash(node2p->user4p())<<" "<<node2p<<endl);
|
||||
m_walkLast1p = node1p;
|
||||
m_walkLast2p = node2p;
|
||||
node1p->user1(true);
|
||||
node2p->user1(true);
|
||||
if (node1p->nextp() && node2p->nextp()) {
|
||||
return hashval.depth()+walkDupCodeNext(node1p->nextp(), node2p->nextp(), level+1);
|
||||
return hashval.depth() + walkDupCodeNext(node1p->nextp(), node2p->nextp(), level + 1);
|
||||
}
|
||||
return hashval.depth();
|
||||
}
|
||||
|
||||
void walkReplace(AstNode* node1p, AstNode* node2p,
|
||||
AstNode* last1p, AstNode* last2p) { // Final node in linked list, maybe null if all statements to be grabbed
|
||||
void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p,
|
||||
AstNode* last2p) { // Final node in linked list, maybe null if all statements
|
||||
// to be grabbed
|
||||
// Make new function
|
||||
string oldname = m_funcp->name();
|
||||
string::size_type pos;
|
||||
if ((pos = oldname.find("_common")) != string::npos) {
|
||||
oldname.erase(pos);
|
||||
}
|
||||
if ((pos = oldname.find("__")) != string::npos) {
|
||||
oldname.erase(pos);
|
||||
}
|
||||
if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos);
|
||||
if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos);
|
||||
AstCFunc* newfuncp = new AstCFunc(node1p->fileline(),
|
||||
oldname+"_common"+cvtToStr(++m_modNFuncs),
|
||||
NULL);
|
||||
oldname + "_common" + cvtToStr(++m_modNFuncs), NULL);
|
||||
m_modp->addStmtp(newfuncp);
|
||||
// Create calls
|
||||
AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp);
|
||||
|
|
@ -347,21 +343,29 @@ private:
|
|||
// Grab statement bodies
|
||||
AstNRelinker relink1Handle;
|
||||
AstNRelinker relink2Handle;
|
||||
for (AstNode* nextp, *walkp = node1p; 1; walkp = nextp) {
|
||||
for (AstNode *nextp, *walkp = node1p; 1; walkp = nextp) {
|
||||
nextp = walkp->nextp();
|
||||
if (walkp==node1p) walkp->unlinkFrBack(&relink1Handle);
|
||||
else { walkp->unlinkFrBack(); node1p->addNext(walkp); }
|
||||
if (walkp==last1p) break;
|
||||
if (walkp == node1p) {
|
||||
walkp->unlinkFrBack(&relink1Handle);
|
||||
} else {
|
||||
walkp->unlinkFrBack();
|
||||
node1p->addNext(walkp);
|
||||
}
|
||||
if (walkp == last1p) break;
|
||||
}
|
||||
for (AstNode* nextp, *walkp = node2p; 1; walkp = nextp) {
|
||||
for (AstNode *nextp, *walkp = node2p; 1; walkp = nextp) {
|
||||
nextp = walkp->nextp();
|
||||
if (walkp==node2p) walkp->unlinkFrBack(&relink2Handle);
|
||||
else { walkp->unlinkFrBack(); node2p->addNext(walkp); }
|
||||
if (walkp==last2p) break;
|
||||
if (walkp == node2p) {
|
||||
walkp->unlinkFrBack(&relink2Handle);
|
||||
} else {
|
||||
walkp->unlinkFrBack();
|
||||
node2p->addNext(walkp);
|
||||
}
|
||||
if (walkp == last2p) break;
|
||||
}
|
||||
// Move node1 statements to new function
|
||||
newfuncp->addStmtsp(node1p);
|
||||
//newfuncp->dumpTree(cout, " newfunctree: ");
|
||||
// newfuncp->dumpTree(cout, " newfunctree: ");
|
||||
// Mark node2 statements as dead
|
||||
CombMarkVisitor visitor(node2p);
|
||||
pushDeletep(node2p); // Delete later
|
||||
|
|
@ -383,13 +387,13 @@ private:
|
|||
// Track all callers of each function
|
||||
m_call.main(nodep);
|
||||
//
|
||||
//In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree
|
||||
// In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree
|
||||
// Iterate modules backwards, in bottom-up order.
|
||||
// Required so that a module instantiating another can benefit from collapsing.
|
||||
iterateChildrenBackwards(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
m_modp = nodep;
|
||||
m_modNFuncs = 0;
|
||||
m_walkLast2p = NULL;
|
||||
|
|
@ -398,17 +402,11 @@ private:
|
|||
m_state = STATE_HASH;
|
||||
iterateChildren(nodep);
|
||||
m_state = STATE_IDLE;
|
||||
if (debug()>=9) {
|
||||
m_hashed.dumpFilePrefixed("combine");
|
||||
}
|
||||
if (debug() >= 9) m_hashed.dumpFilePrefixed("combine");
|
||||
// Walk the hashes removing empty functions
|
||||
if (emptyFunctionDeletion()) {
|
||||
walkEmptyFuncs();
|
||||
}
|
||||
if (emptyFunctionDeletion()) walkEmptyFuncs();
|
||||
// Walk the hashes looking for duplicate functions
|
||||
if (duplicateFunctionCombine()) {
|
||||
walkDupFuncs();
|
||||
}
|
||||
if (duplicateFunctionCombine()) walkDupFuncs();
|
||||
// Walk the statements looking for large replicated code sections
|
||||
if (statementCombine()) {
|
||||
m_state = STATE_DUP;
|
||||
|
|
@ -435,8 +433,7 @@ private:
|
|||
}
|
||||
if (m_state == STATE_HASH && m_funcp) {
|
||||
hashStatement(nodep);
|
||||
}
|
||||
else if (m_state == STATE_DUP && m_funcp) {
|
||||
} else if (m_state == STATE_DUP && m_funcp) {
|
||||
walkDupCodeStart(nodep);
|
||||
}
|
||||
}
|
||||
|
|
@ -459,7 +456,7 @@ public:
|
|||
m_walkLast2p = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~CombineVisitor() {
|
||||
virtual ~CombineVisitor() { //
|
||||
V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs);
|
||||
}
|
||||
};
|
||||
|
|
@ -468,9 +465,7 @@ public:
|
|||
// Combine class functions
|
||||
|
||||
void V3Combine::combineAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
CombineVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ CombineVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -327,12 +327,12 @@ public:
|
|||
inline void applyIgnores(FileLine* filelinep) {
|
||||
// HOT routine, called each parsed token line of this filename
|
||||
if (m_lastIgnore.lineno != filelinep->lineno()) {
|
||||
// UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
|
||||
// UINFO(9, " ApplyIgnores for " << filelinep->ascii() << endl);
|
||||
// Process all on/offs for lines up to and including the current line
|
||||
int curlineno = filelinep->lastLineno();
|
||||
for (; m_lastIgnore.it != m_ignLines.end(); ++m_lastIgnore.it) {
|
||||
if (m_lastIgnore.it->m_lineno > curlineno) break;
|
||||
// UINFO(9," Hit "<<*m_lastIt<<endl);
|
||||
// UINFO(9, " Hit " << *m_lastIt << endl);
|
||||
filelinep->warnOn(m_lastIgnore.it->m_code, m_lastIgnore.it->m_on);
|
||||
}
|
||||
if (0 && debug() >= 9) {
|
||||
|
|
|
|||
1056
src/V3Const.cpp
1056
src/V3Const.cpp
File diff suppressed because it is too large
Load Diff
199
src/V3Dead.cpp
199
src/V3Dead.cpp
|
|
@ -63,9 +63,7 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit DeadModVisitor(AstNodeModule* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); }
|
||||
virtual ~DeadModVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -80,52 +78,46 @@ private:
|
|||
// AstVar::user1() -> int. Count of number of references
|
||||
// AstVarScope::user1() -> int. Count of number of references
|
||||
// AstNodeDType::user1() -> int. Count of number of references
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
typedef std::multimap<AstVarScope*,AstNodeAssign*> AssignMap;
|
||||
typedef std::multimap<AstVarScope*, AstNodeAssign*> AssignMap;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
std::vector<AstVar*> m_varsp; // List of all encountered to avoid another loop through tree
|
||||
std::vector<AstNode*> m_dtypesp; // List of all encountered to avoid another loop through tree
|
||||
std::vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
|
||||
std::vector<AstScope*> m_scopesp; // List of all encountered to avoid another loop through tree
|
||||
std::vector<AstCell*> m_cellsp; // List of all encountered to avoid another loop through tree
|
||||
std::vector<AstClass*> m_classesp; // List of all encountered to avoid another loop through tree
|
||||
AssignMap m_assignMap; // List of all simple assignments for each variable
|
||||
bool m_elimUserVars; // Allow removal of user's vars
|
||||
bool m_elimDTypes; // Allow removal of DTypes
|
||||
bool m_elimScopes; // Allow removal of Scopes
|
||||
bool m_elimCells; // Allow removal of Cells
|
||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||
AstNodeModule* m_modp; // Current module
|
||||
// List of all encountered to avoid another loop through tree
|
||||
std::vector<AstVar*> m_varsp;
|
||||
std::vector<AstNode*> m_dtypesp;
|
||||
std::vector<AstVarScope*> m_vscsp;
|
||||
std::vector<AstScope*> m_scopesp;
|
||||
std::vector<AstCell*> m_cellsp;
|
||||
std::vector<AstClass*> m_classesp;
|
||||
|
||||
AssignMap m_assignMap; // List of all simple assignments for each variable
|
||||
bool m_elimUserVars; // Allow removal of user's vars
|
||||
bool m_elimDTypes; // Allow removal of DTypes
|
||||
bool m_elimScopes; // Allow removal of Scopes
|
||||
bool m_elimCells; // Allow removal of Cells
|
||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void checkAll(AstNode* nodep) {
|
||||
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
|
||||
if (AstNode* subnodep = nodep->dtypep()) {
|
||||
subnodep->user1Inc();
|
||||
}
|
||||
}
|
||||
if (AstNode* subnodep = nodep->getChildDTypep()) {
|
||||
subnodep->user1Inc();
|
||||
if (AstNode* subnodep = nodep->dtypep()) subnodep->user1Inc();
|
||||
}
|
||||
if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
||||
}
|
||||
void checkDType(AstNodeDType* nodep) {
|
||||
if (!nodep->generic() // Don't remove generic types
|
||||
&& m_elimDTypes // dtypes stick around until post-widthing
|
||||
&& !VN_IS(nodep, MemberDType) // Keep member names iff upper type exists
|
||||
) {
|
||||
) {
|
||||
m_dtypesp.push_back(nodep);
|
||||
}
|
||||
if (AstNode* subnodep = nodep->virtRefDTypep()) {
|
||||
subnodep->user1Inc();
|
||||
}
|
||||
if (AstNode* subnodep = nodep->virtRefDType2p()) {
|
||||
subnodep->user1Inc();
|
||||
}
|
||||
if (AstNode* subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
|
||||
if (AstNode* subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
|
|
@ -177,20 +169,24 @@ private:
|
|||
nodep->varScopep()->user1Inc();
|
||||
nodep->varScopep()->varp()->user1Inc();
|
||||
}
|
||||
if (nodep->varp()) {
|
||||
nodep->varp()->user1Inc();
|
||||
}
|
||||
if (nodep->varp()) nodep->varp()->user1Inc();
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) nodep->packagep(NULL);
|
||||
else nodep->packagep()->user1Inc();
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) nodep->packagep(NULL);
|
||||
else nodep->packagep()->user1Inc();
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstMethodCall* nodep) VL_OVERRIDE {
|
||||
|
|
@ -202,8 +198,11 @@ private:
|
|||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) nodep->packagep(NULL);
|
||||
else nodep->packagep()->user1Inc();
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstClassRefDType* nodep) VL_OVERRIDE {
|
||||
|
|
@ -211,12 +210,13 @@ private:
|
|||
checkDType(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) nodep->packagep(NULL);
|
||||
else nodep->packagep()->user1Inc();
|
||||
}
|
||||
if (nodep->classp()) {
|
||||
nodep->classp()->user1Inc();
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
if (nodep->classp()) nodep->classp()->user1Inc();
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -227,8 +227,11 @@ private:
|
|||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->packagep()) {
|
||||
if (m_elimCells) nodep->packagep(NULL);
|
||||
else nodep->packagep()->user1Inc();
|
||||
if (m_elimCells) {
|
||||
nodep->packagep(NULL);
|
||||
} else {
|
||||
nodep->packagep()->user1Inc();
|
||||
}
|
||||
}
|
||||
checkAll(nodep);
|
||||
}
|
||||
|
|
@ -263,17 +266,13 @@ private:
|
|||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->scopep()) nodep->scopep()->user1Inc();
|
||||
if (mightElimVar(nodep->varp())) {
|
||||
m_vscsp.push_back(nodep);
|
||||
}
|
||||
if (mightElimVar(nodep->varp())) m_vscsp.push_back(nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
checkAll(nodep);
|
||||
if (nodep->isSigPublic() && m_modp && VN_IS(m_modp, Package)) m_modp->user1Inc();
|
||||
if (mightElimVar(nodep)) {
|
||||
m_varsp.push_back(nodep);
|
||||
}
|
||||
if (mightElimVar(nodep)) m_varsp.push_back(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
// See if simple assignments to variables may be eliminated because
|
||||
|
|
@ -306,14 +305,15 @@ private:
|
|||
// Kill any unused modules
|
||||
// V3LinkCells has a graph that is capable of this too, but we need to do it
|
||||
// after we've done all the generate blocks
|
||||
for (bool retry=true; retry; ) {
|
||||
for (bool retry = true; retry;) {
|
||||
retry = false;
|
||||
AstNodeModule* nextmodp;
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp = nextmodp) {
|
||||
nextmodp = VN_CAST(modp->nextp(), NodeModule);
|
||||
if (modp->dead() || (modp->level()>2 && modp->user1()==0 && !modp->internal())) {
|
||||
if (modp->dead()
|
||||
|| (modp->level() > 2 && modp->user1() == 0 && !modp->internal())) {
|
||||
// > 2 because L1 is the wrapper, L2 is the top user module
|
||||
UINFO(4," Dead module "<<modp<<endl);
|
||||
UINFO(4, " Dead module " << modp << endl);
|
||||
// And its children may now be killable too; correct counts
|
||||
// Recurse, as cells may not be directly under the module but in a generate
|
||||
if (!modp->dead()) { // If was dead didn't increment user1's
|
||||
|
|
@ -327,27 +327,23 @@ private:
|
|||
}
|
||||
bool mightElimVar(AstVar* nodep) {
|
||||
return (!nodep->isSigPublic() // Can't elim publics!
|
||||
&& !nodep->isIO()
|
||||
&& !nodep->isClassMember()
|
||||
&& !nodep->isIO() && !nodep->isClassMember()
|
||||
&& ((nodep->isTemp() && !nodep->isTrace())
|
||||
|| (nodep->isParam() && !nodep->isTrace() && !v3Global.opt.xmlOnly())
|
||||
|| m_elimUserVars)); // Post-Trace can kill most anything
|
||||
}
|
||||
|
||||
void deadCheckScope() {
|
||||
for (bool retry=true; retry; ) {
|
||||
for (bool retry = true; retry;) {
|
||||
retry = false;
|
||||
for (std::vector<AstScope*>::iterator it = m_scopesp.begin();
|
||||
it != m_scopesp.end();++it) {
|
||||
for (std::vector<AstScope*>::iterator it = m_scopesp.begin(); it != m_scopesp.end();
|
||||
++it) {
|
||||
AstScope* scp = *it;
|
||||
if (!scp)
|
||||
continue;
|
||||
if (!scp) continue;
|
||||
if (scp->user1() == 0) {
|
||||
UINFO(4, " Dead AstScope " << scp << endl);
|
||||
scp->aboveScopep()->user1Inc(-1);
|
||||
if (scp->dtypep()) {
|
||||
scp->dtypep()->user1Inc(-1);
|
||||
}
|
||||
if (scp->dtypep()) scp->dtypep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(scp->unlinkFrBack()->deleteTree(), scp);
|
||||
*it = NULL;
|
||||
retry = true;
|
||||
|
|
@ -357,7 +353,7 @@ private:
|
|||
}
|
||||
|
||||
void deadCheckCells() {
|
||||
for (std::vector<AstCell*>::iterator it = m_cellsp.begin(); it!=m_cellsp.end(); ++it) {
|
||||
for (std::vector<AstCell*>::iterator it = m_cellsp.begin(); it != m_cellsp.end(); ++it) {
|
||||
AstCell* cellp = *it;
|
||||
if (cellp->user1() == 0 && !cellp->modp()->stmtsp()) {
|
||||
cellp->modp()->user1Inc(-1);
|
||||
|
|
@ -385,15 +381,15 @@ private:
|
|||
|
||||
void deadCheckVar() {
|
||||
// Delete any unused varscopes
|
||||
for (std::vector<AstVarScope*>::iterator it = m_vscsp.begin(); it!=m_vscsp.end(); ++it) {
|
||||
for (std::vector<AstVarScope*>::iterator it = m_vscsp.begin(); it != m_vscsp.end(); ++it) {
|
||||
AstVarScope* vscp = *it;
|
||||
if (vscp->user1() == 0) {
|
||||
UINFO(4," Dead "<<vscp<<endl);
|
||||
std::pair<AssignMap::iterator,AssignMap::iterator> eqrange
|
||||
UINFO(4, " Dead " << vscp << endl);
|
||||
std::pair<AssignMap::iterator, AssignMap::iterator> eqrange
|
||||
= m_assignMap.equal_range(vscp);
|
||||
for (AssignMap::iterator itr = eqrange.first; itr != eqrange.second; ++itr) {
|
||||
AstNodeAssign* assp = itr->second;
|
||||
UINFO(4," Dead assign "<<assp<<endl);
|
||||
UINFO(4, " Dead assign " << assp << endl);
|
||||
assp->dtypep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(assp->unlinkFrBack()->deleteTree(), assp);
|
||||
}
|
||||
|
|
@ -402,40 +398,36 @@ private:
|
|||
VL_DO_DANGLING(vscp->unlinkFrBack()->deleteTree(), vscp);
|
||||
}
|
||||
}
|
||||
for (bool retry=true; retry; ) {
|
||||
for (bool retry = true; retry;) {
|
||||
retry = false;
|
||||
for (std::vector<AstVar *>::iterator it = m_varsp.begin(); it != m_varsp.end();++it) {
|
||||
for (std::vector<AstVar*>::iterator it = m_varsp.begin(); it != m_varsp.end(); ++it) {
|
||||
AstVar* varp = *it;
|
||||
if (!varp)
|
||||
continue;
|
||||
if (!varp) continue;
|
||||
if (varp->user1() == 0) {
|
||||
UINFO(4, " Dead " << varp << endl);
|
||||
if (varp->dtypep()) {
|
||||
varp->dtypep()->user1Inc(-1);
|
||||
}
|
||||
if (varp->dtypep()) varp->dtypep()->user1Inc(-1);
|
||||
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
|
||||
*it = NULL;
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end();++it) {
|
||||
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) {
|
||||
if ((*it)->user1() == 0) {
|
||||
AstNodeUOrStructDType *classp;
|
||||
AstNodeUOrStructDType* classp;
|
||||
// It's possible that there if a reference to each individual member, but
|
||||
// not to the dtype itself. Check and don't remove the parent dtype if
|
||||
// members are still alive.
|
||||
if ((classp = VN_CAST((*it), NodeUOrStructDType))) {
|
||||
bool cont = true;
|
||||
for (AstMemberDType *memberp = classp->membersp();
|
||||
memberp; memberp = VN_CAST(memberp->nextp(), MemberDType)) {
|
||||
for (AstMemberDType* memberp = classp->membersp(); memberp;
|
||||
memberp = VN_CAST(memberp->nextp(), MemberDType)) {
|
||||
if (memberp->user1() != 0) {
|
||||
cont = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!cont)
|
||||
continue;
|
||||
if (!cont) continue;
|
||||
}
|
||||
VL_DO_DANGLING((*it)->unlinkFrBack()->deleteTree(), *it);
|
||||
}
|
||||
|
|
@ -444,8 +436,8 @@ private:
|
|||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes,
|
||||
bool elimScopes, bool elimCells) {
|
||||
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes,
|
||||
bool elimCells) {
|
||||
m_modp = NULL;
|
||||
m_elimCells = elimCells;
|
||||
m_elimUserVars = elimUserVars;
|
||||
|
|
@ -476,41 +468,32 @@ public:
|
|||
// Dead class functions
|
||||
|
||||
void V3Dead::deadifyModules(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
DeadVisitor visitor (nodep, false, false, false, false);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor(nodep, false, false, false, false); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadModules", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyDTypes(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
DeadVisitor visitor (nodep, false, true, false, false);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor(nodep, false, true, false, false); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypes", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
DeadVisitor visitor (nodep, false, true, true, false);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor(nodep, false, true, true, false); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0,
|
||||
v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
DeadVisitor visitor (nodep, true, true, false, true);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor(nodep, true, true, false, true); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadAll", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Dead::deadifyAllScoped(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
DeadVisitor visitor (nodep, true, true, true, true);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DeadVisitor visitor(nodep, true, true, true, true); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("deadAllScoped", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,40 +81,41 @@ private:
|
|||
// Cleared each scope/active:
|
||||
// AstAssignDly::user3() -> AstVarScope*. __Vdlyvset__ created for this assign
|
||||
// AstAlwaysPost::user3() -> AstVarScope*. __Vdlyvset__ last referenced in IF
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
|
||||
enum VarUsage { VU_NONE=0, VU_DLY=1, VU_NONDLY=2 };
|
||||
enum VarUsage { VU_NONE = 0, VU_DLY = 1, VU_NONDLY = 2 };
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Current activate
|
||||
AstCFunc* m_cfuncp; // Current public C Function
|
||||
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
|
||||
bool m_inDly; // True in delayed assignments
|
||||
bool m_inLoop; // True in for loops
|
||||
bool m_inInitial; // True in initial blocks
|
||||
typedef std::map<std::pair<AstNodeModule*,string>,AstVar*> VarMap;
|
||||
VarMap m_modVarMap; // Table of new var names created under module
|
||||
VDouble0 m_statSharedSet; // Statistic tracking
|
||||
typedef std::map<AstVarScope*,int> ScopeVecMap;
|
||||
AstActive* m_activep; // Current activate
|
||||
AstCFunc* m_cfuncp; // Current public C Function
|
||||
AstAssignDly* m_nextDlyp; // Next delayed assignment in a list of assignments
|
||||
bool m_inDly; // True in delayed assignments
|
||||
bool m_inLoop; // True in for loops
|
||||
bool m_inInitial; // True in initial blocks
|
||||
typedef std::map<std::pair<AstNodeModule*, string>, AstVar*> VarMap;
|
||||
VarMap m_modVarMap; // Table of new var names created under module
|
||||
VDouble0 m_statSharedSet; // Statistic tracking
|
||||
typedef std::map<AstVarScope*, int> ScopeVecMap;
|
||||
ScopeVecMap m_scopeVecMap; // Next var number for each scope
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void markVarUsage(AstVarScope* nodep, uint32_t flags) {
|
||||
//UINFO(4," MVU "<<flags<<" "<<nodep<<endl);
|
||||
nodep->user5( nodep->user5() | flags );
|
||||
// UINFO(4, " MVU " << flags << " " << nodep << endl);
|
||||
nodep->user5(nodep->user5() | flags);
|
||||
if ((nodep->user5() & VU_DLY) && (nodep->user5() & VU_NONDLY)) {
|
||||
nodep->v3warn(BLKANDNBLK, "Unsupported: Blocked and non-blocking assignments to same variable: "
|
||||
<<nodep->varp()->prettyNameQ());
|
||||
nodep->v3warn(BLKANDNBLK,
|
||||
"Unsupported: Blocked and non-blocking assignments to same variable: "
|
||||
<< nodep->varp()->prettyNameQ());
|
||||
}
|
||||
}
|
||||
AstVarScope* createVarSc(AstVarScope* oldvarscp, const string& name,
|
||||
int width/*0==fromoldvar*/, AstNodeDType* newdtypep) {
|
||||
int width /*0==fromoldvar*/, AstNodeDType* newdtypep) {
|
||||
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
|
||||
UASSERT_OBJ(oldvarscp->scopep(), oldvarscp, "Var unscoped");
|
||||
AstVar* varp;
|
||||
|
|
@ -126,15 +127,14 @@ private:
|
|||
varp = it->second;
|
||||
} else {
|
||||
if (newdtypep) {
|
||||
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP,
|
||||
name, newdtypep);
|
||||
} else if (width==0) {
|
||||
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP,
|
||||
name, oldvarscp->varp());
|
||||
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, newdtypep);
|
||||
} else if (width == 0) {
|
||||
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
oldvarscp->varp());
|
||||
varp->dtypeFrom(oldvarscp);
|
||||
} else { // Used for vset and dimensions, so can zero init
|
||||
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP,
|
||||
name, VFlagBitPacked(), width);
|
||||
varp = new AstVar(oldvarscp->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
VFlagBitPacked(), width);
|
||||
}
|
||||
addmodp->addStmtp(varp);
|
||||
m_modVarMap.insert(make_pair(make_pair(addmodp, name), varp));
|
||||
|
|
@ -146,8 +146,8 @@ private:
|
|||
}
|
||||
|
||||
AstActive* createActivePost(AstVarRef* varrefp) {
|
||||
AstActive* newactp = new AstActive(varrefp->fileline(), "sequentdly",
|
||||
m_activep->sensesp());
|
||||
AstActive* newactp
|
||||
= new AstActive(varrefp->fileline(), "sequentdly", m_activep->sensesp());
|
||||
// Was addNext(), but addNextHere() avoids a linear search.
|
||||
m_activep->addNextHere(newactp);
|
||||
return newactp;
|
||||
|
|
@ -159,18 +159,18 @@ private:
|
|||
if (!varrefp->varp()->fileline()->warnIsOff(V3ErrorCode::MULTIDRIVEN)
|
||||
&& !varrefp->varp()->user2()) {
|
||||
varrefp->varp()->v3warn(
|
||||
MULTIDRIVEN, "Signal has multiple driving blocks with different clocking: "
|
||||
<<varrefp->varp()->prettyNameQ()<<endl
|
||||
<<varrefp->warnOther()<<"... Location of first driving block"<<endl
|
||||
<<varrefp->warnContextPrimary()<<endl
|
||||
<<oldactivep->warnOther()<<"... Location of other driving block"<<endl
|
||||
<<oldactivep->warnContextSecondary()
|
||||
);
|
||||
MULTIDRIVEN,
|
||||
"Signal has multiple driving blocks with different clocking: "
|
||||
<< varrefp->varp()->prettyNameQ() << endl
|
||||
<< varrefp->warnOther() << "... Location of first driving block" << endl
|
||||
<< varrefp->warnContextPrimary() << endl
|
||||
<< oldactivep->warnOther() << "... Location of other driving block" << endl
|
||||
<< oldactivep->warnContextSecondary());
|
||||
varrefp->varp()->user2(true);
|
||||
}
|
||||
UINFO(4,"AssignDupDlyVar: "<<varrefp<<endl);
|
||||
UINFO(4," Act: "<<m_activep<<endl);
|
||||
UINFO(4," Act: "<<oldactivep<<endl);
|
||||
UINFO(4, "AssignDupDlyVar: " << varrefp << endl);
|
||||
UINFO(4, " Act: " << m_activep << endl);
|
||||
UINFO(4, " Act: " << oldactivep << endl);
|
||||
// Make a new sensitivity list, which is the combination of both blocks
|
||||
AstNodeSenItem* sena = m_activep->sensesp()->sensesp()->cloneTree(true);
|
||||
AstNodeSenItem* senb = oldactivep->sensesp()->sensesp()->cloneTree(true);
|
||||
|
|
@ -191,8 +191,8 @@ private:
|
|||
// Return the new LHS for the assignment, Null = unlink
|
||||
// Find selects
|
||||
AstNode* newlhsp = NULL; // NULL = unlink old assign
|
||||
AstSel* bitselp = NULL;
|
||||
AstArraySel* arrayselp = NULL;
|
||||
AstSel* bitselp = NULL;
|
||||
AstArraySel* arrayselp = NULL;
|
||||
if (VN_IS(lhsp, Sel)) {
|
||||
bitselp = VN_CAST(lhsp, Sel);
|
||||
arrayselp = VN_CAST(bitselp->fromp(), ArraySel);
|
||||
|
|
@ -202,12 +202,12 @@ private:
|
|||
UASSERT_OBJ(arrayselp, nodep, "No arraysel under bitsel?");
|
||||
UASSERT_OBJ(!VN_IS(arrayselp->dtypep()->skipRefp(), UnpackArrayDType), nodep,
|
||||
"ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
UINFO(4,"AssignDlyArray: "<<nodep<<endl);
|
||||
UINFO(4, "AssignDlyArray: " << nodep << endl);
|
||||
//
|
||||
//=== Dimensions: __Vdlyvdim__
|
||||
std::deque<AstNode*> dimvalp; // Assignment value for each dimension of assignment
|
||||
AstNode* dimselp = arrayselp;
|
||||
for (; VN_IS(dimselp, ArraySel); dimselp=VN_CAST(dimselp, ArraySel)->fromp()) {
|
||||
for (; VN_IS(dimselp, ArraySel); dimselp = VN_CAST(dimselp, ArraySel)->fromp()) {
|
||||
AstNode* valp = VN_CAST(dimselp, ArraySel)->bitp()->unlinkFrBack();
|
||||
dimvalp.push_front(valp);
|
||||
}
|
||||
|
|
@ -219,19 +219,17 @@ private:
|
|||
int modVecNum = m_scopeVecMap[varrefp->varScopep()]++;
|
||||
//
|
||||
std::deque<AstNode*> dimreadps; // Read value for each dimension of assignment
|
||||
for (unsigned dimension=0; dimension<dimvalp.size(); dimension++) {
|
||||
for (unsigned dimension = 0; dimension < dimvalp.size(); dimension++) {
|
||||
AstNode* dimp = dimvalp[dimension];
|
||||
if (VN_IS(dimp, Const)) { // bit = const, can just use it
|
||||
dimreadps.push_front(dimp);
|
||||
} else {
|
||||
string bitvarname = (string("__Vdlyvdim")+cvtToStr(dimension)
|
||||
+"__"+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(),
|
||||
bitvarname, dimp->width(), NULL);
|
||||
AstAssign* bitassignp
|
||||
= new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), bitvscp, true),
|
||||
dimp);
|
||||
string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__"
|
||||
+ oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), NULL);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), dimp);
|
||||
nodep->addNextHere(bitassignp);
|
||||
dimreadps.push_front(new AstVarRef(nodep->fileline(), bitvscp, false));
|
||||
}
|
||||
|
|
@ -241,15 +239,16 @@ private:
|
|||
AstNode* bitreadp = NULL; // Code to read Vdlyvlsb
|
||||
if (bitselp) {
|
||||
AstNode* lsbvaluep = bitselp->lsbp()->unlinkFrBack();
|
||||
if (VN_IS(bitselp->fromp(), Const)) { // vlsb = constant, can just push constant into where we use it
|
||||
if (VN_IS(bitselp->fromp(), Const)) {
|
||||
// vlsb = constant, can just push constant into where we use it
|
||||
bitreadp = lsbvaluep;
|
||||
} else {
|
||||
string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(),
|
||||
bitvarname, lsbvaluep->width(), NULL);
|
||||
AstAssign* bitassignp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), bitvscp, true),
|
||||
lsbvaluep);
|
||||
string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v"
|
||||
+ cvtToStr(modVecNum));
|
||||
AstVarScope* bitvscp
|
||||
= createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), NULL);
|
||||
AstAssign* bitassignp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), bitvscp, true), lsbvaluep);
|
||||
nodep->addNextHere(bitassignp);
|
||||
bitreadp = new AstVarRef(nodep->fileline(), bitvscp, false);
|
||||
}
|
||||
|
|
@ -257,11 +256,14 @@ private:
|
|||
//
|
||||
//=== Value: __Vdlyvval__
|
||||
AstNode* valreadp; // Code to read Vdlyvval
|
||||
if (VN_IS(nodep->rhsp(), Const)) { // vval = constant, can just push constant into where we use it
|
||||
if (VN_IS(nodep->rhsp(), Const)) {
|
||||
// vval = constant, can just push constant into where we use it
|
||||
valreadp = nodep->rhsp()->unlinkFrBack();
|
||||
} else {
|
||||
string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
|
||||
AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
string valvarname
|
||||
= (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
AstVarScope* valvscp
|
||||
= createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
|
||||
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
|
||||
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
|
||||
}
|
||||
|
|
@ -278,14 +280,14 @@ private:
|
|||
setvscp = VN_CAST(nodep->user3p(), VarScope);
|
||||
++m_statSharedSet;
|
||||
} else { // Create new one
|
||||
string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
|
||||
string setvarname
|
||||
= (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum));
|
||||
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, NULL);
|
||||
setinitp = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
AstAssign* setassignp
|
||||
= new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
= new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, true),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()));
|
||||
nodep->addNextHere(setassignp);
|
||||
}
|
||||
|
|
@ -299,7 +301,7 @@ private:
|
|||
// in correctly ordered code - the last assignment must be last.
|
||||
// It also has the nice side effect of assisting cache locality.
|
||||
AstNode* selectsp = varrefp;
|
||||
for (int dimension=int(dimreadps.size())-1; dimension>=0; --dimension) {
|
||||
for (int dimension = int(dimreadps.size()) - 1; dimension >= 0; --dimension) {
|
||||
selectsp = new AstArraySel(nodep->fileline(), selectsp, dimreadps[dimension]);
|
||||
}
|
||||
if (bitselp) {
|
||||
|
|
@ -307,16 +309,16 @@ private:
|
|||
bitselp->widthp()->cloneTree(false));
|
||||
}
|
||||
// Build "IF (changeit) ...
|
||||
UINFO(9," For "<<setvscp<<endl);
|
||||
UINFO(9," & "<<varrefp<<endl);
|
||||
UINFO(9, " For " << setvscp << endl);
|
||||
UINFO(9, " & " << varrefp << endl);
|
||||
AstAlwaysPost* finalp = VN_CAST(varrefp->varScopep()->user4p(), AlwaysPost);
|
||||
if (finalp) {
|
||||
AstActive* oldactivep = VN_CAST(finalp->user2p(), Active);
|
||||
checkActivePost(varrefp, oldactivep);
|
||||
if (setinitp) oldactivep->addStmtsp(setinitp);
|
||||
} else { // first time we've dealt with this memory
|
||||
finalp = new AstAlwaysPost(nodep->fileline(), NULL/*sens*/, NULL/*body*/);
|
||||
UINFO(9," Created "<<finalp<<endl);
|
||||
finalp = new AstAlwaysPost(nodep->fileline(), NULL /*sens*/, NULL /*body*/);
|
||||
UINFO(9, " Created " << finalp << endl);
|
||||
AstActive* newactp = createActivePost(varrefp);
|
||||
newactp->addStmtsp(finalp);
|
||||
varrefp->varScopep()->user4p(finalp);
|
||||
|
|
@ -332,9 +334,8 @@ private:
|
|||
"Delayed assignment misoptimized; prev var found w/o associated IF");
|
||||
} else {
|
||||
postLogicp = new AstIf(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), setvscp, false),
|
||||
NULL, NULL);
|
||||
UINFO(9," Created "<<postLogicp<<endl);
|
||||
new AstVarRef(nodep->fileline(), setvscp, false), NULL, NULL);
|
||||
UINFO(9, " Created " << postLogicp << endl);
|
||||
finalp->addBodysp(postLogicp);
|
||||
finalp->user3p(setvscp); // Remember IF's vset variable
|
||||
finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it
|
||||
|
|
@ -345,12 +346,12 @@ private:
|
|||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
//VV***** We reset all userp() on the netlist
|
||||
// VV***** We reset all userp() on the netlist
|
||||
m_modVarMap.clear();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
AstNode::user3ClearTree();
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -363,28 +364,34 @@ private:
|
|||
m_activep = nodep;
|
||||
bool oldinit = m_inInitial;
|
||||
m_inInitial = nodep->hasInitial();
|
||||
AstNode::user3ClearTree(); // Two sets to same variable in different actives must use different vars.
|
||||
AstNode::user3ClearTree(); // Two sets to same variable in different
|
||||
// actives must use different vars.
|
||||
iterateChildren(nodep);
|
||||
m_inInitial = oldinit;
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
m_inDly = true;
|
||||
m_nextDlyp = VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
|
||||
if (m_cfuncp) nodep->v3error("Unsupported: Delayed assignment inside public function/task");
|
||||
m_nextDlyp
|
||||
= VN_CAST(nodep->nextp(), AssignDly); // Next assignment in same block, maybe NULL.
|
||||
if (m_cfuncp) {
|
||||
nodep->v3error("Unsupported: Delayed assignment inside public function/task");
|
||||
}
|
||||
if (VN_IS(nodep->lhsp(), ArraySel)
|
||||
|| (VN_IS(nodep->lhsp(), Sel)
|
||||
&& VN_IS(VN_CAST(nodep->lhsp(), Sel)->fromp(), ArraySel))) {
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newlhsp = createDlyArray(nodep, lhsp);
|
||||
if (m_inLoop) nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
|
||||
if (m_inLoop) {
|
||||
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
|
||||
"loops (non-delayed is ok - see docs)");
|
||||
}
|
||||
if (newlhsp) {
|
||||
nodep->lhsp(newlhsp);
|
||||
} else {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_inDly = false;
|
||||
|
|
@ -394,11 +401,12 @@ private:
|
|||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user2Inc()) { // Not done yet
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
UINFO(4,"AssignDlyVar: "<<nodep<<endl);
|
||||
UINFO(4, "AssignDlyVar: " << nodep << endl);
|
||||
markVarUsage(nodep->varScopep(), VU_DLY);
|
||||
UASSERT_OBJ(m_activep, nodep, "<= not under sensitivity block");
|
||||
if (!m_activep->hasClocked()) {
|
||||
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should have converted in V3Active");
|
||||
nodep->v3error("Internal: Blocking <= assignment in non-clocked block, should "
|
||||
"have converted in V3Active");
|
||||
}
|
||||
AstVarScope* oldvscp = nodep->varScopep();
|
||||
UASSERT_OBJ(oldvscp, nodep, "Var didn't get varscoped in V3Scope.cpp");
|
||||
|
|
@ -408,16 +416,14 @@ private:
|
|||
checkActivePost(nodep, oldactivep);
|
||||
}
|
||||
if (!dlyvscp) { // First use of this delayed variable
|
||||
string newvarname = (string("__Vdly__")+nodep->varp()->shortName());
|
||||
string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL);
|
||||
AstNodeAssign* prep
|
||||
= new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, false));
|
||||
AstNodeAssign* postp
|
||||
= new AstAssignPost(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, true),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, false));
|
||||
AstNodeAssign* prep = new AstAssignPre(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, false));
|
||||
AstNodeAssign* postp = new AstAssignPost(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, false));
|
||||
postp->lhsp()->user2(true); // Don't detect this assignment
|
||||
oldvscp->user1p(dlyvscp); // So we can find it later
|
||||
// Make new ACTIVE with identical sensitivity tree
|
||||
|
|
@ -428,12 +434,12 @@ private:
|
|||
}
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), dlyvscp, true);
|
||||
newrefp->user2(true); // No reason to do it again
|
||||
nodep->replaceWith(newrefp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
else if (!m_inDly && nodep->lvalue()) {
|
||||
//UINFO(9,"NBA "<<nodep<<endl);
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
} else if (!m_inDly && nodep->lvalue()) {
|
||||
// UINFO(9, "NBA " << nodep << endl);
|
||||
if (!m_inInitial) {
|
||||
UINFO(4,"AssignNDlyVar: "<<nodep<<endl);
|
||||
UINFO(4, "AssignNDlyVar: " << nodep << endl);
|
||||
markVarUsage(nodep->varScopep(), VU_NONDLY);
|
||||
}
|
||||
}
|
||||
|
|
@ -441,7 +447,8 @@ private:
|
|||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
|
||||
nodep->v3fatalSrc("For statements should have been converted to while statements in V3Begin");
|
||||
nodep->v3fatalSrc(
|
||||
"For statements should have been converted to while statements in V3Begin");
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
bool oldloop = m_inLoop;
|
||||
|
|
@ -474,9 +481,7 @@ public:
|
|||
// Delayed class functions
|
||||
|
||||
void V3Delayed::delayedAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
DelayedVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ DelayedVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("delayed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ private:
|
|||
|
||||
void createDeepTemp(AstNode* nodep) {
|
||||
UINFO(6, " Deep " << nodep << endl);
|
||||
// if (debug()>=9) nodep->dumpTree(cout, "deep:");
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, "deep:");
|
||||
|
||||
string newvarname = (string("__Vdeeptemp") + cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname,
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ private:
|
|||
nodep->varScopep(NULL);
|
||||
}
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
// UINFO(9," "<<nodep<<endl);
|
||||
// UINFO(9, " " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
// Convert the hierch name
|
||||
UASSERT_OBJ(m_scopep, nodep, "Node not under scope");
|
||||
|
|
|
|||
1509
src/V3EmitC.cpp
1509
src/V3EmitC.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -39,23 +39,32 @@ public:
|
|||
V3OutCFile* ofp() const { return m_ofp; }
|
||||
void puts(const string& str) { ofp()->puts(str); }
|
||||
void putbs(const string& str) { ofp()->putbs(str); }
|
||||
void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); }
|
||||
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 protect(const string& name) { return VIdProtect::protectIf(name, true); }
|
||||
static string protectIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectIf(name, doIt); }
|
||||
return VIdProtect::protectIf(name, doIt);
|
||||
}
|
||||
static string protectWordsIf(const string& name, bool doIt) {
|
||||
return VIdProtect::protectWordsIf(name, 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 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;"; }
|
||||
return v3Global.opt.prefix() + "* __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp;";
|
||||
}
|
||||
static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) {
|
||||
if (nodep->isConstructor()) return prefixNameProtect(modp);
|
||||
else if (nodep->isDestructor()) return string("~") + prefixNameProtect(modp);
|
||||
else return nodep->nameProtect();
|
||||
if (nodep->isConstructor()) {
|
||||
return prefixNameProtect(modp);
|
||||
} else if (nodep->isDestructor()) {
|
||||
return string("~") + prefixNameProtect(modp);
|
||||
} else {
|
||||
return nodep->nameProtect();
|
||||
}
|
||||
}
|
||||
static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix
|
||||
const AstNodeModule* modp = VN_CAST_CONST(nodep, NodeModule);
|
||||
|
|
@ -79,15 +88,17 @@ public:
|
|||
// Return argument list for given C function
|
||||
string args = nodep->argTypes();
|
||||
// Might be a user function with argument list.
|
||||
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
for (const AstNode* stmtp = nodep->argsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (const AstVar* portp = VN_CAST_CONST(stmtp, Var)) {
|
||||
if (portp->isIO() && !portp->isFuncReturn()) {
|
||||
if (args != "") args+= ", ";
|
||||
if (nodep->dpiImport() || nodep->dpiExportWrapper())
|
||||
if (args != "") args += ", ";
|
||||
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
|
||||
args += portp->dpiArgType(true, false);
|
||||
else if (nodep->funcPublic())
|
||||
} else if (nodep->funcPublic()) {
|
||||
args += portp->cPubArgType(true, false);
|
||||
else args += portp->vlArgType(true, false, true);
|
||||
} else {
|
||||
args += portp->vlArgType(true, false, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -114,6 +125,7 @@ private:
|
|||
m_count++;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit EmitCBaseCounterVisitor(AstNode* nodep) {
|
||||
|
|
|
|||
|
|
@ -35,8 +35,7 @@ class CMakeEmitter {
|
|||
// STATIC FUNCTIONS
|
||||
|
||||
// Concatenate all strings in 'strs' with ' ' between them.
|
||||
template<typename List>
|
||||
static string cmake_list(const List& strs) {
|
||||
template <typename List> static string cmake_list(const List& strs) {
|
||||
string s;
|
||||
if (strs.begin() != strs.end()) {
|
||||
s.append("\"");
|
||||
|
|
@ -56,16 +55,14 @@ class CMakeEmitter {
|
|||
// "BOOL", "FILEPATH", "PATH", "STRING" or "INTERNAL" for a CACHE variable
|
||||
// See https://cmake.org/cmake/help/latest/command/set.html
|
||||
static void cmake_set_raw(std::ofstream& of, const string& name, const string& raw_value,
|
||||
const string& cache_type = "", const string& docstring = "") {
|
||||
const string& cache_type = "", const string& docstring = "") {
|
||||
of << "set(" << name << " " << raw_value;
|
||||
if (!cache_type.empty()) {
|
||||
of << " CACHE " << cache_type << " \"" << docstring << "\"";
|
||||
}
|
||||
if (!cache_type.empty()) { of << " CACHE " << cache_type << " \"" << docstring << "\""; }
|
||||
of << ")\n";
|
||||
}
|
||||
|
||||
static void cmake_set(std::ofstream& of, const string& name, const string& value,
|
||||
const string& cache_type = "", const string& docstring = "") {
|
||||
const string& cache_type = "", const string& docstring = "") {
|
||||
string raw_value = "\"" + value + "\"";
|
||||
cmake_set_raw(of, name, raw_value, cache_type, docstring);
|
||||
}
|
||||
|
|
@ -80,22 +77,24 @@ class CMakeEmitter {
|
|||
}
|
||||
|
||||
static void emitOverallCMake() {
|
||||
const vl_unique_ptr<std::ofstream>
|
||||
of (V3File::new_ofstream(v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".cmake"));
|
||||
const vl_unique_ptr<std::ofstream> of(
|
||||
V3File::new_ofstream(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".cmake"));
|
||||
string name = v3Global.opt.prefix();
|
||||
|
||||
*of << "# Verilated -*- CMake -*-\n";
|
||||
*of << "# DESCR" "IPTION: Verilator output: CMake include script with class lists\n";
|
||||
*of << "# DESCR"
|
||||
"IPTION: Verilator output: CMake include script with class lists\n";
|
||||
*of << "#\n";
|
||||
*of << "# This CMake script lists generated Verilated files, for including in higher level CMake scripts.\n";
|
||||
*of << "# This CMake script lists generated Verilated files, for "
|
||||
"including in higher level CMake scripts.\n";
|
||||
*of << "# This file is meant to be consumed by the verilate() function,\n";
|
||||
*of << "# which becomes available after executing `find_package(verilator).\n";
|
||||
|
||||
*of << "\n### Constants...\n";
|
||||
cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()),
|
||||
"FILEPATH", "Perl executable (from $PERL)");
|
||||
cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()),
|
||||
"PATH", "Path to Verilator kit (from $VERILATOR_ROOT)");
|
||||
cmake_set(*of, "PERL", deslash(V3Options::getenvPERL()), "FILEPATH",
|
||||
"Perl executable (from $PERL)");
|
||||
cmake_set(*of, "VERILATOR_ROOT", deslash(V3Options::getenvVERILATOR_ROOT()), "PATH",
|
||||
"Path to Verilator kit (from $VERILATOR_ROOT)");
|
||||
|
||||
*of << "\n### Compiler flags...\n";
|
||||
|
||||
|
|
@ -110,13 +109,19 @@ class CMakeEmitter {
|
|||
*of << "# SystemC output mode? 0/1 (from --sc)\n";
|
||||
cmake_set_raw(*of, name + "_SC", v3Global.opt.systemC() ? "1" : "0");
|
||||
*of << "# Coverage output mode? 0/1 (from --coverage)\n";
|
||||
cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage()?"1":"0");
|
||||
cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0");
|
||||
*of << "# Threaded output mode? 0/1/N threads (from --threads)\n";
|
||||
cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads()));
|
||||
*of << "# VCD Tracing output mode? 0/1 (from --trace)\n";
|
||||
cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))?"1":"0");
|
||||
cmake_set_raw(*of, name + "_TRACE_VCD",
|
||||
(v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD))
|
||||
? "1"
|
||||
: "0");
|
||||
*of << "# FST Tracing output mode? 0/1 (from --fst-trace)\n";
|
||||
cmake_set_raw(*of, name + "_TRACE_FST", (v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD)) ? "1":"0");
|
||||
cmake_set_raw(*of, name + "_TRACE_FST",
|
||||
(v3Global.opt.trace() && (v3Global.opt.traceFormat() != TraceFormat::VCD))
|
||||
? "1"
|
||||
: "0");
|
||||
|
||||
*of << "\n### Sources...\n";
|
||||
std::vector<string> classes_fast, classes_slow, support_fast, support_slow, global;
|
||||
|
|
@ -141,7 +146,7 @@ class CMakeEmitter {
|
|||
}
|
||||
|
||||
global.push_back("${VERILATOR_ROOT}/include/verilated.cpp");
|
||||
if (v3Global.dpi()) {
|
||||
if (v3Global.dpi()) { //
|
||||
global.push_back("${VERILATOR_ROOT}/include/verilated_dpi.cpp");
|
||||
}
|
||||
if (v3Global.opt.vpi()) {
|
||||
|
|
@ -154,21 +159,22 @@ class CMakeEmitter {
|
|||
global.push_back("${VERILATOR_ROOT}/include/verilated_cov.cpp");
|
||||
}
|
||||
if (v3Global.opt.trace()) {
|
||||
global.push_back("${VERILATOR_ROOT}/include/"
|
||||
+ v3Global.opt.traceSourceBase() + "_c.cpp");
|
||||
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase()
|
||||
+ "_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
|
||||
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
|
||||
v3error("Unsupported: This trace format is not supported in SystemC, "
|
||||
"use VCD format.");
|
||||
}
|
||||
global.push_back("${VERILATOR_ROOT}/include/"
|
||||
+ v3Global.opt.traceSourceLang() + ".cpp");
|
||||
global.push_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang()
|
||||
+ ".cpp");
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.mtasks()) {
|
||||
global.push_back("${VERILATOR_ROOT}/include/verilated_threads.cpp");
|
||||
}
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
global.push_back(v3Global.opt.makeDir()+"/"+v3Global.opt.protectLib()+".cpp");
|
||||
global.push_back(v3Global.opt.makeDir() + "/" + v3Global.opt.protectLib() + ".cpp");
|
||||
}
|
||||
|
||||
*of << "# Global classes, need linked once per executable\n";
|
||||
|
|
@ -177,7 +183,8 @@ class CMakeEmitter {
|
|||
cmake_set_raw(*of, name + "_CLASSES_SLOW", deslash(cmake_list(classes_slow)));
|
||||
*of << "# Generated module classes, fast-path, compile with highest optimization\n";
|
||||
cmake_set_raw(*of, name + "_CLASSES_FAST", deslash(cmake_list(classes_fast)));
|
||||
*of << "# Generated support classes, non-fast-path, compile with low/medium optimization\n";
|
||||
*of << "# Generated support classes, non-fast-path, compile with "
|
||||
"low/medium optimization\n";
|
||||
cmake_set_raw(*of, name + "_SUPPORT_SLOW", deslash(cmake_list(support_slow)));
|
||||
*of << "# Generated support classes, fast-path, compile with highest optimization\n";
|
||||
cmake_set_raw(*of, name + "_SUPPORT_FAST", deslash(cmake_list(support_fast)));
|
||||
|
|
@ -188,14 +195,13 @@ class CMakeEmitter {
|
|||
*of << "# User .cpp files (from .cpp's on Verilator command line)\n";
|
||||
cmake_set_raw(*of, name + "_USER_CLASSES", deslash(cmake_list(v3Global.opt.cppFiles())));
|
||||
}
|
||||
|
||||
public:
|
||||
explicit CMakeEmitter() {
|
||||
emitOverallCMake();
|
||||
}
|
||||
explicit CMakeEmitter() { emitOverallCMake(); }
|
||||
virtual ~CMakeEmitter() {}
|
||||
};
|
||||
|
||||
void V3EmitCMake::emit() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
CMakeEmitter emitter;
|
||||
}
|
||||
|
|
|
|||
174
src/V3EmitMk.cpp
174
src/V3EmitMk.cpp
|
|
@ -27,87 +27,91 @@
|
|||
|
||||
class EmitMk {
|
||||
public:
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void putMakeClassEntry(V3OutMkFile& of, const string& name) {
|
||||
of.puts("\t"+V3Os::filenameNonDirExt(name)+" \\\n");
|
||||
of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n");
|
||||
}
|
||||
|
||||
void emitClassMake() {
|
||||
// Generate the makefile
|
||||
V3OutMkFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_classes.mk");
|
||||
V3OutMkFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_classes.mk");
|
||||
of.putsHeader();
|
||||
of.puts("# DESCR" "IPTION: Verilator output: Make include file with class lists\n");
|
||||
of.puts("# DESCR"
|
||||
"IPTION: Verilator output: Make include file with class lists\n");
|
||||
of.puts("#\n");
|
||||
of.puts("# This file lists generated Verilated files, for including in higher level makefiles.\n");
|
||||
of.puts("# See "+v3Global.opt.prefix()+".mk"+" for the caller.\n");
|
||||
of.puts("# This file lists generated Verilated files, for including "
|
||||
"in higher level makefiles.\n");
|
||||
of.puts("# See " + v3Global.opt.prefix() + ".mk" + " for the caller.\n");
|
||||
|
||||
of.puts("\n### Switches...\n");
|
||||
of.puts("# C11 constructs required? 0/1 (from --threads or use of classes)\n");
|
||||
of.puts("VM_C11 = " + cvtToStr(v3Global.needC11() || v3Global.opt.threads()) + "\n");
|
||||
of.puts("# Coverage output mode? 0/1 (from --coverage)\n");
|
||||
of.puts("VM_COVERAGE = "); of.puts(v3Global.opt.coverage()?"1":"0"); of.puts("\n");
|
||||
of.puts("VM_COVERAGE = ");
|
||||
of.puts(v3Global.opt.coverage() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Parallel builds? 0/1 (from --output-split)\n");
|
||||
of.puts("VM_PARALLEL_BUILDS = ");
|
||||
of.puts(v3Global.opt.outputSplit() ? "1" : "0"); of.puts("\n");
|
||||
of.puts(v3Global.opt.outputSplit() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Threaded output mode? 0/1/N threads (from --threads)\n");
|
||||
of.puts("VM_THREADS = "); of.puts(cvtToStr(v3Global.opt.threads())); of.puts("\n");
|
||||
of.puts("VM_THREADS = ");
|
||||
of.puts(cvtToStr(v3Global.opt.threads()));
|
||||
of.puts("\n");
|
||||
of.puts("# Tracing output mode? 0/1 (from --trace)\n");
|
||||
of.puts("VM_TRACE = "); of.puts(v3Global.opt.trace()?"1":"0"); of.puts("\n");
|
||||
of.puts("VM_TRACE = ");
|
||||
of.puts(v3Global.opt.trace() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
of.puts("# Tracing threaded output mode? 0/1 (from --trace-fst-thread)\n");
|
||||
of.puts("VM_TRACE_THREADED = "); of.puts(v3Global.opt.traceFormat().threaded()
|
||||
?"1":"0"); of.puts("\n");
|
||||
of.puts("VM_TRACE_THREADED = ");
|
||||
of.puts(v3Global.opt.traceFormat().threaded() ? "1" : "0");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("\n### Object file lists...\n");
|
||||
for (int support=0; support<3; ++support) {
|
||||
for (int slow=0; slow<2; ++slow) {
|
||||
if (support==2) of.puts("# Global classes, need linked once per executable");
|
||||
else if (support) of.puts("# Generated support classes");
|
||||
else of.puts("# Generated module classes");
|
||||
if (slow) of.puts(", non-fast-path, compile with low/medium optimization\n");
|
||||
else of.puts(", fast-path, compile with highest optimization\n");
|
||||
of.puts(support==2?"VM_GLOBAL":support==1?"VM_SUPPORT":"VM_CLASSES");
|
||||
of.puts(slow?"_SLOW":"_FAST");
|
||||
for (int support = 0; support < 3; ++support) {
|
||||
for (int slow = 0; slow < 2; ++slow) {
|
||||
if (support == 2) {
|
||||
of.puts("# Global classes, need linked once per executable");
|
||||
} else if (support) {
|
||||
of.puts("# Generated support classes");
|
||||
} else {
|
||||
of.puts("# Generated module classes");
|
||||
}
|
||||
if (slow) {
|
||||
of.puts(", non-fast-path, compile with low/medium optimization\n");
|
||||
} else {
|
||||
of.puts(", fast-path, compile with highest optimization\n");
|
||||
}
|
||||
of.puts(support == 2 ? "VM_GLOBAL" : support == 1 ? "VM_SUPPORT" : "VM_CLASSES");
|
||||
of.puts(slow ? "_SLOW" : "_FAST");
|
||||
of.puts(" += \\\n");
|
||||
if (support==2 && !slow) {
|
||||
if (support == 2 && !slow) {
|
||||
putMakeClassEntry(of, "verilated.cpp");
|
||||
if (v3Global.dpi()) {
|
||||
putMakeClassEntry(of, "verilated_dpi.cpp");
|
||||
}
|
||||
if (v3Global.opt.vpi()) {
|
||||
putMakeClassEntry(of, "verilated_vpi.cpp");
|
||||
}
|
||||
if (v3Global.opt.savable()) {
|
||||
putMakeClassEntry(of, "verilated_save.cpp");
|
||||
}
|
||||
if (v3Global.opt.coverage()) {
|
||||
putMakeClassEntry(of, "verilated_cov.cpp");
|
||||
}
|
||||
if (v3Global.dpi()) { putMakeClassEntry(of, "verilated_dpi.cpp"); }
|
||||
if (v3Global.opt.vpi()) { putMakeClassEntry(of, "verilated_vpi.cpp"); }
|
||||
if (v3Global.opt.savable()) { putMakeClassEntry(of, "verilated_save.cpp"); }
|
||||
if (v3Global.opt.coverage()) { putMakeClassEntry(of, "verilated_cov.cpp"); }
|
||||
if (v3Global.opt.trace()) {
|
||||
putMakeClassEntry(of, v3Global.opt.traceSourceBase() + "_c.cpp");
|
||||
if (v3Global.opt.systemC()) {
|
||||
if (v3Global.opt.traceFormat() != TraceFormat::VCD) {
|
||||
v3error("Unsupported: This trace format is not supported in SystemC, use VCD format.");
|
||||
v3error("Unsupported: This trace format is not supported "
|
||||
"in SystemC, use VCD format.");
|
||||
} else {
|
||||
putMakeClassEntry(of, v3Global.opt.traceSourceLang() + ".cpp");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.mtasks()) {
|
||||
putMakeClassEntry(of, "verilated_threads.cpp");
|
||||
}
|
||||
}
|
||||
else if (support==2 && slow) {
|
||||
}
|
||||
else {
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp();
|
||||
nodep; nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
if (v3Global.opt.mtasks()) { putMakeClassEntry(of, "verilated_threads.cpp"); }
|
||||
} else if (support == 2 && slow) {
|
||||
} else {
|
||||
for (AstNodeFile* nodep = v3Global.rootp()->filesp(); nodep;
|
||||
nodep = VN_CAST(nodep->nextp(), NodeFile)) {
|
||||
AstCFile* cfilep = VN_CAST(nodep, CFile);
|
||||
if (cfilep && cfilep->source()
|
||||
&& cfilep->slow()==(slow!=0)
|
||||
&& cfilep->support()==(support!=0)) {
|
||||
if (cfilep && cfilep->source() && cfilep->slow() == (slow != 0)
|
||||
&& cfilep->support() == (support != 0)) {
|
||||
putMakeClassEntry(of, cfilep->name());
|
||||
}
|
||||
}
|
||||
|
|
@ -122,55 +126,56 @@ public:
|
|||
|
||||
void emitOverallMake() {
|
||||
// Generate the makefile
|
||||
V3OutMkFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".mk");
|
||||
V3OutMkFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".mk");
|
||||
of.putsHeader();
|
||||
of.puts("# DESCR" "IPTION: Verilator output: Makefile for building Verilated archive or executable\n");
|
||||
of.puts("# DESCR"
|
||||
"IPTION: Verilator output: "
|
||||
"Makefile for building Verilated archive or executable\n");
|
||||
of.puts("#\n");
|
||||
of.puts("# Execute this makefile from the object directory:\n");
|
||||
of.puts("# make -f "+v3Global.opt.prefix()+".mk"+"\n");
|
||||
of.puts("# make -f " + v3Global.opt.prefix() + ".mk" + "\n");
|
||||
of.puts("\n");
|
||||
|
||||
if (v3Global.opt.exe()) {
|
||||
of.puts("default: "+v3Global.opt.exeName()+"\n");
|
||||
of.puts("default: " + v3Global.opt.exeName() + "\n");
|
||||
} else if (!v3Global.opt.protectLib().empty()) {
|
||||
of.puts("default: lib"+v3Global.opt.protectLib()+"\n");
|
||||
of.puts("default: lib" + v3Global.opt.protectLib() + "\n");
|
||||
} else {
|
||||
of.puts("default: "+v3Global.opt.prefix()+"__ALL.a\n");
|
||||
of.puts("default: " + v3Global.opt.prefix() + "__ALL.a\n");
|
||||
}
|
||||
of.puts("\n### Constants...\n");
|
||||
of.puts("# Perl executable (from $PERL)\n");
|
||||
of.puts("PERL = "+V3Options::getenvPERL()+"\n");
|
||||
of.puts("PERL = " + V3Options::getenvPERL() + "\n");
|
||||
of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n");
|
||||
of.puts("VERILATOR_ROOT = "+V3Options::getenvVERILATOR_ROOT()+"\n");
|
||||
of.puts("VERILATOR_ROOT = " + V3Options::getenvVERILATOR_ROOT() + "\n");
|
||||
of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n");
|
||||
of.puts(string("SYSTEMC_INCLUDE ?= ")+V3Options::getenvSYSTEMC_INCLUDE()+"\n");
|
||||
of.puts(string("SYSTEMC_INCLUDE ?= ") + V3Options::getenvSYSTEMC_INCLUDE() + "\n");
|
||||
of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n");
|
||||
of.puts(string("SYSTEMC_LIBDIR ?= ")+V3Options::getenvSYSTEMC_LIBDIR()+"\n");
|
||||
of.puts(string("SYSTEMC_LIBDIR ?= ") + V3Options::getenvSYSTEMC_LIBDIR() + "\n");
|
||||
|
||||
of.puts("\n### Switches...\n");
|
||||
of.puts("# SystemC output mode? 0/1 (from --sc)\n");
|
||||
of.puts(string("VM_SC = ")+((v3Global.opt.systemC())?"1":"0")+"\n");
|
||||
of.puts(string("VM_SC = ") + ((v3Global.opt.systemC()) ? "1" : "0") + "\n");
|
||||
of.puts("# Legacy or SystemC output mode? 0/1 (from --sc)\n");
|
||||
of.puts(string("VM_SP_OR_SC = $(VM_SC)\n"));
|
||||
of.puts("# Deprecated\n");
|
||||
of.puts(string("VM_PCLI = ")+(v3Global.opt.systemC()?"0":"1")+"\n");
|
||||
of.puts("# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n");
|
||||
of.puts(string("VM_SC_TARGET_ARCH = ")+V3Options::getenvSYSTEMC_ARCH()+"\n");
|
||||
of.puts(string("VM_PCLI = ") + (v3Global.opt.systemC() ? "0" : "1") + "\n");
|
||||
of.puts(
|
||||
"# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n");
|
||||
of.puts(string("VM_SC_TARGET_ARCH = ") + V3Options::getenvSYSTEMC_ARCH() + "\n");
|
||||
|
||||
of.puts("\n### Vars...\n");
|
||||
of.puts("# Design prefix (from --prefix)\n");
|
||||
of.puts(string("VM_PREFIX = ")+v3Global.opt.prefix()+"\n");
|
||||
of.puts(string("VM_PREFIX = ") + v3Global.opt.prefix() + "\n");
|
||||
of.puts("# Module prefix (from --prefix)\n");
|
||||
of.puts(string("VM_MODPREFIX = ")+v3Global.opt.modPrefix()+"\n");
|
||||
of.puts(string("VM_MODPREFIX = ") + v3Global.opt.modPrefix() + "\n");
|
||||
|
||||
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
|
||||
of.puts("VM_USER_CFLAGS = \\\n");
|
||||
if (!v3Global.opt.protectLib().empty()) {
|
||||
of.puts("\t-fPIC \\\n");
|
||||
}
|
||||
if (!v3Global.opt.protectLib().empty()) of.puts("\t-fPIC \\\n");
|
||||
const V3StringList& cFlags = v3Global.opt.cFlags();
|
||||
for (V3StringList::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
|
||||
of.puts("\t"+*it+" \\\n");
|
||||
of.puts("\t" + *it + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
|
||||
|
|
@ -178,7 +183,7 @@ public:
|
|||
of.puts("VM_USER_LDLIBS = \\\n");
|
||||
const V3StringList& ldLibs = v3Global.opt.ldLibs();
|
||||
for (V3StringList::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) {
|
||||
of.puts("\t"+*it+" \\\n");
|
||||
of.puts("\t" + *it + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
|
||||
|
|
@ -188,7 +193,7 @@ public:
|
|||
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
|
||||
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
|
||||
string cppfile = *it;
|
||||
of.puts("\t"+V3Os::filenameNonExt(cppfile)+" \\\n");
|
||||
of.puts("\t" + V3Os::filenameNonExt(cppfile) + " \\\n");
|
||||
string dir = V3Os::filenameDir(cppfile);
|
||||
dirs.insert(dir);
|
||||
}
|
||||
|
|
@ -196,14 +201,14 @@ public:
|
|||
|
||||
of.puts("# User .cpp directories (from .cpp's on Verilator command line)\n");
|
||||
of.puts("VM_USER_DIR = \\\n");
|
||||
for (V3StringSet::iterator it = dirs.begin(); it!=dirs.end(); ++it) {
|
||||
of.puts("\t"+*it+" \\\n");
|
||||
for (V3StringSet::iterator it = dirs.begin(); it != dirs.end(); ++it) {
|
||||
of.puts("\t" + *it + " \\\n");
|
||||
}
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("\n### Default rules...\n");
|
||||
of.puts("# Include list of all generated classes\n");
|
||||
of.puts("include "+v3Global.opt.prefix()+"_classes.mk\n");
|
||||
of.puts("include " + v3Global.opt.prefix() + "_classes.mk\n");
|
||||
of.puts("# Include global rules\n");
|
||||
of.puts("include $(VERILATOR_ROOT)/include/verilated.mk\n");
|
||||
|
||||
|
|
@ -215,12 +220,13 @@ public:
|
|||
string cppfile = *it;
|
||||
string basename = V3Os::filenameNonExt(cppfile);
|
||||
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
||||
of.puts(basename+".o: "+cppfile+"\n");
|
||||
of.puts(basename + ".o: " + cppfile + "\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<\n");
|
||||
}
|
||||
|
||||
of.puts("\n### Link rules... (from --exe)\n");
|
||||
of.puts(v3Global.opt.exeName()+": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n");
|
||||
of.puts(v3Global.opt.exeName()
|
||||
+ ": $(VK_USER_OBJS) $(VK_GLOBAL_OBJS) $(VM_PREFIX)__ALL.a\n");
|
||||
of.puts("\t$(LINK) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@ $(LIBS) $(SC_LIBS)\n");
|
||||
of.puts("\n");
|
||||
}
|
||||
|
|
@ -229,18 +235,20 @@ public:
|
|||
of.puts("\n### Library rules... (from --protect-lib)\n");
|
||||
of.puts("# Using -fPIC objects for both static and dynamic libraries "
|
||||
"(which appears to work)\n");
|
||||
of.puts(v3Global.opt.protectLibName(false)+": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o "+
|
||||
v3Global.opt.protectLib()+".o "+v3Global.opt.protectLib()+".cpp\n");
|
||||
of.puts("\tar rc $@ $^ "+v3Global.opt.protectLib()+".o\n");
|
||||
of.puts(v3Global.opt.protectLibName(false) + ": $(VK_OBJS) $(VK_GLOBAL_OBJS)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o "
|
||||
+ v3Global.opt.protectLib() + ".o " + v3Global.opt.protectLib() + ".cpp\n");
|
||||
of.puts("\tar rc $@ $^ " + v3Global.opt.protectLib() + ".o\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts(v3Global.opt.protectLibName(true)+": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ "+v3Global.opt.protectLib()+".cpp $^\n");
|
||||
of.puts(v3Global.opt.protectLibName(true)
|
||||
+ ": $(VM_PREFIX)__ALL.a $(VK_GLOBAL_OBJS)\n");
|
||||
of.puts("\t$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -shared -o $@ "
|
||||
+ v3Global.opt.protectLib() + ".cpp $^\n");
|
||||
of.puts("\n");
|
||||
|
||||
of.puts("lib"+v3Global.opt.protectLib()+": "+v3Global.opt.protectLibName(false)+
|
||||
" "+v3Global.opt.protectLibName(true)+"\n");
|
||||
of.puts("lib" + v3Global.opt.protectLib() + ": " + v3Global.opt.protectLibName(false)
|
||||
+ " " + v3Global.opt.protectLibName(true) + "\n");
|
||||
}
|
||||
|
||||
of.puts("\n");
|
||||
|
|
@ -259,6 +267,6 @@ public:
|
|||
// Gate class functions
|
||||
|
||||
void V3EmitMk::emitmk() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
EmitMk emitter;
|
||||
}
|
||||
|
|
|
|||
264
src/V3EmitV.cpp
264
src/V3EmitV.cpp
|
|
@ -32,7 +32,7 @@
|
|||
|
||||
class EmitVBaseVisitor : public EmitCBaseVisitor {
|
||||
// MEMBERS
|
||||
bool m_suppressSemi;
|
||||
bool m_suppressSemi;
|
||||
AstSenTree* m_sensesp;
|
||||
|
||||
// METHODS
|
||||
|
|
@ -53,20 +53,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd() + " " + prefixNameProtect(nodep) + ";\n");
|
||||
iterateChildren(nodep);
|
||||
putqs(nodep, "end" + nodep->verilogKwd() + "\n");
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->isFunction() ? "function":"task");
|
||||
putfs(nodep, nodep->isFunction() ? "function" : "task");
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
puts(";\n");
|
||||
putqs(nodep, "begin\n"); // Only putfs the first time for each visitor; later for same node is putqs
|
||||
// Only putfs the first time for each visitor; later for same node is putqs
|
||||
putqs(nodep, "begin\n");
|
||||
iterateAndNextNull(nodep->stmtsp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
|
|
@ -75,7 +74,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
if (nodep->name() == "") {
|
||||
putbs("begin\n");
|
||||
} else {
|
||||
putbs("begin : "+nodep->name()+"\n");
|
||||
putbs("begin : " + nodep->name() + "\n");
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
puts("end\n");
|
||||
|
|
@ -92,23 +91,31 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "always ");
|
||||
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
|
||||
else iterateAndNextNull(nodep->sensesp());
|
||||
if (m_sensesp) {
|
||||
iterateAndNextNull(m_sensesp);
|
||||
} // In active
|
||||
else {
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
}
|
||||
putbs(" begin\n");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "/*verilator public_flat_rw ");
|
||||
if (m_sensesp) iterateAndNextNull(m_sensesp); // In active
|
||||
else iterateAndNextNull(nodep->sensesp());
|
||||
if (m_sensesp) {
|
||||
iterateAndNextNull(m_sensesp);
|
||||
} // In active
|
||||
else {
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
}
|
||||
putqs(nodep, " ");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "*/\n");
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
putfs(nodep, " "+nodep->verilogKwd()+" ");
|
||||
putfs(nodep, " " + nodep->verilogKwd() + " ");
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
|
|
@ -139,7 +146,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
// AstSenItem is called for dumping in isolation by V3Order
|
||||
putfs(nodep, "@(");
|
||||
for (AstNode* expp=nodep->sensesp(); expp; expp = expp->nextp()) {
|
||||
for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) {
|
||||
iterate(expp);
|
||||
if (expp->nextp()) putqs(expp->nextp(), " or ");
|
||||
}
|
||||
|
|
@ -178,13 +185,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
virtual void visit(AstCaseItem* nodep) VL_OVERRIDE {
|
||||
if (nodep->condsp()) {
|
||||
iterateAndNextNull(nodep->condsp());
|
||||
} else putbs("default");
|
||||
} else {
|
||||
putbs("default");
|
||||
}
|
||||
putfs(nodep, ": begin ");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
putqs(nodep, "end\n");
|
||||
}
|
||||
virtual void visit(AstComment* nodep) VL_OVERRIDE {
|
||||
puts(string("// ")+nodep->name()+"\n");
|
||||
puts(string("// ") + nodep->name() + "\n");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
|
||||
|
|
@ -195,20 +204,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
virtual void visit(AstCoverInc*) VL_OVERRIDE {} // N/A
|
||||
virtual void visit(AstCoverToggle*) VL_OVERRIDE {} // N/A
|
||||
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp,
|
||||
const string& text, AstNode* exprsp) {
|
||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
|
||||
AstNode* exprsp) {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
putbs(" (");
|
||||
if (fileOrStrgp) { iterateAndNextNull(fileOrStrgp); putbs(","); }
|
||||
if (fileOrStrgp) {
|
||||
iterateAndNextNull(fileOrStrgp);
|
||||
putbs(",");
|
||||
}
|
||||
putsQuoted(text);
|
||||
for (AstNode* expp=exprsp; expp; expp = expp->nextp()) {
|
||||
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
|
||||
puts(",");
|
||||
iterateAndNextNull(expp);
|
||||
}
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
|
||||
putbs("disable "+nodep->name()+";\n");
|
||||
putbs("disable " + nodep->name() + ";\n");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
visitNodeDisplay(nodep, nodep->filep(), nodep->fmtp()->text(), nodep->fmtp()->exprsp());
|
||||
|
|
@ -251,10 +263,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
||||
putbs("disable "+cvtToHex(nodep->labelp())+";\n");
|
||||
putbs("disable " + cvtToHex(nodep->labelp()) + ";\n");
|
||||
}
|
||||
virtual void visit(AstJumpLabel* nodep) VL_OVERRIDE {
|
||||
putbs("begin : "+cvtToHex(nodep)+"\n");
|
||||
putbs("begin : " + cvtToHex(nodep) + "\n");
|
||||
if (nodep->stmtsp()) iterateAndNextNull(nodep->stmtsp());
|
||||
puts("end\n");
|
||||
}
|
||||
|
|
@ -264,8 +276,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
if (nodep->filenamep()) iterateAndNextNull(nodep->filenamep());
|
||||
putbs(",");
|
||||
if (nodep->memp()) iterateAndNextNull(nodep->memp());
|
||||
if (nodep->lsbp()) { putbs(","); iterateAndNextNull(nodep->lsbp()); }
|
||||
if (nodep->msbp()) { putbs(","); iterateAndNextNull(nodep->msbp()); }
|
||||
if (nodep->lsbp()) {
|
||||
putbs(",");
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
}
|
||||
if (nodep->msbp()) {
|
||||
putbs(",");
|
||||
iterateAndNextNull(nodep->msbp());
|
||||
}
|
||||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstSysFuncAsTask* nodep) VL_OVERRIDE {
|
||||
|
|
@ -340,12 +358,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->lhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstStop* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$stop;\n");
|
||||
}
|
||||
virtual void visit(AstFinish* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$finish;\n");
|
||||
}
|
||||
virtual void visit(AstStop* nodep) VL_OVERRIDE { putfs(nodep, "$stop;\n"); }
|
||||
virtual void visit(AstFinish* nodep) VL_OVERRIDE { putfs(nodep, "$finish;\n"); }
|
||||
virtual void visit(AstNodeSimpleText* nodep) VL_OVERRIDE {
|
||||
if (nodep->tracking() || m_trackText) {
|
||||
puts(nodep->text());
|
||||
|
|
@ -360,8 +374,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
if (nodep->commas() && childp->nextp()) puts(", ");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {}
|
||||
virtual void visit(AstCStmt* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$_CSTMT(");
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
|
|
@ -384,8 +397,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
|
||||
// Operators
|
||||
virtual void emitVerilogFormat(AstNode* nodep, const string& format,
|
||||
AstNode* lhsp=NULL, AstNode* rhsp=NULL, AstNode* thsp=NULL) {
|
||||
virtual void emitVerilogFormat(AstNode* nodep, const string& format, AstNode* lhsp = NULL,
|
||||
AstNode* rhsp = NULL, AstNode* thsp = NULL) {
|
||||
// Look at emitVerilog() format for term/uni/dual/triops,
|
||||
// and write out appropriate text.
|
||||
// %f Potential fileline-if-change and line break
|
||||
|
|
@ -397,16 +410,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
bool inPct = false;
|
||||
putbs("");
|
||||
for (string::const_iterator pos = format.begin(); pos != format.end(); ++pos) {
|
||||
if (pos[0]=='%') {
|
||||
if (pos[0] == '%') {
|
||||
inPct = true;
|
||||
} else if (!inPct) { // Normal text
|
||||
string s; s+=pos[0]; puts(s);
|
||||
string s;
|
||||
s += pos[0];
|
||||
puts(s);
|
||||
} else { // Format character
|
||||
inPct = false;
|
||||
switch (*pos) {
|
||||
case '%': puts("%"); break;
|
||||
case 'f': putfs(nodep, ""); break;
|
||||
case 'k': putbs(""); break;
|
||||
case '%': puts("%"); break;
|
||||
case 'f': putfs(nodep, ""); break;
|
||||
case 'k': putbs(""); break;
|
||||
case 'l': {
|
||||
UASSERT_OBJ(lhsp, nodep, "emitVerilog() references undef node");
|
||||
iterateAndNextNull(lhsp);
|
||||
|
|
@ -427,9 +442,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->dtypep());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
nodep->v3fatalSrc("Unknown emitVerilog format code: %"<<pos[0]);
|
||||
break;
|
||||
default: nodep->v3fatalSrc("Unknown emitVerilog format code: %" << pos[0]); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -445,7 +458,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep) VL_OVERRIDE {
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(), nodep->thsp());
|
||||
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->lhsp(), nodep->rhsp(),
|
||||
nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstAttrOf* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "$_ATTROF(");
|
||||
|
|
@ -460,8 +474,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
putfs(nodep, "`{");
|
||||
int comma = 0;
|
||||
const AstInitArray::KeyItemMap& mapr = nodep->map();
|
||||
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin();
|
||||
it != mapr.end(); ++it) {
|
||||
for (AstInitArray::KeyItemMap::const_iterator it = mapr.begin(); it != mapr.end(); ++it) {
|
||||
if (comma++) putbs(", ");
|
||||
puts(cvtToStr(it->first));
|
||||
puts(":");
|
||||
|
|
@ -472,23 +485,31 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
putbs("(");
|
||||
iterateAndNextNull(nodep->condp()); putfs(nodep, " ? ");
|
||||
iterateAndNextNull(nodep->expr1p()); putbs(" : ");
|
||||
iterateAndNextNull(nodep->expr2p()); puts(")");
|
||||
iterateAndNextNull(nodep->condp());
|
||||
putfs(nodep, " ? ");
|
||||
iterateAndNextNull(nodep->expr1p());
|
||||
putbs(" : ");
|
||||
iterateAndNextNull(nodep->expr2p());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstRange* nodep) VL_OVERRIDE {
|
||||
puts("[");
|
||||
if (VN_IS(nodep->msbp(), Const) && VN_IS(nodep->lsbp(), Const)) {
|
||||
// Looks nicer if we print [1:0] rather than [32'sh1:32sh0]
|
||||
puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt())); puts(":");
|
||||
puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt())); puts("]");
|
||||
puts(cvtToStr(VN_CAST(nodep->leftp(), Const)->toSInt()));
|
||||
puts(":");
|
||||
puts(cvtToStr(VN_CAST(nodep->rightp(), Const)->toSInt()));
|
||||
puts("]");
|
||||
} else {
|
||||
iterateAndNextNull(nodep->leftp()); puts(":");
|
||||
iterateAndNextNull(nodep->rightp()); puts("]");
|
||||
iterateAndNextNull(nodep->leftp());
|
||||
puts(":");
|
||||
iterateAndNextNull(nodep->rightp());
|
||||
puts("]");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->fromp()); puts("[");
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
puts("[");
|
||||
if (VN_IS(nodep->lsbp(), Const)) {
|
||||
if (nodep->widthp()->isOne()) {
|
||||
if (VN_IS(nodep->lsbp(), Const)) {
|
||||
|
|
@ -498,14 +519,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
} else {
|
||||
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()
|
||||
+ VN_CAST(nodep->widthp(), Const)->toSInt()
|
||||
- 1));
|
||||
+ VN_CAST(nodep->widthp(), Const)->toSInt() - 1));
|
||||
puts(":");
|
||||
puts(cvtToStr(VN_CAST(nodep->lsbp(), Const)->toSInt()));
|
||||
}
|
||||
} else {
|
||||
iterateAndNextNull(nodep->lsbp()); putfs(nodep, "+:");
|
||||
iterateAndNextNull(nodep->widthp()); puts("]");
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
putfs(nodep, "+:");
|
||||
iterateAndNextNull(nodep->widthp());
|
||||
puts("]");
|
||||
}
|
||||
puts("]");
|
||||
}
|
||||
|
|
@ -515,15 +537,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
virtual void visit(AstTypedef* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "typedef ");
|
||||
iterateAndNextNull(nodep->dtypep()); puts(" ");
|
||||
iterateAndNextNull(nodep->dtypep());
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
puts(";\n");
|
||||
}
|
||||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->isSigned()) putfs(nodep, "signed ");
|
||||
putfs(nodep, nodep->prettyName());
|
||||
if (nodep->rangep()) { puts(" "); iterateAndNextNull(nodep->rangep()); puts(" "); }
|
||||
else if (nodep->isRanged()) { puts(" ["); puts(cvtToStr(nodep->msb())); puts(":0] "); }
|
||||
if (nodep->rangep()) {
|
||||
puts(" ");
|
||||
iterateAndNextNull(nodep->rangep());
|
||||
puts(" ");
|
||||
} else if (nodep->isRanged()) {
|
||||
puts(" [");
|
||||
puts(cvtToStr(nodep->msb()));
|
||||
puts(":0] ");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConstDType* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, "const ");
|
||||
|
|
@ -534,7 +564,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
iterateAndNextNull(nodep->rangep());
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
puts(nodep->verilogKwd()+" ");
|
||||
puts(nodep->verilogKwd() + " ");
|
||||
if (nodep->packed()) puts("packed ");
|
||||
puts("\n");
|
||||
iterateAndNextNull(nodep->membersp());
|
||||
|
|
@ -547,16 +577,18 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
puts("}");
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->dotted()!="") {
|
||||
putfs(nodep, nodep->dotted()); puts("."); puts(nodep->prettyName());
|
||||
} else { putfs(nodep, nodep->prettyName()); }
|
||||
if (nodep->dotted() != "") {
|
||||
putfs(nodep, nodep->dotted());
|
||||
puts(".");
|
||||
puts(nodep->prettyName());
|
||||
} else {
|
||||
putfs(nodep, nodep->prettyName());
|
||||
}
|
||||
puts("(");
|
||||
iterateAndNextNull(nodep->pinsp());
|
||||
puts(")");
|
||||
}
|
||||
virtual void visit(AstArg* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
}
|
||||
virtual void visit(AstArg* nodep) VL_OVERRIDE { iterateAndNextNull(nodep->exprp()); }
|
||||
// Terminals
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varScopep()) {
|
||||
|
|
@ -576,18 +608,19 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
}
|
||||
|
||||
// Just iterate
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
putfs(nodep, nodep->verilogKwd());
|
||||
puts(" ");
|
||||
iterate(nodep->dtypep()); puts(" ");
|
||||
iterate(nodep->dtypep());
|
||||
puts(" ");
|
||||
puts(nodep->prettyName());
|
||||
if (!m_suppressVarSemi) puts(";\n"); else puts("\n");
|
||||
if (!m_suppressVarSemi) {
|
||||
puts(";\n");
|
||||
} else {
|
||||
puts("\n");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
m_sensesp = nodep->sensesp();
|
||||
|
|
@ -603,15 +636,15 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
virtual void visit(AstCell*) VL_OVERRIDE {} // Handled outside the Visit class
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
puts(string("\n???? // ")+nodep->prettyTypeName()+"\n");
|
||||
puts(string("\n???? // ") + nodep->prettyTypeName() + "\n");
|
||||
iterateChildren(nodep);
|
||||
// Not v3fatalSrc so we keep processing
|
||||
nodep->v3error("Internal: Unknown node type reached emitter: "<<nodep->prettyTypeName());
|
||||
nodep->v3error("Internal: Unknown node type reached emitter: " << nodep->prettyTypeName());
|
||||
}
|
||||
|
||||
public:
|
||||
bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(AstSenTree* domainp=NULL) {
|
||||
bool m_suppressVarSemi; // Suppress emitting semicolon for AstVars
|
||||
explicit EmitVBaseVisitor(AstSenTree* domainp = NULL) {
|
||||
// Domain for printing one a ALWAYS under a ACTIVE
|
||||
m_suppressSemi = false;
|
||||
m_suppressVarSemi = false;
|
||||
|
|
@ -625,17 +658,18 @@ public:
|
|||
|
||||
class EmitVFileVisitor : public EmitVBaseVisitor {
|
||||
// MEMBERS
|
||||
V3OutFile* m_ofp;
|
||||
V3OutFile* m_ofp;
|
||||
// METHODS
|
||||
V3OutFile* ofp() const { return m_ofp; }
|
||||
V3OutFile* ofp() const { return m_ofp; }
|
||||
virtual void puts(const string& str) { ofp()->puts(str); }
|
||||
virtual void putbs(const string& str) { ofp()->putbs(str); }
|
||||
virtual void putfs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
|
||||
|
||||
public:
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText=false,
|
||||
bool suppressVarSemi=false) {
|
||||
EmitVFileVisitor(AstNode* nodep, V3OutFile* ofp, bool trackText = false,
|
||||
bool suppressVarSemi = false) {
|
||||
m_ofp = ofp;
|
||||
m_trackText = trackText;
|
||||
m_suppressVarSemi = suppressVarSemi;
|
||||
|
|
@ -649,13 +683,14 @@ public:
|
|||
|
||||
class EmitVStreamVisitor : public EmitVBaseVisitor {
|
||||
// MEMBERS
|
||||
std::ostream& m_os;
|
||||
std::ostream& m_os;
|
||||
// METHODS
|
||||
virtual void putsNoTracking(const string& str) { m_os<<str; }
|
||||
virtual void putsNoTracking(const string& str) { m_os << str; }
|
||||
virtual void puts(const string& str) { putsNoTracking(str); }
|
||||
virtual void putbs(const string& str) { puts(str); }
|
||||
virtual void putfs(AstNode*, const string& str) { putbs(str); }
|
||||
virtual void putqs(AstNode*, const string& str) { putbs(str); }
|
||||
|
||||
public:
|
||||
EmitVStreamVisitor(AstNode* nodep, std::ostream& os)
|
||||
: m_os(os) {
|
||||
|
|
@ -668,37 +703,41 @@ public:
|
|||
// Emit to a stream (perhaps stringstream)
|
||||
|
||||
class EmitVPrefixedFormatter : public V3OutFormatter {
|
||||
std::ostream& m_os;
|
||||
string m_prefix; // What to print at beginning of each line
|
||||
int m_flWidth; // Padding of fileline
|
||||
int m_column; // Rough location; need just zero or non-zero
|
||||
FileLine* m_prefixFl;
|
||||
std::ostream& m_os;
|
||||
string m_prefix; // What to print at beginning of each line
|
||||
int m_flWidth; // Padding of fileline
|
||||
int m_column; // Rough location; need just zero or non-zero
|
||||
FileLine* m_prefixFl;
|
||||
// METHODS
|
||||
virtual void putcOutput(char chr) {
|
||||
if (chr == '\n') {
|
||||
m_column = 0;
|
||||
m_os<<chr;
|
||||
m_os << chr;
|
||||
} else {
|
||||
if (m_column == 0) {
|
||||
m_column = 10;
|
||||
m_os<<m_prefixFl->ascii()+":";
|
||||
m_os<<V3OutFile::indentSpaces(m_flWidth-(m_prefixFl->ascii().length()+1));
|
||||
m_os<<" ";
|
||||
m_os<<m_prefix;
|
||||
m_os << m_prefixFl->ascii() + ":";
|
||||
m_os << V3OutFile::indentSpaces(m_flWidth - (m_prefixFl->ascii().length() + 1));
|
||||
m_os << " ";
|
||||
m_os << m_prefix;
|
||||
}
|
||||
m_column++;
|
||||
m_os<<chr;
|
||||
m_os << chr;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void prefixFl(FileLine* fl) { m_prefixFl = fl; }
|
||||
FileLine* prefixFl() const { return m_prefixFl; }
|
||||
int column() const { return m_column; }
|
||||
EmitVPrefixedFormatter(std::ostream& os, const string& prefix, int flWidth)
|
||||
: V3OutFormatter("__STREAM", V3OutFormatter::LA_VERILOG)
|
||||
, m_os(os), m_prefix(prefix), m_flWidth(flWidth) {
|
||||
, m_os(os)
|
||||
, m_prefix(prefix)
|
||||
, m_flWidth(flWidth) {
|
||||
m_column = 0;
|
||||
m_prefixFl = v3Global.rootp()->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
|
||||
m_prefixFl = v3Global.rootp()
|
||||
->fileline(); // NETLIST's fileline instead of NULL to avoid NULL checks
|
||||
}
|
||||
virtual ~EmitVPrefixedFormatter() {
|
||||
if (m_column) puts("\n");
|
||||
|
|
@ -707,7 +746,8 @@ public:
|
|||
|
||||
class EmitVPrefixedVisitor : public EmitVBaseVisitor {
|
||||
// MEMBERS
|
||||
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the inheritance is another unused V3OutFormatter)
|
||||
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the
|
||||
// inheritance is another unused V3OutFormatter)
|
||||
// METHODS
|
||||
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
|
||||
virtual void puts(const string& str) { m_formatter.puts(str); }
|
||||
|
|
@ -728,7 +768,8 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
|
|||
public:
|
||||
EmitVPrefixedVisitor(AstNode* nodep, std::ostream& os, const string& prefix, int flWidth,
|
||||
AstSenTree* domainp, bool user3mark)
|
||||
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth) {
|
||||
: EmitVBaseVisitor(domainp)
|
||||
, m_formatter(os, prefix, flWidth) {
|
||||
if (user3mark) { AstUser3InUse::check(); }
|
||||
iterate(nodep);
|
||||
}
|
||||
|
|
@ -739,13 +780,14 @@ public:
|
|||
// EmitV class functions
|
||||
|
||||
void V3EmitV::emitv() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
if (true) {
|
||||
// All-in-one file
|
||||
V3OutVFile of (v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__Vout.v");
|
||||
V3OutVFile of(v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__Vout.v");
|
||||
of.putsHeader();
|
||||
of.puts("# DESCR" "IPTION: Verilator output: Verilog representation of internal tree for debug\n");
|
||||
EmitVFileVisitor visitor (v3Global.rootp(), &of);
|
||||
of.puts("# DESCR"
|
||||
"IPTION: Verilator output: Verilog representation of internal tree for debug\n");
|
||||
EmitVFileVisitor visitor(v3Global.rootp(), &of);
|
||||
} else {
|
||||
// Process each module in turn
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp;
|
||||
|
|
@ -758,24 +800,22 @@ void V3EmitV::emitv() {
|
|||
}
|
||||
}
|
||||
|
||||
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) {
|
||||
EmitVStreamVisitor(nodep, os);
|
||||
}
|
||||
void V3EmitV::verilogForTree(AstNode* nodep, std::ostream& os) { EmitVStreamVisitor(nodep, os); }
|
||||
|
||||
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os,
|
||||
const string& prefix, int flWidth,
|
||||
AstSenTree* domainp, bool user3mark) {
|
||||
void V3EmitV::verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix,
|
||||
int flWidth, AstSenTree* domainp, bool user3mark) {
|
||||
EmitVPrefixedVisitor(nodep, os, prefix, flWidth, domainp, user3mark);
|
||||
}
|
||||
|
||||
void V3EmitV::emitvFiles() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
for (AstNodeFile* filep = v3Global.rootp()->filesp(); filep;
|
||||
filep = VN_CAST(filep->nextp(), NodeFile)) {
|
||||
AstVFile* vfilep = VN_CAST(filep, VFile);
|
||||
if (vfilep && vfilep->tblockp()) {
|
||||
V3OutVFile of(vfilep->name());
|
||||
of.puts("// DESCR" "IPTION: Verilator generated Verilog\n");
|
||||
of.puts("// DESCR"
|
||||
"IPTION: Verilator generated Verilog\n");
|
||||
EmitVFileVisitor visitor(vfilep->tblockp(), &of, true, true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,18 +33,18 @@
|
|||
|
||||
class EmitXmlFileVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// Entire netlist:
|
||||
// AstNode::user1 -> uint64_t, number to connect crossrefs
|
||||
|
||||
// MEMBERS
|
||||
V3OutFile* m_ofp;
|
||||
uint64_t m_id;
|
||||
V3OutFile* m_ofp;
|
||||
uint64_t m_id;
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// Outfile methods
|
||||
V3OutFile* ofp() const { return m_ofp; }
|
||||
V3OutFile* ofp() const { return m_ofp; }
|
||||
virtual void puts(const string& str) { ofp()->puts(str); }
|
||||
virtual void putbs(const string& str) { ofp()->putbs(str); }
|
||||
virtual void putfs(AstNode*, const string& str) { putbs(str); }
|
||||
|
|
@ -62,29 +62,42 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
// XML methods
|
||||
void outputId(AstNode* nodep) {
|
||||
if (!nodep->user1()) { nodep->user1(++m_id); }
|
||||
puts("\""+cvtToStr(nodep->user1())+"\"");
|
||||
puts("\"" + cvtToStr(nodep->user1()) + "\"");
|
||||
}
|
||||
void outputTag(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||
puts("<"+tag+" "+nodep->fileline()->xml());
|
||||
puts(" "+nodep->fileline()->xmlDetailedLocation());
|
||||
if (VN_IS(nodep, NodeDType)) { puts(" id="); outputId(nodep); }
|
||||
if (nodep->name()!="") { puts(" name="); putsQuoted(nodep->prettyName()); }
|
||||
if (nodep->tag()!="") { puts(" tag="); putsQuoted(nodep->tag()); }
|
||||
if (tag == "") tag = VString::downcase(nodep->typeName());
|
||||
puts("<" + tag + " " + nodep->fileline()->xml());
|
||||
puts(" " + nodep->fileline()->xmlDetailedLocation());
|
||||
if (VN_IS(nodep, NodeDType)) {
|
||||
puts(" id=");
|
||||
outputId(nodep);
|
||||
}
|
||||
if (nodep->name() != "") {
|
||||
puts(" name=");
|
||||
putsQuoted(nodep->prettyName());
|
||||
}
|
||||
if (nodep->tag() != "") {
|
||||
puts(" tag=");
|
||||
putsQuoted(nodep->tag());
|
||||
}
|
||||
if (AstNodeDType* dtp = VN_CAST(nodep, NodeDType)) {
|
||||
if (dtp->subDTypep()) {
|
||||
puts(" sub_dtype_id="); outputId(dtp->subDTypep()->skipRefp());
|
||||
puts(" sub_dtype_id=");
|
||||
outputId(dtp->subDTypep()->skipRefp());
|
||||
}
|
||||
} else {
|
||||
if (nodep->dtypep()) { puts(" dtype_id="); outputId(nodep->dtypep()->skipRefp()); }
|
||||
if (nodep->dtypep()) {
|
||||
puts(" dtype_id=");
|
||||
outputId(nodep->dtypep()->skipRefp());
|
||||
}
|
||||
}
|
||||
}
|
||||
void outputChildrenEnd(AstNode* nodep, string tag) {
|
||||
if (tag=="") tag = VString::downcase(nodep->typeName());
|
||||
if (tag == "") tag = VString::downcase(nodep->typeName());
|
||||
if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) {
|
||||
puts(">\n");
|
||||
iterateChildren(nodep);
|
||||
puts("</"+tag+">\n");
|
||||
puts("</" + tag + ">\n");
|
||||
} else {
|
||||
puts("/>\n");
|
||||
}
|
||||
|
|
@ -97,8 +110,10 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "instance"); // IEEE: vpiInstance
|
||||
puts(" defName="); putsQuoted(nodep->modName()); // IEEE vpiDefName
|
||||
puts(" origName="); putsQuoted(nodep->origName());
|
||||
puts(" defName=");
|
||||
putsQuoted(nodep->modName()); // IEEE vpiDefName
|
||||
puts(" origName=");
|
||||
putsQuoted(nodep->origName());
|
||||
outputChildrenEnd(nodep, "instance");
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
|
|
@ -108,8 +123,10 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" origName="); putsQuoted(nodep->origName());
|
||||
if (nodep->level()==1 || nodep->level()==2) // ==2 because we don't add wrapper when in XML mode
|
||||
puts(" origName=");
|
||||
putsQuoted(nodep->origName());
|
||||
if (nodep->level() == 1
|
||||
|| nodep->level() == 2) // ==2 because we don't add wrapper when in XML mode
|
||||
puts(" topModule=\"1\""); // IEEE vpiTopModule
|
||||
if (nodep->modPublic()) puts(" public=\"true\"");
|
||||
outputChildrenEnd(nodep, "");
|
||||
|
|
@ -120,13 +137,16 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
string vt = nodep->dtypep()->name();
|
||||
outputTag(nodep, "");
|
||||
if (nodep->isIO()) {
|
||||
puts(" dir="); putsQuoted(kw);
|
||||
puts(" vartype="); putsQuoted(!vt.empty()
|
||||
? vt : typ == AstVarType::PORT ? "port" : "unknown");
|
||||
puts(" dir=");
|
||||
putsQuoted(kw);
|
||||
puts(" vartype=");
|
||||
putsQuoted(!vt.empty() ? vt : typ == AstVarType::PORT ? "port" : "unknown");
|
||||
} else {
|
||||
puts(" vartype="); putsQuoted(!vt.empty() ? vt : kw);
|
||||
puts(" vartype=");
|
||||
putsQuoted(!vt.empty() ? vt : kw);
|
||||
}
|
||||
puts(" origName="); putsQuoted(nodep->origName());
|
||||
puts(" origName=");
|
||||
putsQuoted(nodep->origName());
|
||||
// Attributes
|
||||
if (nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES)
|
||||
puts(" clocker=\"true\"");
|
||||
|
|
@ -137,8 +157,10 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
if (nodep->isSigPublic()) puts(" public=\"true\"");
|
||||
if (nodep->isSigUserRdPublic()) puts(" public_flat_rd=\"true\"");
|
||||
if (nodep->isSigUserRWPublic()) puts(" public_flat_rw=\"true\"");
|
||||
if (nodep->isGParam()) puts(" param=\"true\"");
|
||||
else if (nodep->isParam()) puts(" localparam=\"true\"");
|
||||
if (nodep->isGParam())
|
||||
puts(" param=\"true\"");
|
||||
else if (nodep->isParam())
|
||||
puts(" localparam=\"true\"");
|
||||
if (nodep->attrScBv()) puts(" sc_bv=\"true\"");
|
||||
if (nodep->attrScClocked()) puts(" sc_clock=\"true\"");
|
||||
if (nodep->attrSFormat()) puts(" sformat=\"true\"");
|
||||
|
|
@ -148,27 +170,29 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
// What we call a pin in verilator is a port in the IEEE spec.
|
||||
outputTag(nodep, "port"); // IEEE: vpiPort
|
||||
if (nodep->modVarp()->isIO()) {
|
||||
puts(" direction=\""+nodep->modVarp()->direction().xmlKwd()+"\"");
|
||||
puts(" direction=\"" + nodep->modVarp()->direction().xmlKwd() + "\"");
|
||||
}
|
||||
puts(" portIndex=\""+cvtToStr(nodep->pinNum())+"\""); // IEEE: vpiPortIndex
|
||||
puts(" portIndex=\"" + cvtToStr(nodep->pinNum()) + "\""); // IEEE: vpiPortIndex
|
||||
// Children includes vpiHighConn and vpiLowConn; we don't support port bits (yet?)
|
||||
outputChildrenEnd(nodep, "port");
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" edgeType=\""+cvtToStr(nodep->edgeType().ascii())+"\""); // IEEE vpiTopModule
|
||||
puts(" edgeType=\"" + cvtToStr(nodep->edgeType().ascii()) + "\""); // IEEE vpiTopModule
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstModportVarRef* nodep) VL_OVERRIDE {
|
||||
// Dump direction for Modport references
|
||||
string kw = nodep->direction().xmlKwd();
|
||||
outputTag(nodep, "");
|
||||
puts(" direction="); putsQuoted(kw);
|
||||
puts(" direction=");
|
||||
putsQuoted(kw);
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" dotted="); putsQuoted(nodep->dotted());
|
||||
puts(" dotted=");
|
||||
putsQuoted(nodep->dotted());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
|
||||
|
|
@ -176,8 +200,8 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
virtual void visit(AstBasicDType* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "basicdtype");
|
||||
if (nodep->isRanged()) {
|
||||
puts(" left=\""+cvtToStr(nodep->left())+"\"");
|
||||
puts(" right=\""+cvtToStr(nodep->right())+"\"");
|
||||
puts(" left=\"" + cvtToStr(nodep->left()) + "\"");
|
||||
puts(" right=\"" + cvtToStr(nodep->right()) + "\"");
|
||||
}
|
||||
puts("/>\n");
|
||||
}
|
||||
|
|
@ -185,29 +209,36 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
string mpn;
|
||||
outputTag(nodep, "");
|
||||
if (nodep->isModport()) mpn = nodep->modportName();
|
||||
puts(" modportname="); putsQuoted(mpn);
|
||||
puts(" modportname=");
|
||||
putsQuoted(mpn);
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
|
||||
puts(" displaytype=");
|
||||
putsQuoted(nodep->verilogKwd());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstElabDisplay* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" displaytype="); putsQuoted(nodep->verilogKwd());
|
||||
puts(" displaytype=");
|
||||
putsQuoted(nodep->verilogKwd());
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstExtend* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
|
||||
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
puts(" width=");
|
||||
putsQuoted(cvtToStr(nodep->width()));
|
||||
puts(" widthminv=");
|
||||
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
virtual void visit(AstExtendS* nodep) VL_OVERRIDE {
|
||||
outputTag(nodep, "");
|
||||
puts(" width="); putsQuoted(cvtToStr(nodep->width()));
|
||||
puts(" widthminv="); putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
puts(" width=");
|
||||
putsQuoted(cvtToStr(nodep->width()));
|
||||
puts(" widthminv=");
|
||||
putsQuoted(cvtToStr(nodep->lhsp()->widthMinV()));
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +247,7 @@ class EmitXmlFileVisitor : public AstNVisitor {
|
|||
outputTag(nodep, "");
|
||||
outputChildrenEnd(nodep, "");
|
||||
}
|
||||
|
||||
public:
|
||||
EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) {
|
||||
m_ofp = ofp;
|
||||
|
|
@ -246,8 +278,7 @@ private:
|
|||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Only list modules and interfaces
|
||||
// Assumes modules and interfaces list is already sorted level wise
|
||||
if (!nodep->dead()
|
||||
&& (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
|
||||
if (!nodep->dead() && (VN_IS(nodep, Module) || VN_IS(nodep, Iface))
|
||||
&& m_modulesCovered.insert(nodep->fileline()->filename()).second) {
|
||||
m_nodeModules.push_front(nodep->fileline());
|
||||
}
|
||||
|
|
@ -260,18 +291,19 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
||||
: m_os(os), m_modulesCovered(), m_nodeModules() {
|
||||
: m_os(os)
|
||||
, m_modulesCovered()
|
||||
, m_nodeModules() {
|
||||
// Operate on whole netlist
|
||||
nodep->accept(*this);
|
||||
// Xml output
|
||||
m_os<<"<module_files>\n";
|
||||
for (std::deque<FileLine*>::iterator it = m_nodeModules.begin();
|
||||
it != m_nodeModules.end(); ++it) {
|
||||
m_os<<"<file id=\""<<(*it)->filenameLetters()
|
||||
<<"\" filename=\""<<(*it)->filename()
|
||||
<<"\" language=\""<<(*it)->language().ascii()<<"\"/>\n";
|
||||
m_os << "<module_files>\n";
|
||||
for (std::deque<FileLine*>::iterator it = m_nodeModules.begin(); it != m_nodeModules.end();
|
||||
++it) {
|
||||
m_os << "<file id=\"" << (*it)->filenameLetters() << "\" filename=\""
|
||||
<< (*it)->filename() << "\" language=\"" << (*it)->language().ascii() << "\"/>\n";
|
||||
}
|
||||
m_os<<"</module_files>\n";
|
||||
m_os << "</module_files>\n";
|
||||
}
|
||||
virtual ~ModuleFilesXmlVisitor() {}
|
||||
};
|
||||
|
|
@ -292,42 +324,38 @@ private:
|
|||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
if (nodep->level() >= 0
|
||||
&& nodep->level() <=2 ) { // ==2 because we don't add wrapper when in XML mode
|
||||
m_os<<"<cells>\n";
|
||||
m_os<<"<cell "<<nodep->fileline()->xml()
|
||||
<<" "<<nodep->fileline()->xmlDetailedLocation()
|
||||
<<" name=\""<<nodep->name()<<"\""
|
||||
<<" submodname=\""<<nodep->name()<<"\""
|
||||
<<" hier=\""<<nodep->name()<<"\"";
|
||||
&& nodep->level() <= 2) { // ==2 because we don't add wrapper when in XML mode
|
||||
m_os << "<cells>\n";
|
||||
m_os << "<cell " << nodep->fileline()->xml() << " "
|
||||
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
|
||||
<< " submodname=\"" << nodep->name() << "\""
|
||||
<< " hier=\"" << nodep->name() << "\"";
|
||||
m_hier = nodep->name() + ".";
|
||||
m_hasChildren = false;
|
||||
iterateChildren(nodep);
|
||||
if (m_hasChildren) {
|
||||
m_os<<"</cell>\n";
|
||||
m_os << "</cell>\n";
|
||||
} else {
|
||||
m_os<<"/>\n";
|
||||
m_os << "/>\n";
|
||||
}
|
||||
m_os<<"</cells>\n";
|
||||
m_os << "</cells>\n";
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
if (nodep->modp()->dead()) {
|
||||
return;
|
||||
}
|
||||
if (!m_hasChildren) m_os<<">\n";
|
||||
m_os<<"<cell "<<nodep->fileline()->xml()
|
||||
<<" "<<nodep->fileline()->xmlDetailedLocation()
|
||||
<<" name=\""<<nodep->name()<<"\""
|
||||
<<" submodname=\""<<nodep->modName()<<"\""
|
||||
<<" hier=\""<<m_hier+nodep->name()<<"\"";
|
||||
if (nodep->modp()->dead()) { return; }
|
||||
if (!m_hasChildren) m_os << ">\n";
|
||||
m_os << "<cell " << nodep->fileline()->xml() << " "
|
||||
<< nodep->fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() << "\""
|
||||
<< " submodname=\"" << nodep->modName() << "\""
|
||||
<< " hier=\"" << m_hier + nodep->name() << "\"";
|
||||
std::string hier = m_hier;
|
||||
m_hier += nodep->name() + ".";
|
||||
m_hasChildren = false;
|
||||
iterateChildren(nodep->modp());
|
||||
if (m_hasChildren) {
|
||||
m_os<<"</cell>\n";
|
||||
m_os << "</cell>\n";
|
||||
} else {
|
||||
m_os<<"/>\n";
|
||||
m_os << "/>\n";
|
||||
}
|
||||
m_hier = hier;
|
||||
m_hasChildren = true;
|
||||
|
|
@ -338,7 +366,9 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os)
|
||||
: m_os(os), m_hier(""), m_hasChildren(false) {
|
||||
: m_os(os)
|
||||
, m_hier("")
|
||||
, m_hasChildren(false) {
|
||||
// Operate on whole netlist
|
||||
nodep->accept(*this);
|
||||
}
|
||||
|
|
@ -349,14 +379,15 @@ public:
|
|||
// EmitXml class functions
|
||||
|
||||
void V3EmitXml::emitxml() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// All-in-one file
|
||||
string filename = (v3Global.opt.xmlOutput().empty()
|
||||
? v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+".xml"
|
||||
: v3Global.opt.xmlOutput());
|
||||
? v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + ".xml"
|
||||
: v3Global.opt.xmlOutput());
|
||||
V3OutXmlFile of(filename);
|
||||
of.putsHeader();
|
||||
of.puts("<!-- DESCR" "IPTION: Verilator output: XML representation of netlist -->\n");
|
||||
of.puts("<!-- DESCR"
|
||||
"IPTION: Verilator output: XML representation of netlist -->\n");
|
||||
of.puts("<verilator_xml>\n");
|
||||
{
|
||||
std::stringstream sstr;
|
||||
|
|
@ -365,10 +396,10 @@ void V3EmitXml::emitxml() {
|
|||
}
|
||||
{
|
||||
std::stringstream sstr;
|
||||
ModuleFilesXmlVisitor moduleFilesVisitor (v3Global.rootp(), sstr);
|
||||
HierCellsXmlVisitor cellsVisitor (v3Global.rootp(), sstr);
|
||||
ModuleFilesXmlVisitor moduleFilesVisitor(v3Global.rootp(), sstr);
|
||||
HierCellsXmlVisitor cellsVisitor(v3Global.rootp(), sstr);
|
||||
of.puts(sstr.str());
|
||||
}
|
||||
EmitXmlFileVisitor visitor (v3Global.rootp(), &of);
|
||||
EmitXmlFileVisitor visitor(v3Global.rootp(), &of);
|
||||
of.puts("</verilator_xml>\n");
|
||||
}
|
||||
|
|
|
|||
152
src/V3Error.cpp
152
src/V3Error.cpp
|
|
@ -14,12 +14,14 @@
|
|||
//
|
||||
//*************************************************************************
|
||||
|
||||
// clang-format off
|
||||
#include "V3Error.h"
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
# include "V3Ast.h"
|
||||
# include "V3Global.h"
|
||||
# include "V3Stats.h"
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#include <cstdarg>
|
||||
|
||||
|
|
@ -43,7 +45,7 @@ V3Error::MessagesSet V3Error::s_messages;
|
|||
V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
|
||||
|
||||
struct v3errorIniter {
|
||||
v3errorIniter() { V3Error::init(); }
|
||||
v3errorIniter() { V3Error::init(); }
|
||||
};
|
||||
v3errorIniter v3errorInit;
|
||||
|
||||
|
|
@ -52,10 +54,11 @@ v3errorIniter v3errorInit;
|
|||
|
||||
V3ErrorCode::V3ErrorCode(const char* msgp) {
|
||||
// Return error encoding for given string, or ERROR, which is a bad code
|
||||
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (0 == VL_STRCASECMP(msgp, code.ascii())) {
|
||||
m_e = code; return;
|
||||
m_e = code;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_e = V3ErrorCode::EC_ERROR;
|
||||
|
|
@ -65,7 +68,7 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
|
|||
// V3Error class functions
|
||||
|
||||
void V3Error::init() {
|
||||
for (int i=0; i<V3ErrorCode::_ENUM_MAX; i++) {
|
||||
for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) {
|
||||
s_describedEachWarn[i] = false;
|
||||
s_pretendError[i] = V3ErrorCode(i).pretendError();
|
||||
}
|
||||
|
|
@ -77,18 +80,19 @@ void V3Error::init() {
|
|||
string V3Error::lineStr(const char* filename, int lineno) {
|
||||
std::ostringstream out;
|
||||
const char* fnslashp = strrchr(filename, '/');
|
||||
if (fnslashp) filename = fnslashp+1;
|
||||
out<<filename<<":"<<std::dec<<lineno<<":";
|
||||
if (fnslashp) filename = fnslashp + 1;
|
||||
out << filename << ":" << std::dec << lineno << ":";
|
||||
const char* const spaces = " ";
|
||||
size_t numsp = out.str().length(); if (numsp>20) numsp = 20;
|
||||
out<<(spaces + numsp);
|
||||
size_t numsp = out.str().length();
|
||||
if (numsp > 20) numsp = 20;
|
||||
out << (spaces + numsp);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
void V3Error::incErrors() {
|
||||
s_errCount++;
|
||||
if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse
|
||||
v3fatalExit("Exiting due to too many errors encountered; --error-limit="
|
||||
v3fatalExit("Exiting due to too many errors encountered; --error-limit=" //
|
||||
<< errorCount() << endl);
|
||||
}
|
||||
}
|
||||
|
|
@ -96,8 +100,8 @@ void V3Error::incErrors() {
|
|||
void V3Error::abortIfWarnings() {
|
||||
bool exwarn = warnFatal() && warnCount();
|
||||
if (errorCount() && exwarn) {
|
||||
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), "
|
||||
<< warnCount() << " warning(s)\n");
|
||||
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " //
|
||||
<< warnCount() << " warning(s)\n");
|
||||
} else if (errorCount()) {
|
||||
v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n");
|
||||
} else if (exwarn) {
|
||||
|
|
@ -106,30 +110,49 @@ void V3Error::abortIfWarnings() {
|
|||
}
|
||||
|
||||
bool V3Error::isError(V3ErrorCode code, bool supp) {
|
||||
if (supp) return false;
|
||||
else if (code == V3ErrorCode::USERINFO) return false;
|
||||
else if (code == V3ErrorCode::EC_INFO) return false;
|
||||
else if (code == V3ErrorCode::EC_FATAL) return true;
|
||||
else if (code == V3ErrorCode::EC_FATALEXIT) return true;
|
||||
else if (code == V3ErrorCode::EC_FATALSRC) return true;
|
||||
else if (code == V3ErrorCode::EC_ERROR) return true;
|
||||
else if (code < V3ErrorCode::EC_FIRST_WARN
|
||||
|| s_pretendError[code]) return true;
|
||||
else return false;
|
||||
if (supp) {
|
||||
return false;
|
||||
} else if (code == V3ErrorCode::USERINFO) {
|
||||
return false;
|
||||
} else if (code == V3ErrorCode::EC_INFO) {
|
||||
return false;
|
||||
} else if (code == V3ErrorCode::EC_FATAL) {
|
||||
return true;
|
||||
} else if (code == V3ErrorCode::EC_FATALEXIT) {
|
||||
return true;
|
||||
} else if (code == V3ErrorCode::EC_FATALSRC) {
|
||||
return true;
|
||||
} else if (code == V3ErrorCode::EC_ERROR) {
|
||||
return true;
|
||||
} else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string V3Error::msgPrefix() {
|
||||
V3ErrorCode code = s_errorCode;
|
||||
bool supp = s_errorSuppressed;
|
||||
if (supp) return "-arning-suppressed: ";
|
||||
else if (code == V3ErrorCode::USERINFO) return "-Info: ";
|
||||
else if (code == V3ErrorCode::EC_INFO) return "-Info: ";
|
||||
else if (code == V3ErrorCode::EC_FATAL) return "%Error: ";
|
||||
else if (code == V3ErrorCode::EC_FATALEXIT) return "%Error: ";
|
||||
else if (code == V3ErrorCode::EC_FATALSRC) return "%Error: Internal Error: ";
|
||||
else if (code == V3ErrorCode::EC_ERROR) return "%Error: ";
|
||||
else if (isError(code, supp)) return "%Error-"+string(code.ascii())+": ";
|
||||
else return "%Warning-"+string(code.ascii())+": ";
|
||||
if (supp) {
|
||||
return "-arning-suppressed: ";
|
||||
} else if (code == V3ErrorCode::USERINFO) {
|
||||
return "-Info: ";
|
||||
} else if (code == V3ErrorCode::EC_INFO) {
|
||||
return "-Info: ";
|
||||
} else if (code == V3ErrorCode::EC_FATAL) {
|
||||
return "%Error: ";
|
||||
} else if (code == V3ErrorCode::EC_FATALEXIT) {
|
||||
return "%Error: ";
|
||||
} else if (code == V3ErrorCode::EC_FATALSRC) {
|
||||
return "%Error: Internal Error: ";
|
||||
} else if (code == V3ErrorCode::EC_ERROR) {
|
||||
return "%Error: ";
|
||||
} else if (isError(code, supp)) {
|
||||
return "%Error-" + string(code.ascii()) + ": ";
|
||||
} else {
|
||||
return "%Warning-" + string(code.ascii()) + ": ";
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
|
@ -137,7 +160,7 @@ string V3Error::msgPrefix() {
|
|||
|
||||
void V3Error::vlAbort() {
|
||||
if (V3Error::debugDefault()) {
|
||||
std::cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
|
||||
std::cerr << msgPrefix() << "Aborting since under --debug" << endl;
|
||||
abort();
|
||||
} else {
|
||||
exit(1);
|
||||
|
|
@ -148,31 +171,30 @@ void V3Error::vlAbort() {
|
|||
// Global Functions
|
||||
|
||||
void V3Error::suppressThisWarning() {
|
||||
if (s_errorCode>=V3ErrorCode::EC_MIN) {
|
||||
if (s_errorCode >= V3ErrorCode::EC_MIN) {
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1);
|
||||
V3Stats::addStatSum(string("Warnings, Suppressed ") + s_errorCode.ascii(), 1);
|
||||
#endif
|
||||
s_errorSuppressed = true;
|
||||
}
|
||||
}
|
||||
|
||||
string V3Error::warnMore() {
|
||||
return string(msgPrefix().size(), ' ');
|
||||
}
|
||||
string V3Error::warnMore() { return string(msgPrefix().size(), ' '); }
|
||||
|
||||
void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
||||
#if defined(__COVERITY__) || defined(__cppcheck__)
|
||||
if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
||||
if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x);
|
||||
#endif
|
||||
// Skip suppressed messages
|
||||
if (s_errorSuppressed
|
||||
// On debug, show only non default-off warning to prevent pages of warnings
|
||||
&& (!debug() || s_errorCode.defaultsOff())) return;
|
||||
string msg = msgPrefix()+sstr.str();
|
||||
&& (!debug() || s_errorCode.defaultsOff()))
|
||||
return;
|
||||
string msg = msgPrefix() + sstr.str();
|
||||
if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity
|
||||
string::size_type pos;
|
||||
if ((pos = msg.find('\n')) != string::npos) {
|
||||
msg.erase(pos, msg.length()-pos);
|
||||
msg.erase(pos, msg.length() - pos);
|
||||
msg += "...";
|
||||
}
|
||||
}
|
||||
|
|
@ -180,15 +202,13 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
|||
{
|
||||
msg += '\n'; // Trailing newlines generally not put on messages so add
|
||||
string::size_type pos;
|
||||
while ((pos = msg.find("\n\n")) != string::npos) {
|
||||
msg.erase(pos+1, 1);
|
||||
}
|
||||
while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1);
|
||||
}
|
||||
// Suppress duplicate messages
|
||||
if (s_messages.find(msg) != s_messages.end()) return;
|
||||
s_messages.insert(msg);
|
||||
if (!locationStr.empty()) {
|
||||
string locationMsg = warnMore()+locationStr+"\n";
|
||||
string locationMsg = warnMore() + locationStr + "\n";
|
||||
size_t pos = msg.find("\n");
|
||||
msg.insert(pos + 1, locationMsg);
|
||||
}
|
||||
|
|
@ -199,44 +219,49 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
|||
#else
|
||||
true
|
||||
#endif
|
||||
) {
|
||||
) {
|
||||
std::cerr << msg;
|
||||
}
|
||||
if (!s_errorSuppressed && !(s_errorCode==V3ErrorCode::EC_INFO
|
||||
|| s_errorCode==V3ErrorCode::USERINFO)) {
|
||||
if (!s_describedEachWarn[s_errorCode]
|
||||
&& !s_pretendError[s_errorCode]) {
|
||||
if (!s_errorSuppressed
|
||||
&& !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) {
|
||||
if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) {
|
||||
s_describedEachWarn[s_errorCode] = true;
|
||||
if (s_errorCode>=V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
|
||||
std::cerr<<warnMore()<<"... Use \"/* verilator lint_off "<<s_errorCode.ascii()
|
||||
<<" */\" and lint_on around source to disable this message."<<endl;
|
||||
if (s_errorCode >= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
|
||||
std::cerr << warnMore() << "... Use \"/* verilator lint_off "
|
||||
<< s_errorCode.ascii()
|
||||
<< " */\" and lint_on around source to disable this message." << endl;
|
||||
s_describedWarnings = true;
|
||||
}
|
||||
if (s_errorCode.dangerous()) {
|
||||
std::cerr<<warnMore()<<"*** See the manual before disabling this,"<<endl;
|
||||
std::cerr<<warnMore()<<"else you may end up with different sim results."<<endl;
|
||||
std::cerr << warnMore() << "*** See the manual before disabling this," << endl;
|
||||
std::cerr << warnMore() << "else you may end up with different sim results."
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
// If first warning is not the user's fault (internal/unsupported) then give the website
|
||||
// Not later warnings, as a internal may be caused by an earlier problem
|
||||
if (s_tellManual == 0) {
|
||||
if (s_errorCode.mentionManual()
|
||||
|| sstr.str().find("Unsupported") != string::npos) {
|
||||
if (s_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) {
|
||||
s_tellManual = 1;
|
||||
} else {
|
||||
s_tellManual = 2;
|
||||
}
|
||||
}
|
||||
if (isError(s_errorCode, s_errorSuppressed)) incErrors();
|
||||
else incWarnings();
|
||||
if (s_errorCode == V3ErrorCode::EC_FATAL
|
||||
|| s_errorCode == V3ErrorCode::EC_FATALEXIT
|
||||
if (isError(s_errorCode, s_errorSuppressed)) {
|
||||
incErrors();
|
||||
} else {
|
||||
incWarnings();
|
||||
}
|
||||
if (s_errorCode == V3ErrorCode::EC_FATAL || s_errorCode == V3ErrorCode::EC_FATALEXIT
|
||||
|| s_errorCode == V3ErrorCode::EC_FATALSRC) {
|
||||
static bool inFatal = false;
|
||||
if (!inFatal) {
|
||||
inFatal = true;
|
||||
if (s_tellManual==1) {
|
||||
std::cerr<<warnMore()<<"... See the manual and https://verilator.org for more assistance."<<endl;
|
||||
if (s_tellManual == 1) {
|
||||
std::cerr
|
||||
<< warnMore()
|
||||
<< "... See the manual and https://verilator.org for more assistance."
|
||||
<< endl;
|
||||
s_tellManual = 2;
|
||||
}
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
|
|
@ -250,8 +275,7 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
|||
}
|
||||
|
||||
vlAbort();
|
||||
}
|
||||
else if (isError(s_errorCode, s_errorSuppressed)) {
|
||||
} else if (isError(s_errorCode, s_errorSuppressed)) {
|
||||
// We don't dump tree on any error because a Visitor may be in middle of
|
||||
// a tree cleanup and cause a false broken problem.
|
||||
if (s_errorExitCb) s_errorExitCb();
|
||||
|
|
|
|||
215
src/V3Error.h
215
src/V3Error.h
|
|
@ -34,6 +34,7 @@
|
|||
|
||||
class V3ErrorCode {
|
||||
public:
|
||||
// clang-format off
|
||||
enum en {
|
||||
EC_MIN=0, // Keep first
|
||||
//
|
||||
|
|
@ -121,14 +122,19 @@ public:
|
|||
_ENUM_MAX
|
||||
// ***Add new elements below also***
|
||||
};
|
||||
// clang-format on
|
||||
enum en m_e;
|
||||
inline V3ErrorCode() : m_e(EC_MIN) {}
|
||||
inline V3ErrorCode()
|
||||
: m_e(EC_MIN) {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
inline V3ErrorCode(en _e) : m_e(_e) {}
|
||||
inline V3ErrorCode(en _e)
|
||||
: m_e(_e) {}
|
||||
explicit V3ErrorCode(const char* msgp); // Matching code or ERROR
|
||||
explicit inline V3ErrorCode(int _e) : m_e(static_cast<en>(_e)) {}
|
||||
explicit inline V3ErrorCode(int _e)
|
||||
: m_e(static_cast<en>(_e)) {}
|
||||
operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
// clang-format off
|
||||
const char* names[] = {
|
||||
// Leading spaces indicate it can't be disabled.
|
||||
" MIN", " INFO", " FATAL", " FATALEXIT", " FATALSRC", " ERROR",
|
||||
|
|
@ -159,50 +165,37 @@ public:
|
|||
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
|
||||
" MAX"
|
||||
};
|
||||
// clang-format on
|
||||
return names[m_e];
|
||||
}
|
||||
// Warnings that default to off
|
||||
bool defaultsOff() const { return ( m_e==IMPERFECTSCH || styleError()); }
|
||||
bool defaultsOff() const { return (m_e == IMPERFECTSCH || styleError()); }
|
||||
// Warnings that warn about nasty side effects
|
||||
bool dangerous() const { return ( m_e==COMBDLY ); }
|
||||
bool dangerous() const { return (m_e == COMBDLY); }
|
||||
// Warnings we'll present to the user as errors
|
||||
// Later -Werror- options may make more of these.
|
||||
bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK
|
||||
|| m_e==BLKLOOPINIT
|
||||
|| m_e==CONTASSREG
|
||||
|| m_e==IMPURE
|
||||
|| m_e==PROCASSWIRE); }
|
||||
bool pretendError() const {
|
||||
return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG
|
||||
|| m_e == IMPURE || m_e == PROCASSWIRE);
|
||||
}
|
||||
// Warnings to mention manual
|
||||
bool mentionManual() const { return ( m_e==EC_FATALSRC || m_e==SYMRSVDWORD
|
||||
|| pretendError() ); }
|
||||
|
||||
bool mentionManual() const {
|
||||
return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || pretendError());
|
||||
}
|
||||
// Warnings that are lint only
|
||||
bool lintError() const { return ( m_e==ALWCOMBORDER
|
||||
|| m_e==BSSPACE
|
||||
|| m_e==CASEINCOMPLETE || m_e==CASEOVERLAP
|
||||
|| m_e==CASEWITHX || m_e==CASEX
|
||||
|| m_e==CMPCONST
|
||||
|| m_e==COLONPLUS
|
||||
|| m_e==ENDLABEL
|
||||
|| m_e==IMPLICIT
|
||||
|| m_e==LITENDIAN
|
||||
|| m_e==PINMISSING
|
||||
|| m_e==REALCVT
|
||||
|| m_e==UNSIGNED
|
||||
|| m_e==WIDTH); }
|
||||
bool lintError() const {
|
||||
return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE
|
||||
|| m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CMPCONST
|
||||
|| m_e == COLONPLUS || m_e == ENDLABEL || m_e == IMPLICIT || m_e == LITENDIAN
|
||||
|| m_e == PINMISSING || m_e == REALCVT || m_e == UNSIGNED || m_e == WIDTH);
|
||||
}
|
||||
// Warnings that are style only
|
||||
bool styleError() const { return ( m_e==ASSIGNDLY // More than style, but for backward compatibility
|
||||
|| m_e==BLKSEQ
|
||||
|| m_e==DEFPARAM
|
||||
|| m_e==DECLFILENAME
|
||||
|| m_e==IMPORTSTAR
|
||||
|| m_e==INCABSPATH
|
||||
|| m_e==PINCONNECTEMPTY
|
||||
|| m_e==PINNOCONNECT
|
||||
|| m_e==SYNCASYNCNET
|
||||
|| m_e==UNDRIVEN
|
||||
|| m_e==UNUSED
|
||||
|| m_e==VARHIDDEN ); }
|
||||
bool styleError() const {
|
||||
return (m_e == ASSIGNDLY // More than style, but for backward compatibility
|
||||
|| m_e == BLKSEQ || m_e == DEFPARAM || m_e == DECLFILENAME || m_e == IMPORTSTAR
|
||||
|| m_e == INCABSPATH || m_e == PINCONNECTEMPTY || m_e == PINNOCONNECT
|
||||
|| m_e == SYNCASYNCNET || m_e == UNDRIVEN || m_e == UNUSED || m_e == VARHIDDEN);
|
||||
}
|
||||
};
|
||||
inline bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
|
|
@ -221,28 +214,32 @@ class V3Error {
|
|||
typedef std::set<string> MessagesSet;
|
||||
typedef void (*ErrorExitCb)(void);
|
||||
|
||||
private:
|
||||
static bool s_describedWarnings; // Told user how to disable warns
|
||||
static bool s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning
|
||||
static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error
|
||||
static int s_debugDefault; // Option: --debugi Default debugging level
|
||||
static int s_errorLimit; // Option: --error-limit Number of errors before exit
|
||||
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
|
||||
static int s_errCount; // Error count
|
||||
static int s_warnCount; // Warning count
|
||||
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
|
||||
static std::ostringstream s_errorStr; // Error string being formed
|
||||
static V3ErrorCode s_errorCode; // Error string being formed will abort
|
||||
static bool s_errorContexted; // Error being formed got context
|
||||
static bool s_errorSuppressed; // Error being formed should be suppressed
|
||||
static MessagesSet s_messages; // What errors we've outputted
|
||||
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
|
||||
private:
|
||||
static bool s_describedWarnings; // Told user how to disable warns
|
||||
static bool
|
||||
s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning
|
||||
static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error
|
||||
static int s_debugDefault; // Option: --debugi Default debugging level
|
||||
static int s_errorLimit; // Option: --error-limit Number of errors before exit
|
||||
static bool s_warnFatal; // Option: --warnFatal Warnings are fatal
|
||||
static int s_errCount; // Error count
|
||||
static int s_warnCount; // Warning count
|
||||
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
|
||||
static std::ostringstream s_errorStr; // Error string being formed
|
||||
static V3ErrorCode s_errorCode; // Error string being formed will abort
|
||||
static bool s_errorContexted; // Error being formed got context
|
||||
static bool s_errorSuppressed; // Error being formed should be suppressed
|
||||
static MessagesSet s_messages; // What errors we've outputted
|
||||
static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
|
||||
|
||||
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
|
||||
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
|
||||
|
||||
V3Error() { std::cerr<<("Static class"); abort(); }
|
||||
V3Error() {
|
||||
std::cerr << ("Static class");
|
||||
abort();
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
// ACCESSORS
|
||||
static void debugDefault(int level) { s_debugDefault = level; }
|
||||
|
|
@ -254,14 +251,16 @@ class V3Error {
|
|||
static string msgPrefix(); // returns %Error/%Warn
|
||||
static int errorCount() { return s_errCount; }
|
||||
static int warnCount() { return s_warnCount; }
|
||||
static int errorOrWarnCount() { return errorCount()+warnCount(); }
|
||||
static int errorOrWarnCount() { return errorCount() + warnCount(); }
|
||||
static bool errorContexted() { return s_errorContexted; }
|
||||
static void errorContexted(bool flag) { s_errorContexted = flag; }
|
||||
// METHODS
|
||||
static void incErrors();
|
||||
static void incWarnings() { s_warnCount++; }
|
||||
static void init();
|
||||
static void abortIfErrors() { if (errorCount()) abortIfWarnings(); }
|
||||
static void abortIfErrors() {
|
||||
if (errorCount()) abortIfWarnings();
|
||||
}
|
||||
static void abortIfWarnings();
|
||||
static void suppressThisWarning(); // Suppress next %Warn if user has it off
|
||||
static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code] = flag; }
|
||||
|
|
@ -273,77 +272,109 @@ class V3Error {
|
|||
// When printing an error/warning, print prefix for multiline message
|
||||
static string warnMore();
|
||||
/// When building an error, don't show context info
|
||||
static string warnContextNone() { V3Error::errorContexted(true); return ""; }
|
||||
static string warnContextNone() {
|
||||
V3Error::errorContexted(true);
|
||||
return "";
|
||||
}
|
||||
|
||||
// Internals for v3error()/v3fatal() macros only
|
||||
// Error end takes the string stream to output, be careful to seek() as needed
|
||||
static void v3errorPrep(V3ErrorCode code) {
|
||||
s_errorStr.str(""); s_errorCode = code;
|
||||
s_errorContexted = false; s_errorSuppressed = false; }
|
||||
s_errorStr.str("");
|
||||
s_errorCode = code;
|
||||
s_errorContexted = false;
|
||||
s_errorSuppressed = false;
|
||||
}
|
||||
static std::ostringstream& v3errorStr() { return s_errorStr; }
|
||||
static void vlAbort();
|
||||
static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = ""); // static, but often overridden in classes.
|
||||
// static, but often overridden in classes.
|
||||
static void v3errorEnd(std::ostringstream& sstr, const string& locationStr = "");
|
||||
};
|
||||
|
||||
// Global versions, so that if the class doesn't define a operator, we get the functions anyways.
|
||||
inline int debug() { return V3Error::debugDefault(); }
|
||||
inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
|
||||
inline void v3errorEndFatal(std::ostringstream& sstr) {
|
||||
V3Error::v3errorEnd(sstr); assert(0); VL_UNREACHABLE }
|
||||
V3Error::v3errorEnd(sstr);
|
||||
assert(0);
|
||||
VL_UNREACHABLE
|
||||
}
|
||||
|
||||
// Theses allow errors using << operators: v3error("foo"<<"bar");
|
||||
// Careful, you can't put () around msg, as you would in most macro definitions
|
||||
// Note the commas are the comma operator, not separating arguments. These are needed to ensure
|
||||
// evaluation order as otherwise we couldn't ensure v3errorPrep is called first.
|
||||
#define v3warnCode(code,msg) \
|
||||
v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
|
||||
#define v3warnCodeFatal(code,msg) \
|
||||
v3errorEndFatal((V3Error::v3errorPrep(code), (V3Error::v3errorStr()<<msg), \
|
||||
V3Error::v3errorStr()));
|
||||
#define v3warn(code,msg) v3warnCode(V3ErrorCode::code, msg)
|
||||
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
|
||||
#define v3warnCode(code, msg) \
|
||||
v3errorEnd( \
|
||||
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()));
|
||||
#define v3warnCodeFatal(code, msg) \
|
||||
v3errorEndFatal( \
|
||||
(V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr()));
|
||||
#define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg)
|
||||
#define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg)
|
||||
#define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg)
|
||||
#define v3fatal(msg) v3warnCodeFatal(V3ErrorCode::EC_FATAL, msg)
|
||||
// Use this instead of fatal() if message gets suppressed with --quiet-exit
|
||||
#define v3fatalExit(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALEXIT, msg)
|
||||
// Use this instead of fatal() to mention the source code line.
|
||||
#define v3fatalSrc(msg) v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, __FILE__<<":"<<std::dec<<__LINE__<<": "<<msg)
|
||||
#define v3fatalSrc(msg) \
|
||||
v3warnCodeFatal(V3ErrorCode::EC_FATALSRC, \
|
||||
__FILE__ << ":" << std::dec << __LINE__ << ": " << msg)
|
||||
// Use this when normal v3fatal is called in static method that overrides fileline.
|
||||
#define v3fatalStatic(msg) \
|
||||
::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \
|
||||
(V3Error::v3errorStr()<<msg), V3Error::v3errorStr()));
|
||||
(V3Error::v3errorStr() << msg), V3Error::v3errorStr()));
|
||||
|
||||
#define UINFO(level, stmsg) \
|
||||
{ if (VL_UNCOVERABLE(debug() >= (level))) { \
|
||||
cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; } }
|
||||
{ \
|
||||
if (VL_UNCOVERABLE(debug() >= (level))) { \
|
||||
cout << "- " << V3Error::lineStr(__FILE__, __LINE__) << stmsg; \
|
||||
} \
|
||||
}
|
||||
#define UINFONL(level, stmsg) \
|
||||
{ if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } }
|
||||
{ \
|
||||
if (VL_UNCOVERABLE(debug() >= (level))) { cout << stmsg; } \
|
||||
}
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
# define UDEBUGONLY(stmts) \
|
||||
#define UDEBUGONLY(stmts) \
|
||||
{ stmts }
|
||||
#else
|
||||
# define UDEBUGONLY(stmts) \
|
||||
{ if (false) { stmts } }
|
||||
#define UDEBUGONLY(stmts) \
|
||||
{ \
|
||||
if (false) { stmts } \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Assertion without object, generally UOBJASSERT preferred
|
||||
#define UASSERT(condition,stmsg) \
|
||||
do { if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); }} while (false)
|
||||
#define UASSERT(condition, stmsg) \
|
||||
do { \
|
||||
if (VL_UNCOVERABLE(!(condition))) { v3fatalSrc(stmsg); } \
|
||||
} while (false)
|
||||
// Assertion with object
|
||||
#define UASSERT_OBJ(condition,obj,stmsg) \
|
||||
do { if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); }} while (false)
|
||||
#define UASSERT_OBJ(condition, obj, stmsg) \
|
||||
do { \
|
||||
if (VL_UNCOVERABLE(!(condition))) { (obj)->v3fatalSrc(stmsg); } \
|
||||
} while (false)
|
||||
// For use in V3Ast static functions only
|
||||
#define UASSERT_STATIC(condition,stmsg) \
|
||||
do { if (VL_UNCOVERABLE(!(condition))) { \
|
||||
std::cerr<<"Internal Error: "<<__FILE__<<":"<<std::dec<<__LINE__ \
|
||||
<<":"<<(stmsg)<<std::endl; abort(); } } while (false)
|
||||
#define UASSERT_STATIC(condition, stmsg) \
|
||||
do { \
|
||||
if (VL_UNCOVERABLE(!(condition))) { \
|
||||
std::cerr << "Internal Error: " << __FILE__ << ":" << std::dec << __LINE__ << ":" \
|
||||
<< (stmsg) << std::endl; \
|
||||
abort(); \
|
||||
} \
|
||||
} while (false)
|
||||
// Check self test values for expected value. Safe from side-effects.
|
||||
// Type argument can be removed when go to C++11 (use auto).
|
||||
#define UASSERT_SELFTEST(Type,got,exp) \
|
||||
do { Type g = (got); Type e = (exp); \
|
||||
UASSERT(g==e, "Self-test failed '" #got "==" #exp "'"" got=" \
|
||||
<<g<<" expected="<<e); } while(false)
|
||||
#define UASSERT_SELFTEST(Type, got, exp) \
|
||||
do { \
|
||||
Type g = (got); \
|
||||
Type e = (exp); \
|
||||
UASSERT(g == e, "Self-test failed '" #got "==" #exp "'" \
|
||||
" got=" \
|
||||
<< g << " expected=" << e); \
|
||||
} while (false)
|
||||
|
||||
#define V3ERROR_NA \
|
||||
do { \
|
||||
|
|
@ -361,7 +392,7 @@ inline void v3errorEndFatal(std::ostringstream& sstr) {
|
|||
/// Verilator so that --debugi-<srcfile> will work to control UINFOs in
|
||||
/// that class:
|
||||
#define VL_DEBUG_FUNC \
|
||||
static int debug() { \
|
||||
static int debug() { \
|
||||
static int level = -1; \
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__); \
|
||||
return level; \
|
||||
|
|
|
|||
545
src/V3Expand.cpp
545
src/V3Expand.cpp
|
|
@ -42,10 +42,10 @@ class ExpandVisitor : public AstNVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
// AstNode::user1() -> bool. Processed
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNode* m_stmtp; // Current statement
|
||||
AstNode* m_stmtp; // Current statement
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -60,7 +60,7 @@ private:
|
|||
if (nodep->isWide()) {
|
||||
return V3Number(nodep, VL_EDATASIZE, VL_MASK_E(nodep->widthMin()));
|
||||
} else {
|
||||
V3Number mask (nodep, longOrQuadWidth(nodep));
|
||||
V3Number mask(nodep, longOrQuadWidth(nodep));
|
||||
mask.setMask(nodep->widthMin());
|
||||
return mask;
|
||||
}
|
||||
|
|
@ -80,10 +80,8 @@ private:
|
|||
}
|
||||
AstNode* newWordAssign(AstNodeAssign* placep, int word, AstNode* lhsp, AstNode* rhsp) {
|
||||
AstAssign* newp = new AstAssign(placep->fileline(),
|
||||
new AstWordSel(placep->fileline(),
|
||||
lhsp->cloneTree(true),
|
||||
new AstConst(placep->fileline(),
|
||||
word)),
|
||||
new AstWordSel(placep->fileline(), lhsp->cloneTree(true),
|
||||
new AstConst(placep->fileline(), word)),
|
||||
rhsp);
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -109,24 +107,20 @@ private:
|
|||
// Get the specified word number from a wide array
|
||||
// Or, if it's a long/quad, do appropriate conversion to wide
|
||||
// Concat may pass negative word numbers, that means it wants a zero
|
||||
if (nodep->isWide() && word>=0 && word<nodep->widthWords()) {
|
||||
return new AstWordSel(nodep->fileline(),
|
||||
nodep->cloneTree(true),
|
||||
if (nodep->isWide() && word >= 0 && word < nodep->widthWords()) {
|
||||
return new AstWordSel(nodep->fileline(), nodep->cloneTree(true),
|
||||
new AstConst(nodep->fileline(), word));
|
||||
} else if (nodep->isQuad() && word == 0) {
|
||||
AstNode* quadfromp = nodep->cloneTree(true);
|
||||
quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(),
|
||||
AstNumeric::UNSIGNED);
|
||||
return new AstCCast(nodep->fileline(),
|
||||
quadfromp,
|
||||
VL_EDATASIZE);
|
||||
} else if (nodep->isQuad() && word==1) {
|
||||
return new AstCCast(nodep->fileline(), quadfromp, VL_EDATASIZE);
|
||||
} else if (nodep->isQuad() && word == 1) {
|
||||
AstNode* quadfromp = nodep->cloneTree(true);
|
||||
quadfromp->dtypeSetBitUnsized(VL_QUADSIZE, quadfromp->widthMin(),
|
||||
AstNumeric::UNSIGNED);
|
||||
return new AstCCast(nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(),
|
||||
quadfromp,
|
||||
new AstShiftR(nodep->fileline(), quadfromp,
|
||||
new AstConst(nodep->fileline(), VL_EDATASIZE),
|
||||
VL_EDATASIZE),
|
||||
VL_EDATASIZE);
|
||||
|
|
@ -146,22 +140,14 @@ private:
|
|||
int othword = word - shift / VL_EDATASIZE;
|
||||
AstNode* llowp = newAstWordSelClone(lhsp, othword);
|
||||
if (int loffset = VL_BITBIT_E(shift)) {
|
||||
AstNode* lhip = newAstWordSelClone(lhsp, othword-1);
|
||||
AstNode* lhip = newAstWordSelClone(lhsp, othword - 1);
|
||||
int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword
|
||||
newp = new AstOr
|
||||
(fl,
|
||||
new AstAnd(fl,
|
||||
new AstConst(fl, AstConst::SizedEData(), VL_MASK_E(loffset)),
|
||||
new AstShiftR(fl,
|
||||
lhip,
|
||||
new AstConst(fl, nbitsonright),
|
||||
VL_EDATASIZE)),
|
||||
new AstAnd(fl,
|
||||
new AstConst(fl, AstConst::SizedEData(), ~VL_MASK_E(loffset)),
|
||||
new AstShiftL(fl,
|
||||
llowp,
|
||||
new AstConst(fl, loffset),
|
||||
VL_EDATASIZE)));
|
||||
newp = new AstOr(
|
||||
fl,
|
||||
new AstAnd(fl, new AstConst(fl, AstConst::SizedEData(), VL_MASK_E(loffset)),
|
||||
new AstShiftR(fl, lhip, new AstConst(fl, nbitsonright), VL_EDATASIZE)),
|
||||
new AstAnd(fl, new AstConst(fl, AstConst::SizedEData(), ~VL_MASK_E(loffset)),
|
||||
new AstShiftL(fl, llowp, new AstConst(fl, loffset), VL_EDATASIZE)));
|
||||
} else {
|
||||
newp = llowp;
|
||||
}
|
||||
|
|
@ -174,15 +160,13 @@ private:
|
|||
return new AstConst(lsbp->fileline(),
|
||||
wordAdder + VL_BITWORD_E(VN_CAST(lsbp, Const)->toUInt()));
|
||||
} else {
|
||||
AstNode* shiftp = new AstShiftR(lsbp->fileline(),
|
||||
lsbp->cloneTree(true),
|
||||
new AstConst(lsbp->fileline(), VL_EDATASIZE_LOG2),
|
||||
VL_EDATASIZE);
|
||||
AstNode* shiftp
|
||||
= new AstShiftR(lsbp->fileline(), lsbp->cloneTree(true),
|
||||
new AstConst(lsbp->fileline(), VL_EDATASIZE_LOG2), VL_EDATASIZE);
|
||||
if (wordAdder != 0) {
|
||||
shiftp = new AstAdd(lsbp->fileline(),
|
||||
// This is indexing a arraysel, so a 32 bit constant is fine
|
||||
new AstConst(lsbp->fileline(), wordAdder),
|
||||
shiftp);
|
||||
new AstConst(lsbp->fileline(), wordAdder), shiftp);
|
||||
}
|
||||
return shiftp;
|
||||
}
|
||||
|
|
@ -193,7 +177,7 @@ private:
|
|||
// If there's a CONDBOUND safety to keep arrays in bounds,
|
||||
// we're going to AND it to a value that always fits inside a
|
||||
// word, so we don't need it.
|
||||
//if (VN_IS(nodep, CondBound) && VN_IS(VN_CAST(nodep, CondBound)->lhsp(), Lte)) {
|
||||
// if (VN_IS(nodep, CondBound) && VN_IS(VN_CAST(nodep, CondBound)->lhsp(), Lte)) {
|
||||
// nodep = VN_CAST(nodep, CondBound)->rhsp();
|
||||
//}
|
||||
return nodep;
|
||||
|
|
@ -202,11 +186,9 @@ private:
|
|||
AstNode* newSelBitBit(AstNode* lsbp) {
|
||||
// Return equation to get the VL_BITBIT of a constant or non-constant
|
||||
if (VN_IS(lsbp, Const)) {
|
||||
return new AstConst(lsbp->fileline(),
|
||||
VL_BITBIT_E(VN_CAST(lsbp, Const)->toUInt()));
|
||||
return new AstConst(lsbp->fileline(), VL_BITBIT_E(VN_CAST(lsbp, Const)->toUInt()));
|
||||
} else {
|
||||
return new AstAnd(lsbp->fileline(),
|
||||
new AstConst(lsbp->fileline(), VL_EDATASIZE - 1),
|
||||
return new AstAnd(lsbp->fileline(), new AstConst(lsbp->fileline(), VL_EDATASIZE - 1),
|
||||
dropCondBound(lsbp)->cloneTree(true));
|
||||
}
|
||||
}
|
||||
|
|
@ -214,89 +196,89 @@ private:
|
|||
//====================
|
||||
|
||||
bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(CONST) "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl);
|
||||
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}}
|
||||
if (rhsp->num().isFourState()) {
|
||||
rhsp->v3error("Unsupported: 4-state numbers in this context");
|
||||
}
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstConst(nodep->fileline(),
|
||||
AstConst::SizedEData(),
|
||||
rhsp->num().edataWord(w)));
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(
|
||||
nodep, w,
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), rhsp->num().edataWord(w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------- Uniops
|
||||
bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(VARREF) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstArraySel* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(ARRAYSEL) "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl);
|
||||
UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep,
|
||||
"ArraySel with unpacked arrays should have been removed in V3Slice");
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp, w));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(NOT) "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl);
|
||||
// -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }}
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstNot(rhsp->fileline(),
|
||||
newAstWordSelClone(rhsp->lhsp(), w)));
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstNot(rhsp->fileline(), newAstWordSelClone(rhsp->lhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------- Biops
|
||||
bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(AND) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstAnd(nodep->fileline(),
|
||||
newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstAnd(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(OR) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstOr(nodep->fileline(),
|
||||
newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstOr(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(XOR) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstXor(nodep->fileline(),
|
||||
newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstXor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstXnor* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(XNOR) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstXnor(nodep->fileline(),
|
||||
newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
UINFO(8, " Wordize ASSIGN(XNOR) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstXnor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//-------- Triops
|
||||
bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(COND) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstCond(nodep->fileline(),
|
||||
rhsp->condp()->cloneTree(true),
|
||||
newAstWordSelClone(rhsp->expr1p(), w),
|
||||
newAstWordSelClone(rhsp->expr2p(), w)));
|
||||
UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstCond(nodep->fileline(), rhsp->condp()->cloneTree(true),
|
||||
newAstWordSelClone(rhsp->expr1p(), w),
|
||||
newAstWordSelClone(rhsp->expr2p(), w)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -316,7 +298,7 @@ private:
|
|||
} else if (lhsp->isWide()) {
|
||||
nodep->v3fatalSrc("extending larger thing into smaller?");
|
||||
} else {
|
||||
UINFO(8," EXTEND(q<-l) "<<nodep<<endl);
|
||||
UINFO(8, " EXTEND(q<-l) " << nodep << endl);
|
||||
newp = new AstCCast(nodep->fileline(), lhsp, nodep);
|
||||
}
|
||||
} else { // Long
|
||||
|
|
@ -328,12 +310,12 @@ private:
|
|||
}
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstExtend* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(EXTEND) "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ASSIGN(EXTEND) " << nodep << endl);
|
||||
int w = 0;
|
||||
for (w=0; w<rhsp->lhsp()->widthWords(); w++) {
|
||||
for (w = 0; w < rhsp->lhsp()->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp->lhsp(), w));
|
||||
}
|
||||
for (; w<nodep->widthWords(); w++) {
|
||||
for (; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, new AstConst(rhsp->fileline(), AstConst::SizedEData(), 0));
|
||||
}
|
||||
return true;
|
||||
|
|
@ -345,33 +327,29 @@ private:
|
|||
// Remember, Sel's may have non-integer rhs, so need to optimize for that!
|
||||
UASSERT_OBJ(nodep->widthMin() == nodep->widthConst(), nodep, "Width mismatch");
|
||||
if (VN_IS(nodep->backp(), NodeAssign)
|
||||
&& nodep==VN_CAST(nodep->backp(), NodeAssign)->lhsp()) {
|
||||
&& nodep == VN_CAST(nodep->backp(), NodeAssign)->lhsp()) {
|
||||
// Sel is an LHS assignment select
|
||||
} else if (nodep->isWide()) {
|
||||
// See under ASSIGN(WIDE)
|
||||
}
|
||||
else if (nodep->fromp()->isWide()) {
|
||||
UINFO(8," SEL(wide) "<<nodep<<endl);
|
||||
} else if (nodep->fromp()->isWide()) {
|
||||
UINFO(8, " SEL(wide) " << nodep << endl);
|
||||
// Selection amounts
|
||||
// Check for constant shifts & save some constification work later.
|
||||
// Grab lowest bit(s)
|
||||
AstNode* lowwordp = new AstWordSel(nodep->fromp()->fileline(),
|
||||
nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 0));
|
||||
AstNode* lowwordp
|
||||
= new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 0));
|
||||
if (nodep->isQuad() && !lowwordp->isQuad()) {
|
||||
lowwordp = new AstCCast(nodep->fileline(), lowwordp, nodep);
|
||||
}
|
||||
AstNode* lowp = new AstShiftR(nodep->fileline(),
|
||||
lowwordp,
|
||||
newSelBitBit(nodep->lsbp()),
|
||||
AstNode* lowp = new AstShiftR(nodep->fileline(), lowwordp, newSelBitBit(nodep->lsbp()),
|
||||
nodep->width());
|
||||
// If > 1 bit, we might be crossing the word boundary
|
||||
AstNode* midp = NULL;
|
||||
V3Number zero (nodep, longOrQuadWidth(nodep));
|
||||
V3Number zero(nodep, longOrQuadWidth(nodep));
|
||||
if (nodep->widthConst() > 1) {
|
||||
AstNode* midwordp = // SEL(from,[1+wordnum])
|
||||
new AstWordSel(nodep->fromp()->fileline(),
|
||||
nodep->fromp()->cloneTree(true),
|
||||
new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 1));
|
||||
if (nodep->isQuad() && !midwordp->isQuad()) {
|
||||
midwordp = new AstCCast(nodep->fileline(), midwordp, nodep);
|
||||
|
|
@ -380,23 +358,19 @@ private:
|
|||
// get shifted << by 32 bits
|
||||
// else we need to form the lower word, so we << by 31 or less
|
||||
// nbitsfromlow <= (lsb==0) ? 64-bitbit(lsb) : 32-bitbit(lsb)
|
||||
AstNode* midshiftp = new AstSub(nodep->lsbp()->fileline(),
|
||||
new AstConst(nodep->lsbp()->fileline(),
|
||||
VL_EDATASIZE),
|
||||
newSelBitBit(nodep->lsbp()));
|
||||
AstNode* midshiftp
|
||||
= new AstSub(nodep->lsbp()->fileline(),
|
||||
new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE),
|
||||
newSelBitBit(nodep->lsbp()));
|
||||
if (nodep->isQuad()) {
|
||||
midshiftp =
|
||||
new AstCond(nodep->fileline(),
|
||||
new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), 0),
|
||||
newSelBitBit(nodep->lsbp())),
|
||||
new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE),
|
||||
midshiftp);
|
||||
midshiftp = new AstCond(
|
||||
nodep->fileline(),
|
||||
new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0),
|
||||
newSelBitBit(nodep->lsbp())),
|
||||
new AstConst(nodep->lsbp()->fileline(), VL_EDATASIZE), midshiftp);
|
||||
}
|
||||
AstNode* midmayp = new AstShiftL(nodep->fileline(),
|
||||
midwordp,
|
||||
midshiftp,
|
||||
nodep->width());
|
||||
AstNode* midmayp
|
||||
= new AstShiftL(nodep->fileline(), midwordp, midshiftp, nodep->width());
|
||||
if (nodep->isQuad()) {
|
||||
midp = midmayp; // Always grab from two words
|
||||
} else {
|
||||
|
|
@ -404,35 +378,30 @@ private:
|
|||
new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), 0),
|
||||
newSelBitBit(nodep->lsbp())),
|
||||
new AstConst(nodep->fileline(), zero),
|
||||
midmayp);
|
||||
new AstConst(nodep->fileline(), zero), midmayp);
|
||||
}
|
||||
}
|
||||
// If > 32 bits, we might be crossing the second word boundary
|
||||
AstNode* hip = NULL;
|
||||
if (nodep->widthConst() > VL_EDATASIZE) {
|
||||
AstNode* hiwordp = // SEL(from,[2+wordnum])
|
||||
new AstWordSel(nodep->fromp()->fileline(),
|
||||
nodep->fromp()->cloneTree(true),
|
||||
new AstWordSel(nodep->fromp()->fileline(), nodep->fromp()->cloneTree(true),
|
||||
newSelBitWord(nodep->lsbp(), 2));
|
||||
if (nodep->isQuad() && !hiwordp->isQuad()) {
|
||||
hiwordp = new AstCCast(nodep->fileline(), hiwordp, nodep);
|
||||
}
|
||||
AstNode* himayp =
|
||||
new AstShiftL(nodep->fileline(),
|
||||
hiwordp,
|
||||
// nbitsfromlow_and_mid <= 64-bitbit(lsb)
|
||||
new AstSub(nodep->lsbp()->fileline(),
|
||||
new AstConst(nodep->lsbp()->fileline(), 64),
|
||||
newSelBitBit(nodep->lsbp())),
|
||||
nodep->width());
|
||||
AstNode* himayp
|
||||
= new AstShiftL(nodep->fileline(), hiwordp,
|
||||
// nbitsfromlow_and_mid <= 64-bitbit(lsb)
|
||||
new AstSub(nodep->lsbp()->fileline(),
|
||||
new AstConst(nodep->lsbp()->fileline(), 64),
|
||||
newSelBitBit(nodep->lsbp())),
|
||||
nodep->width());
|
||||
// if (frombit==0) then ignore, else use it
|
||||
hip = new AstCond(nodep->fileline(),
|
||||
new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), 0),
|
||||
new AstEq(nodep->fileline(), new AstConst(nodep->fileline(), 0),
|
||||
newSelBitBit(nodep->lsbp())),
|
||||
new AstConst(nodep->fileline(), zero),
|
||||
himayp);
|
||||
new AstConst(nodep->fileline(), zero), himayp);
|
||||
}
|
||||
|
||||
AstNode* newp = lowp;
|
||||
|
|
@ -440,18 +409,16 @@ private:
|
|||
if (hip) newp = new AstOr(nodep->fileline(), hip, newp);
|
||||
newp->dtypeFrom(nodep);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
else { // Long/Quad from Long/Quad
|
||||
UINFO(8," SEL->SHIFT "<<nodep<<endl);
|
||||
} else { // Long/Quad from Long/Quad
|
||||
UINFO(8, " SEL->SHIFT " << nodep << endl);
|
||||
AstNode* fromp = nodep->fromp()->unlinkFrBack();
|
||||
AstNode* lsbp = nodep->lsbp()->unlinkFrBack();
|
||||
if (nodep->isQuad() && !fromp->isQuad()) {
|
||||
fromp = new AstCCast(nodep->fileline(), fromp, nodep);
|
||||
}
|
||||
AstNode* newp = new AstShiftR(nodep->fileline(),
|
||||
fromp,
|
||||
dropCondBound(lsbp),
|
||||
fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast
|
||||
AstNode* newp = new AstShiftR(
|
||||
nodep->fileline(), fromp, dropCondBound(lsbp),
|
||||
fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast
|
||||
newp->dtypeFrom(fromp);
|
||||
if (!nodep->isQuad() && fromp->isQuad()) {
|
||||
newp = new AstCCast(newp->fileline(), newp, nodep);
|
||||
|
|
@ -465,42 +432,35 @@ private:
|
|||
UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch");
|
||||
if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) {
|
||||
int lsb = rhsp->lsbConst();
|
||||
UINFO(8," Wordize ASSIGN(SEL,align) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
addWordAssign(nodep, w, newAstWordSelClone(rhsp->fromp(), w + VL_BITWORD_E(lsb)));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
UINFO(8," Wordize ASSIGN(EXTRACT,misalign) "<<nodep<<endl);
|
||||
for (int w=0; w<nodep->widthWords(); w++) {
|
||||
UINFO(8, " Wordize ASSIGN(EXTRACT,misalign) " << nodep << endl);
|
||||
for (int w = 0; w < nodep->widthWords(); w++) {
|
||||
// Grab lowest bits
|
||||
AstNode* lowwordp = new AstWordSel(rhsp->fileline(),
|
||||
rhsp->fromp()->cloneTree(true),
|
||||
newSelBitWord(rhsp->lsbp(), w));
|
||||
AstNode* lowp = new AstShiftR(rhsp->fileline(),
|
||||
lowwordp,
|
||||
newSelBitBit(rhsp->lsbp()),
|
||||
VL_EDATASIZE);
|
||||
AstNode* lowwordp
|
||||
= new AstWordSel(rhsp->fileline(), rhsp->fromp()->cloneTree(true),
|
||||
newSelBitWord(rhsp->lsbp(), w));
|
||||
AstNode* lowp = new AstShiftR(rhsp->fileline(), lowwordp,
|
||||
newSelBitBit(rhsp->lsbp()), VL_EDATASIZE);
|
||||
// Upper bits
|
||||
V3Number zero (nodep, VL_EDATASIZE, 0);
|
||||
V3Number zero(nodep, VL_EDATASIZE, 0);
|
||||
AstNode* midwordp = // SEL(from,[1+wordnum])
|
||||
new AstWordSel(rhsp->fromp()->fileline(),
|
||||
rhsp->fromp()->cloneTree(true),
|
||||
newSelBitWord(rhsp->lsbp(), w+1));
|
||||
AstNode* midshiftp = new AstSub(rhsp->lsbp()->fileline(),
|
||||
new AstConst(rhsp->lsbp()->fileline(),
|
||||
VL_EDATASIZE),
|
||||
newSelBitBit(rhsp->lsbp()));
|
||||
AstNode* midmayp = new AstShiftL(rhsp->fileline(),
|
||||
midwordp,
|
||||
midshiftp,
|
||||
VL_EDATASIZE);
|
||||
AstNode* midp = new AstCond(rhsp->fileline(),
|
||||
new AstEq(rhsp->fileline(),
|
||||
new AstConst(rhsp->fileline(), 0),
|
||||
newSelBitBit(rhsp->lsbp())),
|
||||
new AstConst(rhsp->fileline(), zero),
|
||||
midmayp);
|
||||
new AstWordSel(rhsp->fromp()->fileline(), rhsp->fromp()->cloneTree(true),
|
||||
newSelBitWord(rhsp->lsbp(), w + 1));
|
||||
AstNode* midshiftp = new AstSub(
|
||||
rhsp->lsbp()->fileline(), new AstConst(rhsp->lsbp()->fileline(), VL_EDATASIZE),
|
||||
newSelBitBit(rhsp->lsbp()));
|
||||
AstNode* midmayp
|
||||
= new AstShiftL(rhsp->fileline(), midwordp, midshiftp, VL_EDATASIZE);
|
||||
AstNode* midp
|
||||
= new AstCond(rhsp->fileline(),
|
||||
new AstEq(rhsp->fileline(), new AstConst(rhsp->fileline(), 0),
|
||||
newSelBitBit(rhsp->lsbp())),
|
||||
new AstConst(rhsp->fileline(), zero), midmayp);
|
||||
AstNode* newp = new AstOr(nodep->fileline(), midp, lowp);
|
||||
addWordAssign(nodep, w, newp);
|
||||
}
|
||||
|
|
@ -524,99 +484,84 @@ private:
|
|||
AstNode* destp = lhsp->fromp()->unlinkFrBack();
|
||||
int lsb = lhsp->lsbConst();
|
||||
int msb = lhsp->msbConst();
|
||||
V3Number maskset (nodep, destp->widthMin());
|
||||
for (int bit=lsb; bit<(msb+1); bit++) maskset.setBit(bit, 1);
|
||||
V3Number maskold (nodep, destp->widthMin()); maskold.opNot(maskset);
|
||||
V3Number maskset(nodep, destp->widthMin());
|
||||
for (int bit = lsb; bit < (msb + 1); bit++) maskset.setBit(bit, 1);
|
||||
V3Number maskold(nodep, destp->widthMin());
|
||||
maskold.opNot(maskset);
|
||||
if (destwide) {
|
||||
UINFO(8," ASSIGNSEL(const,wide) "<<nodep<<endl);
|
||||
for (int w=0; w<destp->widthWords(); w++) {
|
||||
UINFO(8, " ASSIGNSEL(const,wide) " << nodep << endl);
|
||||
for (int w = 0; w < destp->widthWords(); w++) {
|
||||
if (w >= VL_BITWORD_E(lsb) && w <= VL_BITWORD_E(msb)) {
|
||||
// else we would just be setting it to the same exact value
|
||||
AstNode* oldvalp = newAstWordSelClone(destp, w);
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) {
|
||||
oldvalp = new AstAnd(lhsp->fileline(),
|
||||
new AstConst(lhsp->fileline(),
|
||||
AstConst::SizedEData(),
|
||||
maskold.edataWord(w)),
|
||||
oldvalp);
|
||||
oldvalp
|
||||
= new AstAnd(lhsp->fileline(),
|
||||
new AstConst(lhsp->fileline(), AstConst::SizedEData(),
|
||||
maskold.edataWord(w)),
|
||||
oldvalp);
|
||||
}
|
||||
addWordAssign(nodep, w,
|
||||
destp,
|
||||
new AstOr(lhsp->fileline(),
|
||||
oldvalp,
|
||||
newWordGrabShift(lhsp->fileline(), w,
|
||||
rhsp, lsb)));
|
||||
addWordAssign(nodep, w, destp,
|
||||
new AstOr(lhsp->fileline(), oldvalp,
|
||||
newWordGrabShift(lhsp->fileline(), w, rhsp, lsb)));
|
||||
}
|
||||
}
|
||||
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
|
||||
VL_DO_DANGLING(destp->deleteTree(), destp);
|
||||
} else {
|
||||
UINFO(8," ASSIGNSEL(const,narrow) "<<nodep<<endl);
|
||||
UINFO(8, " ASSIGNSEL(const,narrow) " << nodep << endl);
|
||||
if (destp->isQuad() && !rhsp->isQuad()) {
|
||||
rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
|
||||
}
|
||||
AstNode* oldvalp = destp->cloneTree(true);
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) {
|
||||
oldvalp = new AstAnd(lhsp->fileline(),
|
||||
new AstConst(lhsp->fileline(), maskold),
|
||||
oldvalp = new AstAnd(lhsp->fileline(), new AstConst(lhsp->fileline(), maskold),
|
||||
oldvalp);
|
||||
}
|
||||
AstNode* newp
|
||||
= new AstOr(lhsp->fileline(),
|
||||
oldvalp,
|
||||
new AstShiftL(lhsp->fileline(),
|
||||
rhsp,
|
||||
new AstConst(lhsp->fileline(), lsb),
|
||||
destp->width()));
|
||||
AstNode* newp = new AstOr(lhsp->fileline(), oldvalp,
|
||||
new AstShiftL(lhsp->fileline(), rhsp,
|
||||
new AstConst(lhsp->fileline(), lsb),
|
||||
destp->width()));
|
||||
newp = new AstAssign(nodep->fileline(), destp, newp);
|
||||
insertBefore(nodep, newp);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else { // non-const RHS
|
||||
if (destwide && lhsp->widthConst()==1) {
|
||||
UINFO(8," ASSIGNSEL(varlsb,wide,1bit) "<<nodep<<endl);
|
||||
} else { // non-const RHS
|
||||
if (destwide && lhsp->widthConst() == 1) {
|
||||
UINFO(8, " ASSIGNSEL(varlsb,wide,1bit) " << nodep << endl);
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNode* oldvalp = new AstWordSel(lhsp->fileline(),
|
||||
destp->cloneTree(true),
|
||||
AstNode* oldvalp = new AstWordSel(lhsp->fileline(), destp->cloneTree(true),
|
||||
newSelBitWord(lhsp->lsbp(), 0));
|
||||
fixCloneLvalue(oldvalp);
|
||||
if (!ones) {
|
||||
oldvalp = new AstAnd
|
||||
(lhsp->fileline(),
|
||||
new AstNot(lhsp->fileline(),
|
||||
new AstShiftL
|
||||
(lhsp->fileline(),
|
||||
new AstConst(nodep->fileline(), 1),
|
||||
// newSelBitBit may exceed the MSB of this variable.
|
||||
// That's ok as we'd just AND with a larger value,
|
||||
// but oldval would clip the upper bits to sanity
|
||||
newSelBitBit(lhsp->lsbp()),
|
||||
VL_EDATASIZE)),
|
||||
oldvalp);
|
||||
oldvalp = new AstAnd(
|
||||
lhsp->fileline(),
|
||||
new AstNot(
|
||||
lhsp->fileline(),
|
||||
new AstShiftL(lhsp->fileline(), new AstConst(nodep->fileline(), 1),
|
||||
// newSelBitBit may exceed the MSB of this variable.
|
||||
// That's ok as we'd just AND with a larger value,
|
||||
// but oldval would clip the upper bits to sanity
|
||||
newSelBitBit(lhsp->lsbp()), VL_EDATASIZE)),
|
||||
oldvalp);
|
||||
}
|
||||
// Restrict the shift amount to 0-31, see bug804.
|
||||
AstNode* shiftp = new AstAnd(nodep->fileline(), lhsp->lsbp()->cloneTree(true),
|
||||
new AstConst(nodep->fileline(), VL_EDATASIZE - 1));
|
||||
AstNode* newp = new AstOr(lhsp->fileline(),
|
||||
oldvalp,
|
||||
new AstShiftL(lhsp->fileline(),
|
||||
rhsp,
|
||||
shiftp,
|
||||
VL_EDATASIZE));
|
||||
newp = new AstAssign(nodep->fileline(),
|
||||
new AstWordSel(nodep->fileline(),
|
||||
destp,
|
||||
newSelBitWord(lhsp->lsbp(), 0)),
|
||||
newp);
|
||||
AstNode* newp
|
||||
= new AstOr(lhsp->fileline(), oldvalp,
|
||||
new AstShiftL(lhsp->fileline(), rhsp, shiftp, VL_EDATASIZE));
|
||||
newp = new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstWordSel(nodep->fileline(), destp, newSelBitWord(lhsp->lsbp(), 0)),
|
||||
newp);
|
||||
insertBefore(nodep, newp);
|
||||
return true;
|
||||
}
|
||||
else if (destwide) {
|
||||
UINFO(8," ASSIGNSEL(varlsb,wide) -- NoOp -- "<<nodep<<endl);
|
||||
} else if (destwide) {
|
||||
UINFO(8, " ASSIGNSEL(varlsb,wide) -- NoOp -- " << nodep << endl);
|
||||
// For wide destp, we can either form a equation for every destination word,
|
||||
// with the appropriate long equation of if it's being written or not.
|
||||
// Or, we can use a LHS variable arraysel with
|
||||
|
|
@ -628,38 +573,34 @@ private:
|
|||
// Reconsider if we get subexpression elimination.
|
||||
return false;
|
||||
} else {
|
||||
UINFO(8," ASSIGNSEL(varlsb,narrow) "<<nodep<<endl);
|
||||
UINFO(8, " ASSIGNSEL(varlsb,narrow) " << nodep << endl);
|
||||
// nodep->dumpTree(cout, "- old: ");
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* destp = lhsp->fromp()->unlinkFrBack();
|
||||
AstNode* oldvalp = destp->cloneTree(true);
|
||||
fixCloneLvalue(oldvalp);
|
||||
|
||||
V3Number maskwidth (nodep, destp->widthMin());
|
||||
for (int bit=0; bit < lhsp->widthConst(); bit++) maskwidth.setBit(bit, 1);
|
||||
V3Number maskwidth(nodep, destp->widthMin());
|
||||
for (int bit = 0; bit < lhsp->widthConst(); bit++) maskwidth.setBit(bit, 1);
|
||||
|
||||
if (destp->isQuad() && !rhsp->isQuad()) {
|
||||
rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
|
||||
}
|
||||
if (!ones) {
|
||||
oldvalp = new AstAnd(lhsp->fileline(),
|
||||
new AstNot(lhsp->fileline(),
|
||||
new AstShiftL(lhsp->fileline(),
|
||||
new AstConst(nodep->fileline(),
|
||||
maskwidth),
|
||||
lhsp->lsbp()->cloneTree(true),
|
||||
destp->width())),
|
||||
oldvalp);
|
||||
oldvalp = new AstAnd(
|
||||
lhsp->fileline(),
|
||||
new AstNot(lhsp->fileline(),
|
||||
new AstShiftL(lhsp->fileline(),
|
||||
new AstConst(nodep->fileline(), maskwidth),
|
||||
lhsp->lsbp()->cloneTree(true), destp->width())),
|
||||
oldvalp);
|
||||
}
|
||||
AstNode* newp
|
||||
= new AstOr(lhsp->fileline(),
|
||||
oldvalp,
|
||||
new AstShiftL(lhsp->fileline(),
|
||||
rhsp,
|
||||
lhsp->lsbp()->cloneTree(true),
|
||||
destp->width()));
|
||||
= new AstOr(lhsp->fileline(), oldvalp,
|
||||
new AstShiftL(lhsp->fileline(), rhsp,
|
||||
lhsp->lsbp()->cloneTree(true), destp->width()));
|
||||
newp = new AstAssign(nodep->fileline(), destp, newp);
|
||||
//newp->dumpTree(cout, "- new: ");
|
||||
// newp->dumpTree(cout, "- new: ");
|
||||
insertBefore(nodep, newp);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -672,7 +613,7 @@ private:
|
|||
if (nodep->isWide()) {
|
||||
// See under ASSIGN(WIDE)
|
||||
} else {
|
||||
UINFO(8," CONCAT "<<nodep<<endl);
|
||||
UINFO(8, " CONCAT " << nodep << endl);
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
int rhsshift = rhsp->widthMin();
|
||||
|
|
@ -683,28 +624,26 @@ private:
|
|||
rhsp = new AstCCast(nodep->fileline(), rhsp, nodep);
|
||||
}
|
||||
AstNode* newp = new AstOr(nodep->fileline(),
|
||||
new AstShiftL(nodep->fileline(),
|
||||
lhsp,
|
||||
new AstShiftL(nodep->fileline(), lhsp,
|
||||
new AstConst(nodep->fileline(), rhsshift),
|
||||
nodep->width()),
|
||||
rhsp);
|
||||
rhsp);
|
||||
newp->dtypeFrom(nodep); // Unsigned
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(CONCAT) "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl);
|
||||
// Lhs or Rhs may be word, long, or quad.
|
||||
// newAstWordSelClone nicely abstracts the difference.
|
||||
int rhsshift = rhsp->rhsp()->widthMin();
|
||||
// Sometimes doing the words backwards is preferable.
|
||||
// When we have x={x,foo} backwards is better, when x={foo,x} forward is better
|
||||
// However V3Subst tends to rip this up, so not worth optimizing now.
|
||||
for (int w=0; w<rhsp->widthWords(); w++) {
|
||||
for (int w = 0; w < rhsp->widthWords(); w++) {
|
||||
addWordAssign(nodep, w,
|
||||
new AstOr(rhsp->fileline(),
|
||||
newWordGrabShift(rhsp->fileline(), w,
|
||||
rhsp->lhsp(), rhsshift),
|
||||
newWordGrabShift(rhsp->fileline(), w, rhsp->lhsp(), rhsshift),
|
||||
newAstWordSelClone(rhsp->rhsp(), w)));
|
||||
}
|
||||
return true;
|
||||
|
|
@ -719,11 +658,11 @@ private:
|
|||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newp;
|
||||
int lhswidth = lhsp->widthMin();
|
||||
if (lhswidth==1) {
|
||||
UINFO(8," REPLICATE(w1) "<<nodep<<endl);
|
||||
if (lhswidth == 1) {
|
||||
UINFO(8, " REPLICATE(w1) " << nodep << endl);
|
||||
newp = new AstNegate(nodep->fileline(), lhsp);
|
||||
} else {
|
||||
UINFO(8," REPLICATE "<<nodep<<endl);
|
||||
UINFO(8, " REPLICATE " << nodep << endl);
|
||||
const AstConst* constp = VN_CAST(nodep->rhsp(), Const);
|
||||
UASSERT_OBJ(constp, nodep,
|
||||
"Replication value isn't a constant. Checked earlier!");
|
||||
|
|
@ -732,14 +671,13 @@ private:
|
|||
lhsp = new AstCCast(nodep->fileline(), lhsp, nodep);
|
||||
}
|
||||
newp = lhsp->cloneTree(true);
|
||||
for (unsigned repnum=1; repnum<times; repnum++) {
|
||||
int rhsshift = repnum*lhswidth;
|
||||
for (unsigned repnum = 1; repnum < times; repnum++) {
|
||||
int rhsshift = repnum * lhswidth;
|
||||
newp = new AstOr(nodep->fileline(),
|
||||
new AstShiftL(nodep->fileline(),
|
||||
lhsp->cloneTree(true),
|
||||
new AstShiftL(nodep->fileline(), lhsp->cloneTree(true),
|
||||
new AstConst(nodep->fileline(), rhsshift),
|
||||
nodep->width()),
|
||||
newp);
|
||||
newp);
|
||||
newp->dtypeFrom(nodep); // Unsigned
|
||||
}
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp); // Never used
|
||||
|
|
@ -749,25 +687,24 @@ private:
|
|||
}
|
||||
}
|
||||
bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) {
|
||||
UINFO(8," Wordize ASSIGN(REPLICATE) "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl);
|
||||
AstNode* lhsp = rhsp->lhsp();
|
||||
int lhswidth = lhsp->widthMin();
|
||||
const AstConst* constp = VN_CAST(rhsp->rhsp(), Const);
|
||||
UASSERT_OBJ(constp, rhsp, "Replication value isn't a constant. Checked earlier!");
|
||||
uint32_t times = constp->toUInt();
|
||||
for (int w=0; w<rhsp->widthWords(); w++) {
|
||||
for (int w = 0; w < rhsp->widthWords(); w++) {
|
||||
AstNode* newp;
|
||||
if (lhswidth==1) {
|
||||
if (lhswidth == 1) {
|
||||
newp = new AstNegate(nodep->fileline(), lhsp->cloneTree(true));
|
||||
newp->dtypeSetLogicSized(VL_EDATASIZE,
|
||||
AstNumeric::UNSIGNED); // Replicate always unsigned
|
||||
} else {
|
||||
newp = newAstWordSelClone(lhsp, w);
|
||||
for (unsigned repnum=1; repnum<times; repnum++) {
|
||||
newp = new AstOr(nodep->fileline(),
|
||||
newWordGrabShift(rhsp->fileline(), w, lhsp,
|
||||
lhswidth*repnum),
|
||||
newp);
|
||||
for (unsigned repnum = 1; repnum < times; repnum++) {
|
||||
newp = new AstOr(
|
||||
nodep->fileline(),
|
||||
newWordGrabShift(rhsp->fileline(), w, lhsp, lhswidth * repnum), newp);
|
||||
}
|
||||
}
|
||||
addWordAssign(nodep, w, newp);
|
||||
|
|
@ -778,14 +715,13 @@ private:
|
|||
virtual void visit(AstChangeXor* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
UINFO(8," Wordize ChangeXor "<<nodep<<endl);
|
||||
UINFO(8, " Wordize ChangeXor " << nodep << endl);
|
||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = new AstXor(nodep->fileline(),
|
||||
newAstWordSelClone(nodep->lhsp(), w),
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
|
||||
newAstWordSelClone(nodep->rhsp(), w));
|
||||
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
|
|
@ -794,23 +730,21 @@ private:
|
|||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize EQ/NEQ "<<nodep<<endl);
|
||||
UINFO(8, " Wordize EQ/NEQ " << nodep << endl);
|
||||
// -> (0=={or{for each_word{WORDSEL(lhs,#)^WORDSEL(rhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = new AstXor(nodep->fileline(),
|
||||
newAstWordSelClone(nodep->lhsp(), w),
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = new AstXor(nodep->fileline(), newAstWordSelClone(nodep->lhsp(), w),
|
||||
newAstWordSelClone(nodep->rhsp(), w));
|
||||
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
if (VN_IS(nodep, Neq)) {
|
||||
newp = new AstNeq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
|
||||
newp);
|
||||
newp
|
||||
= new AstNeq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
|
||||
} else {
|
||||
newp = new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
|
||||
newp);
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
|
||||
}
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
|
|
@ -822,19 +756,18 @@ private:
|
|||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize REDOR "<<nodep<<endl);
|
||||
UINFO(8, " Wordize REDOR " << nodep << endl);
|
||||
// -> (0!={or{for each_word{WORDSEL(lhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
newp = (newp==NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == NULL) ? eqp : (new AstOr(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstNeq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0),
|
||||
newp);
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), 0), newp);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
} else {
|
||||
UINFO(8," REDOR->EQ "<<nodep<<endl);
|
||||
UINFO(8, " REDOR->EQ " << nodep << endl);
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newp = new AstNeq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
|
|
@ -847,12 +780,12 @@ private:
|
|||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize REDAND "<<nodep<<endl);
|
||||
UINFO(8, " Wordize REDAND " << nodep << endl);
|
||||
// -> (0!={and{for each_word{WORDSEL(lhs,#)}}}
|
||||
AstNode* newp = NULL;
|
||||
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
if (w==nodep->lhsp()->widthWords()-1) {
|
||||
if (w == nodep->lhsp()->widthWords() - 1) {
|
||||
// Rather than doing a (slowish) ==##, we OR in the
|
||||
// bits that aren't part of the mask
|
||||
eqp = new AstOr(nodep->fileline(),
|
||||
|
|
@ -861,18 +794,17 @@ private:
|
|||
// cppcheck-suppress memleak
|
||||
eqp);
|
||||
}
|
||||
newp = (newp==NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == NULL) ? eqp : (new AstAnd(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(),
|
||||
~VL_MASK_E(0)), newp);
|
||||
newp = new AstEq(
|
||||
nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::SizedEData(), ~VL_MASK_E(0)), newp);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
} else {
|
||||
UINFO(8," REDAND->EQ "<<nodep<<endl);
|
||||
UINFO(8, " REDAND->EQ " << nodep << endl);
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* newp = new AstEq(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), wordMask(lhsp)),
|
||||
lhsp);
|
||||
new AstConst(nodep->fileline(), wordMask(lhsp)), lhsp);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
}
|
||||
|
|
@ -880,15 +812,15 @@ private:
|
|||
if (nodep->user1SetOnce()) return; // Process once
|
||||
iterateChildren(nodep);
|
||||
if (nodep->lhsp()->isWide()) {
|
||||
UINFO(8," Wordize REDXOR "<<nodep<<endl);
|
||||
UINFO(8, " Wordize REDXOR " << nodep << endl);
|
||||
// -> (0!={redxor{for each_word{XOR(WORDSEL(lhs,#))}}}
|
||||
AstNode* newp = NULL;
|
||||
for (int w=0; w<nodep->lhsp()->widthWords(); w++) {
|
||||
for (int w = 0; w < nodep->lhsp()->widthWords(); w++) {
|
||||
AstNode* eqp = newAstWordSelClone(nodep->lhsp(), w);
|
||||
newp = (newp==NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
|
||||
newp = (newp == NULL) ? eqp : (new AstXor(nodep->fileline(), newp, eqp));
|
||||
}
|
||||
newp = new AstRedXor(nodep->fileline(), newp);
|
||||
UINFO(8," Wordize REDXORnew "<<newp<<endl);
|
||||
UINFO(8, " Wordize REDXORnew " << newp << endl);
|
||||
VL_DO_DANGLING(replaceWithDelete(nodep, newp), nodep);
|
||||
}
|
||||
// We don't reduce non-wide XORs, as its more efficient to use a temp register,
|
||||
|
|
@ -910,8 +842,7 @@ private:
|
|||
m_stmtp = nodep;
|
||||
iterateChildren(nodep);
|
||||
bool did = false;
|
||||
if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef)
|
||||
|| VN_IS(nodep->lhsp(), ArraySel)))
|
||||
if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel)))
|
||||
&& !AstVar::scVarRecurse(nodep->lhsp()) // Need special function for SC
|
||||
&& !AstVar::scVarRecurse(nodep->rhsp())) {
|
||||
if (AstConst* rhsp = VN_CAST(nodep->rhsp(), Const)) {
|
||||
|
|
@ -943,9 +874,7 @@ private:
|
|||
did = expandLhs(nodep, lhsp);
|
||||
}
|
||||
// Cleanup common code
|
||||
if (did) {
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
if (did) VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
m_stmtp = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -969,9 +898,7 @@ public:
|
|||
// Expand class functions
|
||||
|
||||
void V3Expand::expandAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
ExpandVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ExpandVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("expand", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
591
src/V3File.cpp
591
src/V3File.cpp
File diff suppressed because it is too large
Load Diff
59
src/V3File.h
59
src/V3File.h
|
|
@ -40,11 +40,11 @@ public:
|
|||
static std::ifstream* new_ifstream_nodepend(const string& filename) {
|
||||
return new std::ifstream(filename.c_str());
|
||||
}
|
||||
static std::ofstream* new_ofstream(const string& filename, bool append=false) {
|
||||
static std::ofstream* new_ofstream(const string& filename, bool append = false) {
|
||||
addTgtDepend(filename);
|
||||
return new_ofstream_nodepend(filename, append);
|
||||
}
|
||||
static std::ofstream* new_ofstream_nodepend(const string& filename, bool append=false) {
|
||||
static std::ofstream* new_ofstream_nodepend(const string& filename, bool append = false) {
|
||||
createMakeDirFor(filename);
|
||||
if (append) {
|
||||
return new std::ofstream(filename.c_str(), std::ios::app);
|
||||
|
|
@ -86,6 +86,7 @@ private:
|
|||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VInFilter);
|
||||
|
||||
public:
|
||||
explicit VInFilter(const string& command);
|
||||
~VInFilter();
|
||||
|
|
@ -100,12 +101,9 @@ public:
|
|||
|
||||
class V3OutFormatter {
|
||||
// TYPES
|
||||
enum MiscConsts {
|
||||
MAXSPACE = 80}; // After this indent, stop indenting more
|
||||
enum MiscConsts { MAXSPACE = 80 }; // After this indent, stop indenting more
|
||||
public:
|
||||
enum AlignClass {
|
||||
AL_AUTO = 0,
|
||||
AL_STATIC = 1};
|
||||
enum AlignClass { AL_AUTO = 0, AL_STATIC = 1 };
|
||||
enum Language {
|
||||
LA_C = 0,
|
||||
LA_VERILOG = 1,
|
||||
|
|
@ -115,17 +113,17 @@ public:
|
|||
|
||||
private:
|
||||
// MEMBERS
|
||||
string m_filename;
|
||||
Language m_lang; // Indenting Verilog code
|
||||
int m_blockIndent; // Characters per block indent
|
||||
int m_commaWidth; // Width after which to break at ,'s
|
||||
int m_lineno;
|
||||
int m_column;
|
||||
int m_nobreak; // Basic operator or begin paren, don't break next
|
||||
bool m_prependIndent;
|
||||
int m_indentLevel; // Current {} indentation
|
||||
string m_filename;
|
||||
Language m_lang; // Indenting Verilog code
|
||||
int m_blockIndent; // Characters per block indent
|
||||
int m_commaWidth; // Width after which to break at ,'s
|
||||
int m_lineno;
|
||||
int m_column;
|
||||
int m_nobreak; // Basic operator or begin paren, don't break next
|
||||
bool m_prependIndent;
|
||||
int m_indentLevel; // Current {} indentation
|
||||
std::stack<int> m_parenVec; // Stack of columns where last ( was
|
||||
int m_bracketLevel; // Intenting = { block, indicates number of {'s seen.
|
||||
int m_bracketLevel; // Intenting = { block, indicates number of {'s seen.
|
||||
|
||||
int endLevels(const char* strg);
|
||||
void putcNoTracking(char chr);
|
||||
|
|
@ -146,18 +144,26 @@ public:
|
|||
void putsQuoted(const string& strg);
|
||||
void putBreak(); // Print linebreak if line is too wide
|
||||
void putBreakExpr(); // Print linebreak in expression if line is too wide
|
||||
void putbs(const char* strg) { putBreakExpr(); puts(strg); }
|
||||
void putbs(const string& strg) { putBreakExpr(); puts(strg); }
|
||||
void putbs(const char* strg) {
|
||||
putBreakExpr();
|
||||
puts(strg);
|
||||
}
|
||||
void putbs(const string& strg) {
|
||||
putBreakExpr();
|
||||
puts(strg);
|
||||
}
|
||||
bool exceededWidth() const { return m_column > m_commaWidth; }
|
||||
bool tokenStart(const char* cp, const char* cmp);
|
||||
bool tokenEnd(const char* cp);
|
||||
void indentInc() { m_indentLevel += m_blockIndent; }
|
||||
void indentDec() {
|
||||
m_indentLevel -= m_blockIndent;
|
||||
UASSERT(m_indentLevel>=0, ": "<<m_filename<<": Underflow of indentation");
|
||||
UASSERT(m_indentLevel >= 0, ": " << m_filename << ": Underflow of indentation");
|
||||
}
|
||||
void blockInc() { m_parenVec.push(m_indentLevel + m_blockIndent); }
|
||||
void blockDec() { if (!m_parenVec.empty()) m_parenVec.pop(); }
|
||||
void blockDec() {
|
||||
if (!m_parenVec.empty()) m_parenVec.pop();
|
||||
}
|
||||
// STATIC METHODS
|
||||
static const string indentSpaces(int num);
|
||||
// Add escaped characters to strings
|
||||
|
|
@ -172,11 +178,13 @@ public:
|
|||
|
||||
class V3OutFile : public V3OutFormatter {
|
||||
// MEMBERS
|
||||
FILE* m_fp;
|
||||
FILE* m_fp;
|
||||
|
||||
public:
|
||||
V3OutFile(const string& filename, V3OutFormatter::Language lang);
|
||||
virtual ~V3OutFile();
|
||||
void putsForceIncs();
|
||||
|
||||
private:
|
||||
// CALLBACKS
|
||||
virtual void putcOutput(char chr) { fputc(chr, m_fp); }
|
||||
|
|
@ -213,7 +221,8 @@ public:
|
|||
|
||||
class V3OutScFile : public V3OutCFile {
|
||||
public:
|
||||
explicit V3OutScFile(const string& filename) : V3OutCFile(filename) {}
|
||||
explicit V3OutScFile(const string& filename)
|
||||
: V3OutCFile(filename) {}
|
||||
virtual ~V3OutScFile() {}
|
||||
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
|
||||
virtual void putsIntTopInclude() {
|
||||
|
|
@ -262,9 +271,9 @@ 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);
|
||||
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);
|
||||
static string protectWordsIf(const string& old, bool doIt = true);
|
||||
// Write map of renames to output file
|
||||
static void writeMapFile(const string& filename);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
// clang-format off
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
#include "V3String.h"
|
||||
|
|
@ -27,6 +28,7 @@
|
|||
# include "V3Config.h"
|
||||
# include "V3File.h"
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
|
|
@ -39,11 +41,11 @@
|
|||
const string FileLineSingleton::filenameLetters(int fileno) {
|
||||
const int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number
|
||||
char out[size];
|
||||
char* op = out+size-1;
|
||||
char* op = out + size - 1;
|
||||
*--op = '\0'; // We build backwards
|
||||
int num = fileno;
|
||||
do {
|
||||
*--op = 'a'+num%26;
|
||||
*--op = 'a' + num % 26;
|
||||
num /= 26;
|
||||
} while (num);
|
||||
return op;
|
||||
|
|
@ -70,13 +72,13 @@ int FileLineSingleton::nameToNumber(const string& filename) {
|
|||
//! Support XML output
|
||||
//! Experimental. Updated to also put out the language.
|
||||
void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) {
|
||||
os<<"<files>\n";
|
||||
os << "<files>\n";
|
||||
for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) {
|
||||
os<<"<file id=\""<<filenameLetters(it->second)
|
||||
<<"\" filename=\""<<V3OutFormatter::quoteNameControls(it->first, V3OutFormatter::LA_XML)
|
||||
<<"\" language=\""<<numberToLang(it->second).ascii()<<"\"/>\n";
|
||||
os << "<file id=\"" << filenameLetters(it->second) << "\" filename=\""
|
||||
<< V3OutFormatter::quoteNameControls(it->first, V3OutFormatter::LA_XML)
|
||||
<< "\" language=\"" << numberToLang(it->second).ascii() << "\"/>\n";
|
||||
}
|
||||
os<<"</files>\n";
|
||||
os << "</files>\n";
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -95,17 +97,18 @@ void VFileContent::pushText(const string& text) {
|
|||
}
|
||||
|
||||
// Any leftover text is stored on largest line (might be "")
|
||||
string leftover = m_lines.back() + text; m_lines.pop_back();
|
||||
string leftover = m_lines.back() + text;
|
||||
m_lines.pop_back();
|
||||
|
||||
// Insert line-by-line
|
||||
string::size_type line_start = 0;
|
||||
while (true) {
|
||||
string::size_type line_end = leftover.find('\n', line_start);
|
||||
if (line_end != string::npos) {
|
||||
string oneline (leftover, line_start, line_end-line_start+1);
|
||||
string oneline(leftover, line_start, line_end - line_start + 1);
|
||||
m_lines.push_back(oneline); // Keeps newline
|
||||
UINFO(9, "PushStream[ct"<<m_id<<"+"<<(m_lines.size()-1)<<"]: "<<oneline);
|
||||
line_start = line_end+1;
|
||||
UINFO(9, "PushStream[ct" << m_id << "+" << (m_lines.size() - 1) << "]: " << oneline);
|
||||
line_start = line_end + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
|
@ -119,18 +122,22 @@ string VFileContent::getLine(int lineno) const {
|
|||
// cppcheck-suppress negativeContainerIndex
|
||||
if (VL_UNCOVERABLE(lineno < 0 || lineno >= (int)m_lines.size())) {
|
||||
if (debug() || v3Global.opt.debugCheck()) {
|
||||
return ("%Error-internal-contents-bad-ct"+cvtToStr(m_id)
|
||||
+"-ln"+cvtToStr(lineno));
|
||||
} else return "";
|
||||
return ("%Error-internal-contents-bad-ct" + cvtToStr(m_id) + "-ln" + cvtToStr(lineno));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
string text = m_lines[lineno];
|
||||
UINFO(9, "Get Stream[ct"<<m_id<<"+"<<lineno<<"]: "<<text);
|
||||
UINFO(9, "Get Stream[ct" << m_id << "+" << lineno << "]: " << text);
|
||||
return text;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, VFileContent* contentp) {
|
||||
if (!contentp) os <<"ct0";
|
||||
else os <<contentp->ascii();
|
||||
if (!contentp) {
|
||||
os << "ct0";
|
||||
} else {
|
||||
os << contentp->ascii();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
@ -149,7 +156,7 @@ FileLine::FileLine(FileLine::EmptySecret) {
|
|||
m_parent = NULL;
|
||||
|
||||
m_warnOn = 0;
|
||||
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
warnOff(code, code.defaultsOff());
|
||||
}
|
||||
|
|
@ -161,18 +168,17 @@ void FileLine::newContent() {
|
|||
}
|
||||
|
||||
const string FileLine::xmlDetailedLocation() const {
|
||||
return "loc=\"" +
|
||||
cvtToStr(filenameLetters()) + "," +
|
||||
cvtToStr(firstLineno()) + "," +
|
||||
cvtToStr(firstColumn()) + "," +
|
||||
cvtToStr(lastLineno()) + "," +
|
||||
cvtToStr(lastColumn()) + "\"";
|
||||
return "loc=\"" + cvtToStr(filenameLetters()) + "," + cvtToStr(firstLineno()) + ","
|
||||
+ cvtToStr(firstColumn()) + "," + cvtToStr(lastLineno()) + "," + cvtToStr(lastColumn())
|
||||
+ "\"";
|
||||
}
|
||||
|
||||
string FileLine::lineDirectiveStrg(int enterExit) const {
|
||||
char numbuf[20]; sprintf(numbuf, "%d", lastLineno());
|
||||
char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
|
||||
return (string("`line ")+numbuf+" \""+filename()+"\" "+levelbuf+"\n");
|
||||
char numbuf[20];
|
||||
sprintf(numbuf, "%d", lastLineno());
|
||||
char levelbuf[20];
|
||||
sprintf(levelbuf, "%d", enterExit);
|
||||
return (string("`line ") + numbuf + " \"" + filename() + "\" " + levelbuf + "\n");
|
||||
}
|
||||
|
||||
void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
||||
|
|
@ -183,7 +189,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
|||
// Skip `line
|
||||
while (*textp && isspace(*textp)) textp++;
|
||||
while (*textp && !isspace(*textp)) textp++;
|
||||
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
|
||||
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
|
||||
|
||||
// Grab linenumber
|
||||
bool fail = false;
|
||||
|
|
@ -191,22 +197,26 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
|||
while (*textp && !isspace(*textp)) textp++;
|
||||
if (isdigit(*ln)) {
|
||||
lineno(atoi(ln));
|
||||
} else fail = true;
|
||||
} else {
|
||||
fail = true;
|
||||
}
|
||||
while (*textp && (isspace(*textp))) textp++;
|
||||
if (*textp != '"') fail = true;
|
||||
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
|
||||
|
||||
// Grab filename
|
||||
const char* fn = textp;
|
||||
while (*textp && !(isspace(*textp) || *textp=='"')) textp++;
|
||||
while (*textp && !(isspace(*textp) || *textp == '"')) textp++;
|
||||
if (textp != fn) {
|
||||
string strfn = fn;
|
||||
strfn = strfn.substr(0, textp-fn);
|
||||
strfn = strfn.substr(0, textp - fn);
|
||||
filename(strfn);
|
||||
} else fail = true;
|
||||
} else {
|
||||
fail = true;
|
||||
}
|
||||
|
||||
// Grab level
|
||||
while (*textp && (isspace(*textp) || *textp=='"')) textp++;
|
||||
while (*textp && (isspace(*textp) || *textp == '"')) textp++;
|
||||
if (isdigit(*textp)) {
|
||||
enterExitRef = atoi(textp);
|
||||
if (enterExitRef >= 3) fail = true;
|
||||
|
|
@ -219,7 +229,7 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) {
|
|||
v3error("`line was not properly formed with '`line number \"filename\" level'\n");
|
||||
}
|
||||
|
||||
//printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
|
||||
// printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
|
||||
}
|
||||
|
||||
void FileLine::forwardToken(const char* textp, size_t size, bool trackLines) {
|
||||
|
|
@ -254,50 +264,46 @@ FileLine* FileLine::copyOrSameFileLine() {
|
|||
const string FileLine::filebasename() const {
|
||||
string name = filename();
|
||||
string::size_type pos;
|
||||
if ((pos = name.rfind('/')) != string::npos) {
|
||||
name.erase(0, pos+1);
|
||||
}
|
||||
if ((pos = name.rfind('/')) != string::npos) name.erase(0, pos + 1);
|
||||
return name;
|
||||
}
|
||||
|
||||
const string FileLine::filebasenameNoExt() const {
|
||||
string name = filebasename();
|
||||
string::size_type pos;
|
||||
if ((pos = name.find('.')) != string::npos) {
|
||||
name = name.substr(0, pos);
|
||||
}
|
||||
if ((pos = name.find('.')) != string::npos) name = name.substr(0, pos);
|
||||
return name;
|
||||
}
|
||||
|
||||
const string FileLine::profileFuncname() const {
|
||||
// Return string that is OK as a function name - for profiling
|
||||
string name = filebasenameNoExt();
|
||||
string name = filebasenameNoExt();
|
||||
string::size_type pos;
|
||||
while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
|
||||
while ((pos = name.find_first_not_of(
|
||||
"abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
|
||||
!= string::npos) {
|
||||
name.replace(pos, 1, "_");
|
||||
}
|
||||
name += "__l"+cvtToStr(lastLineno());
|
||||
name += "__l" + cvtToStr(lastLineno());
|
||||
return name;
|
||||
}
|
||||
|
||||
string FileLine::asciiLineCol() const {
|
||||
return (cvtToStr(firstLineno())+"-"+cvtToStr(lastLineno())
|
||||
+":"+cvtToStr(firstColumn())+"-"+cvtToStr(lastColumn())
|
||||
+"["+(m_contentp ? m_contentp->ascii() : "ct0")
|
||||
+"+"+cvtToStr(m_contentLineno)+"]");
|
||||
return (cvtToStr(firstLineno()) + "-" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn())
|
||||
+ "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+"
|
||||
+ cvtToStr(m_contentLineno) + "]");
|
||||
}
|
||||
string FileLine::ascii() const {
|
||||
// For most errors especially in the parser the lastLineno is more accurate than firstLineno
|
||||
return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn());
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, FileLine* fileline) {
|
||||
os <<fileline->ascii()<<": "<<std::hex;
|
||||
return(os);
|
||||
os << fileline->ascii() << ": " << std::hex;
|
||||
return (os);
|
||||
}
|
||||
|
||||
bool FileLine::warnOff(const string& msg, bool flag) {
|
||||
V3ErrorCode code (msg.c_str());
|
||||
V3ErrorCode code(msg.c_str());
|
||||
if (code < V3ErrorCode::EC_FIRST_WARN) {
|
||||
return false;
|
||||
#ifndef _V3ERROR_NO_GLOBAL_
|
||||
|
|
@ -312,14 +318,14 @@ bool FileLine::warnOff(const string& msg, bool flag) {
|
|||
}
|
||||
|
||||
void FileLine::warnLintOff(bool flag) {
|
||||
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (code.lintError()) warnOff(code, flag);
|
||||
}
|
||||
}
|
||||
|
||||
void FileLine::warnStyleOff(bool flag) {
|
||||
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (code.styleError()) warnOff(code, flag);
|
||||
}
|
||||
|
|
@ -329,15 +335,16 @@ bool FileLine::warnIsOff(V3ErrorCode code) const {
|
|||
if (!m_warnOn.test(code)) return true;
|
||||
if (!defaultFileLine().m_warnOn.test(code)) return true; // Global overrides local
|
||||
// UNOPTFLAT implies UNOPT
|
||||
if (code==V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
|
||||
if ((code.lintError() || code.styleError())
|
||||
&& !m_warnOn.test(V3ErrorCode::I_LINT)) return true;
|
||||
if (code == V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
|
||||
if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void FileLine::modifyStateInherit(const FileLine* fromp) {
|
||||
// Any warnings that are off in "from", become off in "this".
|
||||
for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
for (int codei = V3ErrorCode::EC_MIN; codei < V3ErrorCode::_ENUM_MAX; codei++) {
|
||||
V3ErrorCode code = V3ErrorCode(codei);
|
||||
if (fromp->warnIsOff(code)) { warnOff(code, true); }
|
||||
}
|
||||
|
|
@ -345,31 +352,33 @@ void FileLine::modifyStateInherit(const FileLine* fromp) {
|
|||
|
||||
void FileLine::v3errorEnd(std::ostringstream& sstr, const string& locationStr) {
|
||||
std::ostringstream nsstr;
|
||||
if (lastLineno()) nsstr<<this;
|
||||
if (lastLineno()) nsstr << this;
|
||||
nsstr << sstr.str();
|
||||
nsstr << endl;
|
||||
std::ostringstream lstr;
|
||||
if (!locationStr.empty()) {
|
||||
lstr<<std::setw(ascii().length())<<" "<<": "<<locationStr;
|
||||
lstr << std::setw(ascii().length()) << " "
|
||||
<< ": " << locationStr;
|
||||
}
|
||||
if (warnIsOff(V3Error::errorCode())
|
||||
|| V3Config::waive(this, V3Error::errorCode(), sstr.str())) {
|
||||
V3Error::suppressThisWarning();
|
||||
} else if (!V3Error::errorContexted()) {
|
||||
nsstr << warnContextPrimary();
|
||||
}
|
||||
else if (!V3Error::errorContexted()) nsstr<<warnContextPrimary();
|
||||
V3Error::v3errorEnd(nsstr, lstr.str());
|
||||
}
|
||||
|
||||
string FileLine::warnMore() const {
|
||||
if (lastLineno()) {
|
||||
return V3Error::warnMore()+string(ascii().size(), ' ')+": ";
|
||||
return V3Error::warnMore() + string(ascii().size(), ' ') + ": ";
|
||||
} else {
|
||||
return V3Error::warnMore();
|
||||
}
|
||||
}
|
||||
string FileLine::warnOther() const {
|
||||
if (lastLineno()) {
|
||||
return V3Error::warnMore()+ascii()+": ";
|
||||
return V3Error::warnMore() + ascii() + ": ";
|
||||
} else {
|
||||
return V3Error::warnMore();
|
||||
}
|
||||
|
|
@ -405,8 +414,7 @@ string FileLine::warnContext(bool secondary) const {
|
|||
if (!sourceLine.empty() && sourceLine.length() < SHOW_SOURCE_MAX_LENGTH
|
||||
&& sourceLine.length() >= static_cast<size_t>(lastColumn() - 1)) {
|
||||
string linestr = cvtToStr(firstLineno());
|
||||
while (linestr.size() < 5)
|
||||
linestr = ' ' + linestr;
|
||||
while (linestr.size() < 5) linestr = ' ' + linestr;
|
||||
out += linestr + " | " + sourceLine + "\n";
|
||||
out += std::string(linestr.size(), ' ') + " | ";
|
||||
out += string((firstColumn() - 1), ' ') + '^';
|
||||
|
|
@ -458,7 +466,7 @@ void FileLine::deleteAllRemaining() {
|
|||
// only when leak checking we'll track them all and cleanup.
|
||||
while (true) {
|
||||
FileLineCheckSet::iterator it = fileLineLeakChecks.begin();
|
||||
if (it==fileLineLeakChecks.end()) break;
|
||||
if (it == fileLineLeakChecks.end()) break;
|
||||
delete *it;
|
||||
// Operator delete will remove the iterated object from the list.
|
||||
// Eventually the list will be empty and terminate the loop.
|
||||
|
|
|
|||
|
|
@ -39,22 +39,27 @@ class FileLine;
|
|||
//! source file (each with its own unique filename number).
|
||||
class FileLineSingleton {
|
||||
// TYPES
|
||||
typedef std::map<string,int> FileNameNumMap;
|
||||
typedef std::map<string,V3LangCode> FileLangNumMap;
|
||||
typedef std::map<string, int> FileNameNumMap;
|
||||
typedef std::map<string, V3LangCode> FileLangNumMap;
|
||||
// MEMBERS
|
||||
FileNameNumMap m_namemap; // filenameno for each filename
|
||||
std::deque<string> m_names; // filename text for each filenameno
|
||||
FileNameNumMap m_namemap; // filenameno for each filename
|
||||
std::deque<string> m_names; // filename text for each filenameno
|
||||
std::deque<V3LangCode> m_languages; // language for each filenameno
|
||||
// CONSTRUCTORS
|
||||
FileLineSingleton() { }
|
||||
~FileLineSingleton() { }
|
||||
FileLineSingleton() {}
|
||||
~FileLineSingleton() {}
|
||||
|
||||
protected:
|
||||
friend class FileLine;
|
||||
int nameToNumber(const string& filename);
|
||||
const string numberToName(int filenameno) const { return m_names[filenameno]; }
|
||||
const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
|
||||
void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
|
||||
void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
|
||||
void clear() {
|
||||
m_namemap.clear();
|
||||
m_names.clear();
|
||||
m_languages.clear();
|
||||
}
|
||||
void fileNameNumMapDumpXml(std::ostream& os);
|
||||
static const string filenameLetters(int fileno);
|
||||
};
|
||||
|
|
@ -65,12 +70,15 @@ class VFileContent {
|
|||
int m_id; // Content ID number
|
||||
std::deque<string> m_lines; // Source text lines
|
||||
public:
|
||||
VFileContent() { static int s_id = 0; m_id = ++s_id; }
|
||||
~VFileContent() { }
|
||||
VFileContent() {
|
||||
static int s_id = 0;
|
||||
m_id = ++s_id;
|
||||
}
|
||||
~VFileContent() {}
|
||||
// METHODS
|
||||
void pushText(const string& text); // Add arbitrary text (need not be line-by-line)
|
||||
string getLine(int lineno) const;
|
||||
string ascii() const { return "ct"+cvtToStr(m_id); }
|
||||
string ascii() const { return "ct" + cvtToStr(m_id); }
|
||||
static int debug();
|
||||
};
|
||||
std::ostream& operator<<(std::ostream& os, VFileContent* contentp);
|
||||
|
|
@ -104,6 +112,7 @@ protected:
|
|||
friend class V3PreLex;
|
||||
friend class V3PreProcImp;
|
||||
friend class V3PreShellImp;
|
||||
|
||||
private:
|
||||
// CONSTRUCTORS
|
||||
static FileLineSingleton& singleton() {
|
||||
|
|
@ -114,6 +123,7 @@ private:
|
|||
static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
|
||||
return *defFilelinep;
|
||||
}
|
||||
|
||||
public:
|
||||
explicit FileLine(const string& filename)
|
||||
: m_firstLineno(0)
|
||||
|
|
@ -139,24 +149,33 @@ public:
|
|||
explicit FileLine(EmptySecret);
|
||||
FileLine* copyOrSameFileLine();
|
||||
static void deleteAllRemaining();
|
||||
~FileLine() { }
|
||||
~FileLine() {}
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
static void* operator new(size_t size);
|
||||
static void operator delete(void* obj, size_t size);
|
||||
#endif
|
||||
// METHODS
|
||||
void newContent();
|
||||
void lineno(int num) { m_firstLineno = num; m_lastLineno = num;
|
||||
m_firstColumn = m_lastColumn = 1; }
|
||||
void lineno(int num) {
|
||||
m_firstLineno = num;
|
||||
m_lastLineno = num;
|
||||
m_firstColumn = m_lastColumn = 1;
|
||||
}
|
||||
void language(V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
|
||||
void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
|
||||
void parent(FileLine* fileline) { m_parent = fileline; }
|
||||
void lineDirective(const char* textp, int& enterExitRef);
|
||||
void linenoInc() { m_lastLineno++; m_lastColumn = 1; m_contentLineno++; }
|
||||
void startToken() { m_firstLineno = m_lastLineno;
|
||||
m_firstColumn = m_lastColumn; }
|
||||
void linenoInc() {
|
||||
m_lastLineno++;
|
||||
m_lastColumn = 1;
|
||||
m_contentLineno++;
|
||||
}
|
||||
void startToken() {
|
||||
m_firstLineno = m_lastLineno;
|
||||
m_firstColumn = m_lastColumn;
|
||||
}
|
||||
// Advance last line/column based on given text
|
||||
void forwardToken(const char* textp, size_t size, bool trackLines=true);
|
||||
void forwardToken(const char* textp, size_t size, bool trackLines = true);
|
||||
int firstLineno() const { return m_firstLineno; }
|
||||
int firstColumn() const { return m_firstColumn; }
|
||||
int lastLineno() const { return m_lastLineno; }
|
||||
|
|
@ -172,13 +191,16 @@ public:
|
|||
string ascii() const;
|
||||
string asciiLineCol() const;
|
||||
const string filename() const { return singleton().numberToName(m_filenameno); }
|
||||
bool filenameIsGlobal() const { return (filename() == commandLineFilename()
|
||||
|| filename() == builtInFilename()); }
|
||||
bool filenameIsGlobal() const {
|
||||
return (filename() == commandLineFilename() || filename() == builtInFilename());
|
||||
}
|
||||
const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); }
|
||||
const string filebasename() const;
|
||||
const string filebasenameNoExt() const;
|
||||
const string profileFuncname() const;
|
||||
const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lastLineno())+"\""; }
|
||||
const string xml() const {
|
||||
return "fl=\"" + filenameLetters() + cvtToStr(lastLineno()) + "\"";
|
||||
}
|
||||
const string xmlDetailedLocation() const;
|
||||
string lineDirectiveStrg(int enterExit) const;
|
||||
|
||||
|
|
@ -202,16 +224,15 @@ public:
|
|||
// <command-line> and <built-in> match what GCC outputs
|
||||
static string commandLineFilename() { return "<command-line>"; }
|
||||
static string builtInFilename() { return "<built-in>"; }
|
||||
static void globalWarnLintOff(bool flag) {
|
||||
defaultFileLine().warnLintOff(flag); }
|
||||
static void globalWarnStyleOff(bool flag) {
|
||||
defaultFileLine().warnStyleOff(flag); }
|
||||
static void globalWarnLintOff(bool flag) { defaultFileLine().warnLintOff(flag); }
|
||||
static void globalWarnStyleOff(bool flag) { defaultFileLine().warnStyleOff(flag); }
|
||||
static void globalWarnOff(V3ErrorCode code, bool flag) {
|
||||
defaultFileLine().warnOff(code, flag); }
|
||||
defaultFileLine().warnOff(code, flag);
|
||||
}
|
||||
static bool globalWarnOff(const string& code, bool flag) {
|
||||
return defaultFileLine().warnOff(code, flag); }
|
||||
static void fileNameNumMapDumpXml(std::ostream& os) {
|
||||
singleton().fileNameNumMapDumpXml(os); }
|
||||
return defaultFileLine().warnOff(code, flag);
|
||||
}
|
||||
static void fileNameNumMapDumpXml(std::ostream& os) { singleton().fileNameNumMapDumpXml(os); }
|
||||
|
||||
// METHODS - Called from netlist
|
||||
// Merge warning disables from another fileline
|
||||
|
|
@ -237,13 +258,11 @@ public:
|
|||
/// Simplified information vs warnContextPrimary() to make dump clearer
|
||||
string warnContextSecondary() const { return warnContext(true); }
|
||||
bool operator==(const FileLine& rhs) const {
|
||||
return (m_firstLineno == rhs.m_firstLineno
|
||||
&& m_firstColumn == rhs.m_firstColumn
|
||||
&& m_lastLineno == rhs.m_lastLineno
|
||||
&& m_lastColumn == rhs.m_lastColumn
|
||||
&& m_filenameno == rhs.m_filenameno
|
||||
&& m_warnOn == rhs.m_warnOn);
|
||||
return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn
|
||||
&& m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn
|
||||
&& m_filenameno == rhs.m_filenameno && m_warnOn == rhs.m_warnOn);
|
||||
}
|
||||
|
||||
private:
|
||||
void v3errorEndFatalGuts(std::ostringstream& str);
|
||||
string warnContext(bool secondary) const;
|
||||
|
|
@ -251,7 +270,9 @@ private:
|
|||
std::ostream& operator<<(std::ostream& os, FileLine* fileline);
|
||||
|
||||
inline void FileLine::v3errorEndFatal(std::ostringstream& str) {
|
||||
v3errorEnd(str); assert(0); VL_UNREACHABLE
|
||||
v3errorEnd(str);
|
||||
assert(0);
|
||||
VL_UNREACHABLE
|
||||
}
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
602
src/V3Gate.cpp
602
src/V3Gate.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -45,13 +45,13 @@ private:
|
|||
// Cleared on top scope
|
||||
// AstVarScope::user2() -> AstVarScope*. Signal replacing activation with
|
||||
// AstVarRef::user3() -> bool. Signal is replaced activation (already done)
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
|
||||
// METHODS
|
||||
AstVarScope* genInpClk(AstVarScope* vscp) {
|
||||
|
|
@ -59,18 +59,19 @@ private:
|
|||
return VN_CAST(vscp->user2p(), VarScope);
|
||||
} else {
|
||||
AstVar* varp = vscp->varp();
|
||||
string newvarname = "__VinpClk__"+vscp->scopep()->nameDotless()+"__"+varp->name();
|
||||
string newvarname
|
||||
= "__VinpClk__" + vscp->scopep()->nameDotless() + "__" + varp->name();
|
||||
// Create: VARREF(inpclk)
|
||||
// ...
|
||||
// ASSIGN(VARREF(inpclk), VARREF(var))
|
||||
AstVar* newvarp = new AstVar(varp->fileline(),
|
||||
AstVarType::MODULETEMP, newvarname, varp);
|
||||
AstVar* newvarp
|
||||
= new AstVar(varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
|
||||
m_topModp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
||||
m_scopetopp->addVarp(newvscp);
|
||||
AstAssign* asninitp = new AstAssign(vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
AstAssign* asninitp
|
||||
= new AstAssign(vscp->fileline(), new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
m_scopetopp->addFinalClkp(asninitp);
|
||||
//
|
||||
vscp->user2p(newvscp);
|
||||
|
|
@ -96,7 +97,7 @@ private:
|
|||
if (m_activep && !nodep->user3()) {
|
||||
nodep->user3(true);
|
||||
if (vscp->isCircular()) {
|
||||
UINFO(8," VarActReplace "<<nodep<<endl);
|
||||
UINFO(8, " VarActReplace " << nodep << endl);
|
||||
// Replace with the new variable
|
||||
AstVarScope* newvscp = genInpClk(vscp);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
|
|
@ -112,9 +113,7 @@ private:
|
|||
m_activep = NULL;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
||||
//-----
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
|
@ -138,13 +137,13 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared on top scope
|
||||
// AstVarScope::user() -> bool. Set when the var has been used as clock
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
bool m_tracingCall; // Iterating into a call to a cfunc
|
||||
AstNodeAssign* m_assignp; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstActive* m_activep; // Inside activate statement
|
||||
bool m_tracingCall; // Iterating into a call to a cfunc
|
||||
AstNodeAssign* m_assignp; // Inside assigndly statement
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
|
|
@ -153,7 +152,7 @@ private:
|
|||
{
|
||||
// Make the new clock signals and replace any activate references
|
||||
// See rename, it does some AstNode::userClearTree()'s
|
||||
GenClkRenameVisitor visitor (nodep, m_topModp);
|
||||
GenClkRenameVisitor visitor(nodep, m_topModp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
|
|
@ -188,24 +187,24 @@ private:
|
|||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
if (m_activep) {
|
||||
UINFO(8," VarAct "<<nodep<<endl);
|
||||
UINFO(8, " VarAct " << nodep << endl);
|
||||
vscp->user1(true);
|
||||
}
|
||||
if (m_assignp && nodep->lvalue() && vscp->user1()) {
|
||||
// Variable was previously used as a clock, and is now being set
|
||||
// Thus a unordered generated clock...
|
||||
UINFO(8," VarSetAct "<<nodep<<endl);
|
||||
UINFO(8, " VarSetAct " << nodep << endl);
|
||||
vscp->circular(true);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
//UINFO(8,"ASS "<<nodep<<endl);
|
||||
// UINFO(8, "ASS " << nodep << endl);
|
||||
m_assignp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_assignp = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
UINFO(8,"ACTIVE "<<nodep<<endl);
|
||||
UINFO(8, "ACTIVE " << nodep << endl);
|
||||
m_activep = nodep;
|
||||
UASSERT_OBJ(nodep->sensesp(), nodep, "Unlinked");
|
||||
iterateChildren(nodep->sensesp()); // iterateAndNext?
|
||||
|
|
@ -233,9 +232,7 @@ public:
|
|||
// GenClk class functions
|
||||
|
||||
void V3GenClk::genClkAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
GenClkReadVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ GenClkReadVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("genclk", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
184
src/V3Graph.cpp
184
src/V3Graph.cpp
|
|
@ -34,13 +34,17 @@ int V3Graph::debug() { return std::max(V3Error::debugDefault(), s_debug); }
|
|||
// Vertices
|
||||
|
||||
V3GraphVertex::V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old)
|
||||
: m_fanout(old.m_fanout), m_color(old.m_color), m_rank(old.m_rank) {
|
||||
: m_fanout(old.m_fanout)
|
||||
, m_color(old.m_color)
|
||||
, m_rank(old.m_rank) {
|
||||
m_userp = NULL;
|
||||
verticesPushBack(graphp);
|
||||
}
|
||||
|
||||
V3GraphVertex::V3GraphVertex(V3Graph* graphp)
|
||||
: m_fanout(0), m_color(0), m_rank(0) {
|
||||
: m_fanout(0)
|
||||
, m_color(0)
|
||||
, m_rank(0) {
|
||||
m_userp = NULL;
|
||||
verticesPushBack(graphp);
|
||||
}
|
||||
|
|
@ -68,13 +72,13 @@ void V3GraphVertex::unlinkDelete(V3Graph* graphp) {
|
|||
// Unlink from vertex list
|
||||
m_vertices.unlink(graphp->m_vertices, this);
|
||||
// Delete
|
||||
delete this; //this=NULL;
|
||||
delete this; // this=NULL;
|
||||
}
|
||||
|
||||
void V3GraphVertex::rerouteEdges(V3Graph* graphp) {
|
||||
// Make new edges for each from/to pair
|
||||
for (V3GraphEdge* iedgep = inBeginp(); iedgep; iedgep=iedgep->inNextp()) {
|
||||
for (V3GraphEdge* oedgep = outBeginp(); oedgep; oedgep=oedgep->outNextp()) {
|
||||
for (V3GraphEdge* iedgep = inBeginp(); iedgep; iedgep = iedgep->inNextp()) {
|
||||
for (V3GraphEdge* oedgep = outBeginp(); oedgep; oedgep = oedgep->outNextp()) {
|
||||
new V3GraphEdge(graphp, iedgep->fromp(), oedgep->top(),
|
||||
std::min(iedgep->weight(), oedgep->weight()),
|
||||
iedgep->cutable() && oedgep->cutable());
|
||||
|
|
@ -84,13 +88,8 @@ void V3GraphVertex::rerouteEdges(V3Graph* graphp) {
|
|||
unlinkEdges(graphp);
|
||||
}
|
||||
|
||||
bool V3GraphVertex::inSize1() const {
|
||||
return !inEmpty() && inBeginp()->inNextp()==NULL;
|
||||
}
|
||||
|
||||
bool V3GraphVertex::outSize1() const {
|
||||
return !outEmpty() && outBeginp()->outNextp()==NULL;
|
||||
}
|
||||
bool V3GraphVertex::inSize1() const { return !inEmpty() && !inBeginp()->inNextp(); }
|
||||
bool V3GraphVertex::outSize1() const { return !outEmpty() && !outBeginp()->outNextp(); }
|
||||
|
||||
uint32_t V3GraphVertex::inHash() const {
|
||||
// We want the same hash ignoring the order of edges.
|
||||
|
|
@ -98,7 +97,7 @@ uint32_t V3GraphVertex::inHash() const {
|
|||
// However with XOR multiple edges to the same source will cancel out,
|
||||
// so we use ADD. (Generally call this only after removing duplicates though)
|
||||
uint32_t hash = 0;
|
||||
for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = this->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
hash += cvtToHash(edgep->fromp());
|
||||
}
|
||||
return hash;
|
||||
|
|
@ -106,14 +105,13 @@ uint32_t V3GraphVertex::inHash() const {
|
|||
|
||||
uint32_t V3GraphVertex::outHash() const {
|
||||
uint32_t hash = 0;
|
||||
for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = this->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
hash += cvtToHash(edgep->top());
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way,
|
||||
const V3GraphVertex* waywardp) {
|
||||
V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVertex* waywardp) {
|
||||
// O(edges) linear search. Searches search both nodes' edge lists in
|
||||
// parallel. The lists probably aren't _both_ huge, so this is
|
||||
// unlikely to blow up even on fairly nasty graphs.
|
||||
|
|
@ -131,10 +129,10 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way,
|
|||
|
||||
void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
|
||||
std::ostringstream nsstr;
|
||||
nsstr<<str.str();
|
||||
nsstr << str.str();
|
||||
if (debug()) {
|
||||
nsstr<<endl;
|
||||
nsstr<<"-vertex: "<<this<<endl;
|
||||
nsstr << endl;
|
||||
nsstr << "-vertex: " << this << endl;
|
||||
}
|
||||
if (!fileline()) {
|
||||
V3Error::v3errorEnd(nsstr);
|
||||
|
|
@ -143,14 +141,16 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const {
|
|||
}
|
||||
}
|
||||
void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const {
|
||||
v3errorEnd(str); assert(0); VL_UNREACHABLE
|
||||
v3errorEnd(str);
|
||||
assert(0);
|
||||
VL_UNREACHABLE
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp) {
|
||||
os<<" VERTEX="<<vertexp->name();
|
||||
if (vertexp->rank()) os<<" r"<<vertexp->rank();
|
||||
if (vertexp->fanout()!=0.0) os<<" f"<<vertexp->fanout();
|
||||
if (vertexp->color()) os<<" c"<<vertexp->color();
|
||||
os << " VERTEX=" << vertexp->name();
|
||||
if (vertexp->rank()) os << " r" << vertexp->rank();
|
||||
if (vertexp->fanout() != 0.0) os << " f" << vertexp->fanout();
|
||||
if (vertexp->color()) os << " c" << vertexp->color();
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
@ -158,8 +158,7 @@ std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp) {
|
|||
//######################################################################
|
||||
// Edges
|
||||
|
||||
void V3GraphEdge::init(V3Graph* graphp,
|
||||
V3GraphVertex* fromp, V3GraphVertex* top, int weight,
|
||||
void V3GraphEdge::init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
|
||||
bool cutable) {
|
||||
UASSERT(fromp, "Null from pointer");
|
||||
UASSERT(top, "Null to pointer");
|
||||
|
|
@ -174,7 +173,7 @@ void V3GraphEdge::init(V3Graph* graphp,
|
|||
}
|
||||
|
||||
V3GraphEdge* V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) {
|
||||
V3GraphEdge *oldNxt = outNextp();
|
||||
V3GraphEdge* oldNxt = outNextp();
|
||||
m_outs.unlink(m_fromp->m_outs, this);
|
||||
m_fromp = newFromp;
|
||||
outPushBack();
|
||||
|
|
@ -187,7 +186,7 @@ void V3GraphEdge::unlinkDelete() {
|
|||
// Unlink to side
|
||||
m_ins.unlink(m_top->m_ins, this);
|
||||
// Delete
|
||||
delete this; //this=NULL;
|
||||
delete this; // this=NULL;
|
||||
}
|
||||
|
||||
void V3GraphEdge::outPushBack() {
|
||||
|
|
@ -210,14 +209,12 @@ V3Graph::V3Graph() {
|
|||
verticesUnlink();
|
||||
}
|
||||
|
||||
V3Graph::~V3Graph() {
|
||||
clear();
|
||||
}
|
||||
V3Graph::~V3Graph() { clear(); }
|
||||
|
||||
void V3Graph::clear() {
|
||||
// Empty it of all points, as if making a new object
|
||||
// Delete the old edges
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; /*BELOW*/) {
|
||||
V3GraphEdge* nextp = edgep->outNextp();
|
||||
VL_DO_DANGLING(delete edgep, edgep);
|
||||
|
|
@ -241,7 +238,7 @@ void V3Graph::userClearVertices() {
|
|||
// the graph pointer given a vertex.) For now we don't call this often, and
|
||||
// the extra code on each read of user() would probably slow things
|
||||
// down more than help.
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->user(0);
|
||||
vertexp->userp(NULL); // Its a union, but might be different size than user()
|
||||
}
|
||||
|
|
@ -249,8 +246,8 @@ void V3Graph::userClearVertices() {
|
|||
|
||||
void V3Graph::userClearEdges() {
|
||||
// Clear user() in all of tree
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edgep->user(0);
|
||||
edgep->userp(NULL); // Its a union, but might be different size than user()
|
||||
}
|
||||
|
|
@ -259,7 +256,7 @@ void V3Graph::userClearEdges() {
|
|||
|
||||
void V3Graph::clearColors() {
|
||||
// Reset colors
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->m_color = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -268,72 +265,70 @@ void V3Graph::clearColors() {
|
|||
// Dumping
|
||||
|
||||
void V3Graph::loopsMessageCb(V3GraphVertex* vertexp) {
|
||||
vertexp->v3fatalSrc("Loops detected in graph: "<<vertexp);
|
||||
vertexp->v3fatalSrc("Loops detected in graph: " << vertexp);
|
||||
}
|
||||
|
||||
void V3Graph::loopsVertexCb(V3GraphVertex* vertexp) {
|
||||
// Needed here as V3GraphVertex<< isn't defined until later in header
|
||||
if (debug()) std::cerr<<"-Info-Loop: "<<cvtToHex(vertexp)<<" "<<vertexp<<endl;
|
||||
if (debug()) std::cerr << "-Info-Loop: " << cvtToHex(vertexp) << " " << vertexp << endl;
|
||||
}
|
||||
|
||||
void V3Graph::dump(std::ostream& os) {
|
||||
// This generates a file used by graphviz, https://www.graphviz.org
|
||||
os<<" Graph:\n";
|
||||
os << " Graph:\n";
|
||||
// Print vertices
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
os<<"\tNode: "<<vertexp->name();
|
||||
if (vertexp->color()) os<<" color="<<vertexp->color();
|
||||
os<<endl;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
os << "\tNode: " << vertexp->name();
|
||||
if (vertexp->color()) os << " color=" << vertexp->color();
|
||||
os << endl;
|
||||
// Print edges
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
dumpEdge(os, vertexp, edgep);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
dumpEdge(os, vertexp, edgep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void V3Graph::dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* edgep) {
|
||||
if (edgep->weight()
|
||||
&& (edgep->fromp() == vertexp
|
||||
|| edgep->top() == vertexp)) {
|
||||
os<<"\t\t";
|
||||
if (edgep->fromp() == vertexp) os << "-> "<<edgep->top()->name();
|
||||
if (edgep->top() == vertexp) os << "<- "<<edgep->fromp()->name();
|
||||
if (edgep->cutable()) os<<" [CUTABLE]";
|
||||
os<<endl;
|
||||
if (edgep->weight() && (edgep->fromp() == vertexp || edgep->top() == vertexp)) {
|
||||
os << "\t\t";
|
||||
if (edgep->fromp() == vertexp) os << "-> " << edgep->top()->name();
|
||||
if (edgep->top() == vertexp) os << "<- " << edgep->fromp()->name();
|
||||
if (edgep->cutable()) os << " [CUTABLE]";
|
||||
os << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph) const {
|
||||
if (v3Global.opt.dumpTree()) {
|
||||
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
|
||||
dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph);
|
||||
}
|
||||
}
|
||||
|
||||
//! Variant of dumpDotFilePrefixed without --dump option check
|
||||
void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) const {
|
||||
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
|
||||
dumpDotFile(v3Global.debugFilename(nameComment) + ".dot", colorAsSubgraph);
|
||||
}
|
||||
|
||||
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
||||
// This generates a file used by graphviz, https://www.graphviz.org
|
||||
// "hardcoded" parameters:
|
||||
const vl_unique_ptr<std::ofstream> logp (V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write "<<filename);
|
||||
const vl_unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write " << filename);
|
||||
|
||||
// Header
|
||||
*logp<<"digraph v3graph {\n";
|
||||
*logp<<"\tgraph\t[label=\""<<filename<<"\",\n";
|
||||
*logp<<"\t\t labelloc=t, labeljust=l,\n";
|
||||
*logp<<"\t\t //size="<<"\"7.5,10\","<<"\n";
|
||||
*logp<<"\t\t rankdir="<<dotRankDir()<<"];\n";
|
||||
*logp << "digraph v3graph {\n";
|
||||
*logp << "\tgraph\t[label=\"" << filename << "\",\n";
|
||||
*logp << "\t\t labelloc=t, labeljust=l,\n";
|
||||
*logp << "\t\t //size=\"7.5,10\",\n";
|
||||
*logp << "\t\t rankdir=" << dotRankDir() << "];\n";
|
||||
|
||||
// List of all possible subgraphs
|
||||
typedef std::multimap<string,V3GraphVertex*> SubgraphMmap;
|
||||
typedef std::multimap<string, V3GraphVertex*> SubgraphMmap;
|
||||
SubgraphMmap subgraphs;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
string vertexSubgraph
|
||||
= (colorAsSubgraph && vertexp->color()) ? cvtToStr(vertexp->color()) : "";
|
||||
subgraphs.insert(make_pair(vertexSubgraph, vertexp));
|
||||
|
|
@ -341,7 +336,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
|||
|
||||
// We use a map here, as we don't want to corrupt anything (userp) in the graph,
|
||||
// and we don't care if this is slow.
|
||||
std::map<V3GraphVertex*,int> numMap;
|
||||
std::map<V3GraphVertex*, int> numMap;
|
||||
|
||||
// Print vertices
|
||||
int n = 0;
|
||||
|
|
@ -351,42 +346,41 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
|||
V3GraphVertex* vertexp = it->second;
|
||||
numMap[vertexp] = n;
|
||||
if (subgr != vertexSubgraph) {
|
||||
if (subgr!="") *logp<<"\t};\n";
|
||||
if (subgr != "") *logp << "\t};\n";
|
||||
subgr = vertexSubgraph;
|
||||
if (subgr!="") *logp<<"\tsubgraph cluster_"<<subgr<<" {\n";
|
||||
if (subgr != "") *logp << "\tsubgraph cluster_" << subgr << " {\n";
|
||||
}
|
||||
if (subgr!="") *logp<<"\t";
|
||||
*logp<<"\tn"<<vertexp->dotName()<<(n++)
|
||||
<<"\t[fontsize=8 "
|
||||
<<"label=\""<<(vertexp->name()!="" ? vertexp->name() : "\\N");
|
||||
if (vertexp->rank()) *logp<<" r"<<vertexp->rank();
|
||||
if (vertexp->fanout()!=0.0) *logp<<" f"<<vertexp->fanout();
|
||||
if (vertexp->color()) *logp<<"\\n c"<<vertexp->color();
|
||||
*logp<<"\"";
|
||||
*logp<<", color="<<vertexp->dotColor();
|
||||
if (vertexp->dotStyle()!="") *logp<<", style="<<vertexp->dotStyle();
|
||||
if (vertexp->dotShape()!="") *logp<<", shape="<<vertexp->dotShape();
|
||||
*logp<<"];\n";
|
||||
if (subgr != "") *logp << "\t";
|
||||
*logp << "\tn" << vertexp->dotName() << (n++) << "\t[fontsize=8 "
|
||||
<< "label=\"" << (vertexp->name() != "" ? vertexp->name() : "\\N");
|
||||
if (vertexp->rank()) *logp << " r" << vertexp->rank();
|
||||
if (vertexp->fanout() != 0.0) *logp << " f" << vertexp->fanout();
|
||||
if (vertexp->color()) *logp << "\\n c" << vertexp->color();
|
||||
*logp << "\"";
|
||||
*logp << ", color=" << vertexp->dotColor();
|
||||
if (vertexp->dotStyle() != "") *logp << ", style=" << vertexp->dotStyle();
|
||||
if (vertexp->dotShape() != "") *logp << ", shape=" << vertexp->dotShape();
|
||||
*logp << "];\n";
|
||||
}
|
||||
if (subgr!="") *logp<<"\t};\n";
|
||||
if (subgr != "") *logp << "\t};\n";
|
||||
|
||||
// Print edges
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (edgep->weight()) {
|
||||
int fromVnum = numMap[edgep->fromp()];
|
||||
int toVnum = numMap[edgep->top()];
|
||||
*logp<<"\tn"<<edgep->fromp()->dotName()<<fromVnum
|
||||
<<" -> n"<<edgep->top()->dotName()<<toVnum
|
||||
<<" ["
|
||||
//<<"fontsize=8 label=\""<<(edgep->name()!="" ? edgep->name() : "\\E")<<"\""
|
||||
<<"fontsize=8 label=\""
|
||||
<<(edgep->dotLabel()!="" ? edgep->dotLabel() : "")<<"\""
|
||||
<<" weight="<<edgep->weight()
|
||||
<<" color="<<edgep->dotColor();
|
||||
if (edgep->dotStyle()!="") *logp<<" style="<<edgep->dotStyle();
|
||||
//if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without following edges
|
||||
*logp<<"];\n";
|
||||
int toVnum = numMap[edgep->top()];
|
||||
*logp << "\tn" << edgep->fromp()->dotName() << fromVnum << " -> n"
|
||||
<< edgep->top()->dotName() << toVnum
|
||||
<< " ["
|
||||
//<<"fontsize=8 label=\""<<(edgep->name()!="" ? edgep->name() : "\\E")<<"\""
|
||||
<< "fontsize=8 label=\""
|
||||
<< (edgep->dotLabel() != "" ? edgep->dotLabel() : "") << "\""
|
||||
<< " weight=" << edgep->weight() << " color=" << edgep->dotColor();
|
||||
if (edgep->dotStyle() != "") *logp << " style=" << edgep->dotStyle();
|
||||
// if (edgep->cutable()) { *logp<<",constraint=false"; } // to rank without
|
||||
// following edges
|
||||
*logp << "];\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -396,5 +390,5 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const {
|
|||
*logp << "}\n";
|
||||
logp->close();
|
||||
|
||||
cout << "dot -Tpdf -o ~/a.pdf "<<filename<<endl;
|
||||
cout << "dot -Tpdf -o ~/a.pdf " << filename << endl;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,19 +32,20 @@
|
|||
|
||||
class GraphAcycVertex : public V3GraphVertex {
|
||||
// user() is used for various sub-algorithm pieces
|
||||
V3GraphVertex* m_origVertexp; // Pointer to first vertex this represents
|
||||
V3GraphVertex* m_origVertexp; // Pointer to first vertex this represents
|
||||
protected:
|
||||
friend class GraphAcyc;
|
||||
V3ListEnt<GraphAcycVertex*> m_work; // List of vertices with optimization work left
|
||||
uint32_t m_storedRank; // Rank held until commit to edge placement
|
||||
bool m_onWorkList; // True if already on list of work to do
|
||||
bool m_deleted; // True if deleted
|
||||
V3ListEnt<GraphAcycVertex*> m_work; // List of vertices with optimization work left
|
||||
uint32_t m_storedRank; // Rank held until commit to edge placement
|
||||
bool m_onWorkList; // True if already on list of work to do
|
||||
bool m_deleted; // True if deleted
|
||||
public:
|
||||
|
||||
GraphAcycVertex(V3Graph* graphp, V3GraphVertex* origVertexp)
|
||||
: V3GraphVertex(graphp), m_origVertexp(origVertexp)
|
||||
, m_storedRank(0), m_onWorkList(false), m_deleted(false) {
|
||||
}
|
||||
: V3GraphVertex(graphp)
|
||||
, m_origVertexp(origVertexp)
|
||||
, m_storedRank(0)
|
||||
, m_onWorkList(false)
|
||||
, m_deleted(false) {}
|
||||
virtual ~GraphAcycVertex() {}
|
||||
V3GraphVertex* origVertexp() const { return m_origVertexp; }
|
||||
void setDelete() { m_deleted = true; }
|
||||
|
|
@ -60,25 +61,25 @@ class GraphAcycEdge : public V3GraphEdge {
|
|||
// userp() is always used to point to the head original graph edge
|
||||
private:
|
||||
typedef std::list<V3GraphEdge*> OrigEdgeList; // List of orig edges, see also GraphAcyc's decl
|
||||
V3GraphEdge* origEdgep() const {
|
||||
V3GraphEdge* origEdgep() const {
|
||||
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(userp());
|
||||
if (!oEListp) v3fatalSrc("No original edge associated with acyc edge "<<this<<endl);
|
||||
if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this << endl);
|
||||
return (oEListp->front());
|
||||
}
|
||||
|
||||
public:
|
||||
GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
|
||||
int weight, bool cutable=false)
|
||||
: V3GraphEdge(graphp, fromp, top, weight, cutable) {
|
||||
}
|
||||
GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
|
||||
bool cutable = false)
|
||||
: V3GraphEdge(graphp, fromp, top, weight, cutable) {}
|
||||
virtual ~GraphAcycEdge() {}
|
||||
// yellow=we might still cut it, else oldEdge: yellowGreen=made uncutable, red=uncutable
|
||||
virtual string dotColor() const { return (cutable()?"yellow":origEdgep()->dotColor()); }
|
||||
virtual string dotColor() const { return (cutable() ? "yellow" : origEdgep()->dotColor()); }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
struct GraphAcycEdgeCmp {
|
||||
inline bool operator() (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
|
||||
inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
|
||||
if (lhsp->weight() > rhsp->weight()) return 1; // LHS goes first
|
||||
if (lhsp->weight() < rhsp->weight()) return 0; // RHS goes first
|
||||
return 0;
|
||||
|
|
@ -90,7 +91,8 @@ struct GraphAcycEdgeCmp {
|
|||
// CLASSES
|
||||
class GraphAcyc {
|
||||
private:
|
||||
typedef std::list<V3GraphEdge*> OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl
|
||||
typedef std::list<V3GraphEdge*>
|
||||
OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl
|
||||
// GRAPH USERS
|
||||
// origGraph
|
||||
// GraphVertex::user() GraphAycVerted* New graph node
|
||||
|
|
@ -98,12 +100,12 @@ private:
|
|||
// GraphEdge::user() OrigEdgeList* Old graph edges
|
||||
// GraphVertex::user bool Detection of loops in simplifyDupIterate
|
||||
// MEMBERS
|
||||
V3Graph* m_origGraphp; // Original graph
|
||||
V3Graph m_breakGraph; // Graph with only breakable edges represented
|
||||
V3List<GraphAcycVertex*> m_work; // List of vertices with optimization work left
|
||||
V3Graph* m_origGraphp; // Original graph
|
||||
V3Graph m_breakGraph; // Graph with only breakable edges represented
|
||||
V3List<GraphAcycVertex*> m_work; // List of vertices with optimization work left
|
||||
std::vector<OrigEdgeList*> m_origEdgeDelp; // List of deletions to do when done
|
||||
V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
|
||||
uint32_t m_placeStep; // Number that user() must be equal to to indicate processing
|
||||
V3EdgeFuncP m_origEdgeFuncp; // Function that says we follow this edge (in original graph)
|
||||
uint32_t m_placeStep; // Number that user() must be equal to to indicate processing
|
||||
|
||||
static int debug() { return V3Graph::debug(); }
|
||||
|
||||
|
|
@ -127,8 +129,8 @@ private:
|
|||
}
|
||||
V3GraphEdge* edgeFromEdge(V3GraphEdge* oldedgep, V3GraphVertex* fromp, V3GraphVertex* top) {
|
||||
// Make new breakGraph edge, with old edge as a template
|
||||
GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top,
|
||||
oldedgep->weight(), oldedgep->cutable());
|
||||
GraphAcycEdge* newEdgep = new GraphAcycEdge(&m_breakGraph, fromp, top, oldedgep->weight(),
|
||||
oldedgep->cutable());
|
||||
newEdgep->userp(oldedgep->userp()); // Keep pointer to OrigEdgeList
|
||||
return newEdgep;
|
||||
}
|
||||
|
|
@ -153,16 +155,18 @@ private:
|
|||
}
|
||||
void cutOrigEdge(V3GraphEdge* breakEdgep, const char* why) {
|
||||
// From the break edge, cut edges in original graph it represents
|
||||
UINFO(8,why<<" CUT "<<breakEdgep->fromp()<<endl);
|
||||
UINFO(8, why << " CUT " << breakEdgep->fromp() << endl);
|
||||
breakEdgep->cut();
|
||||
OrigEdgeList* oEListp = static_cast<OrigEdgeList*>(breakEdgep->userp());
|
||||
if (!oEListp) v3fatalSrc("No original edge associated with cutting edge "
|
||||
<<breakEdgep<<endl);
|
||||
if (!oEListp) {
|
||||
v3fatalSrc("No original edge associated with cutting edge " << breakEdgep << endl);
|
||||
}
|
||||
// The breakGraph edge may represent multiple real edges; cut them all
|
||||
for (OrigEdgeList::iterator it = oEListp->begin(); it != oEListp->end(); ++it) {
|
||||
V3GraphEdge* origEdgep = *it;
|
||||
origEdgep->cut();
|
||||
UINFO(8," "<<why<<" "<<origEdgep->fromp()<<" ->"<<origEdgep->top()<<endl);
|
||||
UINFO(8,
|
||||
" " << why << " " << origEdgep->fromp() << " ->" << origEdgep->top() << endl);
|
||||
}
|
||||
}
|
||||
// Work Queue
|
||||
|
|
@ -178,7 +182,9 @@ private:
|
|||
void workPop() {
|
||||
GraphAcycVertex* avertexp = workBeginp();
|
||||
avertexp->m_onWorkList = false;
|
||||
avertexp->m_work.unlink(m_work, avertexp); }
|
||||
avertexp->m_work.unlink(m_work, avertexp);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
GraphAcyc(V3Graph* origGraphp, V3EdgeFuncP edgeFuncp) {
|
||||
|
|
@ -205,8 +211,8 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
|
|||
// For each old node, make a new graph node for optimization
|
||||
origGraphp->userClearVertices();
|
||||
origGraphp->userClearEdges();
|
||||
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp();
|
||||
overtexp; overtexp = overtexp->verticesNextp()) {
|
||||
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
|
||||
overtexp = overtexp->verticesNextp()) {
|
||||
if (overtexp->color()) {
|
||||
GraphAcycVertex* avertexp = new GraphAcycVertex(&m_breakGraph, overtexp);
|
||||
overtexp->userp(avertexp); // Stash so can look up later
|
||||
|
|
@ -214,8 +220,8 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
|
|||
}
|
||||
|
||||
// Build edges between logic vertices
|
||||
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp();
|
||||
overtexp; overtexp = overtexp->verticesNextp()) {
|
||||
for (V3GraphVertex* overtexp = origGraphp->verticesBeginp(); overtexp;
|
||||
overtexp = overtexp->verticesNextp()) {
|
||||
if (overtexp->color()) {
|
||||
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(overtexp->userp());
|
||||
buildGraphIterate(overtexp, avertexp);
|
||||
|
|
@ -225,15 +231,15 @@ void GraphAcyc::buildGraph(V3Graph* origGraphp) {
|
|||
|
||||
void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* avertexp) {
|
||||
// Make new edges
|
||||
for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = overtexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (origFollowEdge(edgep)) { // not cut
|
||||
V3GraphVertex* toVertexp = edgep->top();
|
||||
if (toVertexp->color()) {
|
||||
GraphAcycVertex* toAVertexp = static_cast<GraphAcycVertex*>(toVertexp->userp());
|
||||
// Replicate the old edge into the new graph
|
||||
// There may be multiple edges between same pairs of vertices
|
||||
V3GraphEdge* breakEdgep = new GraphAcycEdge
|
||||
(&m_breakGraph, avertexp, toAVertexp, edgep->weight(), edgep->cutable());
|
||||
V3GraphEdge* breakEdgep = new GraphAcycEdge(&m_breakGraph, avertexp, toAVertexp,
|
||||
edgep->weight(), edgep->cutable());
|
||||
addOrigEdgep(breakEdgep, edgep); // So can find original edge
|
||||
}
|
||||
}
|
||||
|
|
@ -242,8 +248,8 @@ void GraphAcyc::buildGraphIterate(V3GraphVertex* overtexp, GraphAcycVertex* aver
|
|||
|
||||
void GraphAcyc::simplify(bool allowCut) {
|
||||
// Add all nodes to list of work to do
|
||||
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp();
|
||||
vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
workPush(vertexp);
|
||||
}
|
||||
// Optimize till everything finished
|
||||
|
|
@ -267,7 +273,8 @@ void GraphAcyc::simplify(bool allowCut) {
|
|||
|
||||
void GraphAcyc::deleteMarked() {
|
||||
// Delete nodes marked for removal
|
||||
for (V3GraphVertex* nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp; vertexp=nextp) {
|
||||
for (V3GraphVertex *nextp, *vertexp = m_breakGraph.verticesBeginp(); vertexp;
|
||||
vertexp = nextp) {
|
||||
nextp = vertexp->verticesNextp();
|
||||
GraphAcycVertex* avertexp = static_cast<GraphAcycVertex*>(vertexp);
|
||||
if (avertexp->isDelete()) {
|
||||
|
|
@ -281,18 +288,18 @@ void GraphAcyc::simplifyNone(GraphAcycVertex* avertexp) {
|
|||
// Likewise, vertices with no outputs
|
||||
if (avertexp->isDelete()) return;
|
||||
if (avertexp->inEmpty() || avertexp->outEmpty()) {
|
||||
UINFO(9," SimplifyNoneRemove "<<avertexp<<endl);
|
||||
UINFO(9, " SimplifyNoneRemove " << avertexp << endl);
|
||||
avertexp->setDelete(); // Mark so we won't delete it twice
|
||||
// Remove edges
|
||||
while (V3GraphEdge* edgep = avertexp->outBeginp()) {
|
||||
V3GraphVertex* otherVertexp = edgep->top();
|
||||
//UINFO(9," out "<<otherVertexp<<endl);
|
||||
// UINFO(9, " out " << otherVertexp << endl);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(otherVertexp);
|
||||
}
|
||||
while (V3GraphEdge* edgep = avertexp->inBeginp()) {
|
||||
V3GraphVertex* otherVertexp = edgep->fromp();
|
||||
//UINFO(9," in "<<otherVertexp<<endl);
|
||||
// UINFO(9, " in " << otherVertexp << endl);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(otherVertexp);
|
||||
}
|
||||
|
|
@ -309,23 +316,25 @@ void GraphAcyc::simplifyOne(GraphAcycVertex* avertexp) {
|
|||
V3GraphVertex* outVertexp = outEdgep->top();
|
||||
// The in and out may be the same node; we'll make a loop
|
||||
// The in OR out may be THIS node; we can't delete it then.
|
||||
if (inVertexp!=avertexp && outVertexp!=avertexp) {
|
||||
UINFO(9," SimplifyOneRemove "<<avertexp<<endl);
|
||||
if (inVertexp != avertexp && outVertexp != avertexp) {
|
||||
UINFO(9, " SimplifyOneRemove " << avertexp << endl);
|
||||
avertexp->setDelete(); // Mark so we won't delete it twice
|
||||
// Make a new edge connecting the two vertices directly
|
||||
// If both are breakable, we pick the one with less weight, else it's arbitrary
|
||||
// We can forget about the origEdge list for the "non-selected" set of edges,
|
||||
// as we need to break only one set or the other set of edges, not both.
|
||||
// (This is why we must give preference to the cutable set.)
|
||||
V3GraphEdge* templateEdgep = ( (inEdgep->cutable()
|
||||
&& (!outEdgep->cutable()
|
||||
|| inEdgep->weight()<outEdgep->weight() ))
|
||||
? inEdgep : outEdgep);
|
||||
V3GraphEdge* templateEdgep
|
||||
= ((inEdgep->cutable()
|
||||
&& (!outEdgep->cutable() || inEdgep->weight() < outEdgep->weight()))
|
||||
? inEdgep
|
||||
: outEdgep);
|
||||
// cppcheck-suppress leakReturnValNotUsed
|
||||
edgeFromEdge(templateEdgep, inVertexp, outVertexp);
|
||||
// Remove old edge
|
||||
VL_DO_DANGLING(inEdgep->unlinkDelete(), inEdgep);
|
||||
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep); VL_DANGLING(templateEdgep);
|
||||
VL_DO_DANGLING(outEdgep->unlinkDelete(), outEdgep);
|
||||
VL_DANGLING(templateEdgep);
|
||||
workPush(inVertexp);
|
||||
workPush(outVertexp);
|
||||
}
|
||||
|
|
@ -340,16 +349,17 @@ void GraphAcyc::simplifyOut(GraphAcycVertex* avertexp) {
|
|||
V3GraphEdge* outEdgep = avertexp->outBeginp();
|
||||
if (!outEdgep->cutable()) {
|
||||
V3GraphVertex* outVertexp = outEdgep->top();
|
||||
UINFO(9," SimplifyOutRemove "<<avertexp<<endl);
|
||||
UINFO(9, " SimplifyOutRemove " << avertexp << endl);
|
||||
avertexp->setDelete(); // Mark so we won't delete it twice
|
||||
for (V3GraphEdge* nextp, *inEdgep = avertexp->inBeginp(); inEdgep; inEdgep=nextp) {
|
||||
for (V3GraphEdge *nextp, *inEdgep = avertexp->inBeginp(); inEdgep; inEdgep = nextp) {
|
||||
nextp = inEdgep->inNextp();
|
||||
V3GraphVertex* inVertexp = inEdgep->fromp();
|
||||
if (inVertexp == avertexp) {
|
||||
if (debug()) v3error("Non-cutable edge forms a loop, vertex="<<avertexp);
|
||||
if (debug()) v3error("Non-cutable edge forms a loop, vertex=" << avertexp);
|
||||
v3error("Circular logic when ordering code (non-cutable edge loop)");
|
||||
m_origGraphp->reportLoops(&V3GraphEdge::followNotCutable,
|
||||
avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb
|
||||
m_origGraphp->reportLoops(
|
||||
&V3GraphEdge::followNotCutable,
|
||||
avertexp->origVertexp()); // calls OrderGraph::loopsVertexCb
|
||||
// Things are unlikely to end well at this point,
|
||||
// but we'll try something to get to further errors...
|
||||
inEdgep->cutable(true);
|
||||
|
|
@ -372,11 +382,11 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
|
|||
// Remove redundant edges
|
||||
if (avertexp->isDelete()) return;
|
||||
// Clear marks
|
||||
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edgep->top()->userp(NULL);
|
||||
}
|
||||
// Mark edges and detect duplications
|
||||
for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) {
|
||||
for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
V3GraphVertex* outVertexp = edgep->top();
|
||||
V3GraphEdge* prevEdgep = static_cast<V3GraphEdge*>(outVertexp->userp());
|
||||
|
|
@ -384,16 +394,16 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
|
|||
if (!prevEdgep->cutable()) {
|
||||
// !cutable duplicates prev !cutable: we can ignore it, redundant
|
||||
// cutable duplicates prev !cutable: know it's not a relevant loop, ignore it
|
||||
UINFO(8," DelDupEdge "<<avertexp<<" -> "<<edgep->top()<<endl);
|
||||
UINFO(8, " DelDupEdge " << avertexp << " -> " << edgep->top() << endl);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
} else if (!edgep->cutable()) {
|
||||
// !cutable duplicates prev cutable: delete the earlier cutable
|
||||
UINFO(8," DelDupPrev "<<avertexp<<" -> "<<prevEdgep->top()<<endl);
|
||||
UINFO(8, " DelDupPrev " << avertexp << " -> " << prevEdgep->top() << endl);
|
||||
VL_DO_DANGLING(prevEdgep->unlinkDelete(), prevEdgep);
|
||||
outVertexp->userp(edgep);
|
||||
} else {
|
||||
// cutable duplicates prev cutable: combine weights
|
||||
UINFO(8," DelDupComb "<<avertexp<<" -> "<<edgep->top()<<endl);
|
||||
UINFO(8, " DelDupComb " << avertexp << " -> " << edgep->top() << endl);
|
||||
prevEdgep->weight(prevEdgep->weight() + edgep->weight());
|
||||
addOrigEdgep(prevEdgep, edgep);
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
|
|
@ -410,9 +420,9 @@ void GraphAcyc::simplifyDup(GraphAcycVertex* avertexp) {
|
|||
void GraphAcyc::cutBasic(GraphAcycVertex* avertexp) {
|
||||
// Detect and cleanup any loops from node to itself
|
||||
if (avertexp->isDelete()) return;
|
||||
for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) {
|
||||
for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
if (edgep->cutable() && edgep->top()==avertexp) {
|
||||
if (edgep->cutable() && edgep->top() == avertexp) {
|
||||
cutOrigEdge(edgep, " Cut Basic");
|
||||
VL_DO_DANGLING(edgep->unlinkDelete(), edgep);
|
||||
workPush(avertexp);
|
||||
|
|
@ -424,14 +434,14 @@ void GraphAcyc::cutBackward(GraphAcycVertex* avertexp) {
|
|||
// If a cutable edge is from A->B, and there's a non-cutable edge B->A, then must cut!
|
||||
if (avertexp->isDelete()) return;
|
||||
// Clear marks
|
||||
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = avertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edgep->top()->user(false);
|
||||
}
|
||||
for (V3GraphEdge* edgep = avertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = avertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (!edgep->cutable()) edgep->fromp()->user(true);
|
||||
}
|
||||
// Detect duplications
|
||||
for (V3GraphEdge* nextp, *edgep = avertexp->outBeginp(); edgep; edgep=nextp) {
|
||||
for (V3GraphEdge *nextp, *edgep = avertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
if (edgep->cutable() && edgep->top()->user()) {
|
||||
cutOrigEdge(edgep, " Cut A->B->A");
|
||||
|
|
@ -446,25 +456,22 @@ void GraphAcyc::place() {
|
|||
|
||||
// Make a list of all cutable edges in the graph
|
||||
int numEdges = 0;
|
||||
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp();
|
||||
vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (edgep->weight() && edgep->cutable()) {
|
||||
numEdges++;
|
||||
}
|
||||
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (edgep->weight() && edgep->cutable()) ++numEdges;
|
||||
}
|
||||
}
|
||||
UINFO(4, " Cutable edges = "<<numEdges<<endl);
|
||||
UINFO(4, " Cutable edges = " << numEdges << endl);
|
||||
|
||||
std::vector<V3GraphEdge*> edges; // List of all edges to be processed
|
||||
edges.reserve(numEdges+1); // Make the vector properly sized right off the bat -- faster than reallocating
|
||||
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp();
|
||||
vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
// Make the vector properly sized right off the bat -- faster than reallocating
|
||||
edges.reserve(numEdges + 1);
|
||||
for (V3GraphVertex* vertexp = m_breakGraph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->user(0); // Clear in prep of next step
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (edgep->weight() && edgep->cutable()) {
|
||||
edges.push_back(edgep);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (edgep->weight() && edgep->cutable()) edges.push_back(edgep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +480,7 @@ void GraphAcyc::place() {
|
|||
|
||||
// Process each edge in weighted order
|
||||
m_placeStep = 10;
|
||||
for (std::vector<V3GraphEdge*>::iterator it = edges.begin(); it!=edges.end(); ++it) {
|
||||
for (std::vector<V3GraphEdge*>::iterator it = edges.begin(); it != edges.end(); ++it) {
|
||||
V3GraphEdge* edgep = (*it);
|
||||
placeTryEdge(edgep);
|
||||
}
|
||||
|
|
@ -482,22 +489,21 @@ void GraphAcyc::place() {
|
|||
void GraphAcyc::placeTryEdge(V3GraphEdge* edgep) {
|
||||
// Try to make this edge uncutable
|
||||
m_placeStep++;
|
||||
UINFO(8, " PlaceEdge s"<<m_placeStep<<" w"<<edgep->weight()<<" "<<edgep->fromp()<<endl);
|
||||
UINFO(8, " PlaceEdge s" << m_placeStep << " w" << edgep->weight() << " " << edgep->fromp()
|
||||
<< endl);
|
||||
// Make the edge uncutable so we detect it in placement
|
||||
edgep->cutable(false);
|
||||
// Vertex::m_user begin: number indicates this edge was completed
|
||||
// Try to assign ranks, presuming this edge is in place
|
||||
// If we come across user()==placestep, we've detected a loop and must back out
|
||||
bool loop = placeIterate(static_cast<GraphAcycVertex*>(edgep->top()),
|
||||
edgep->fromp()->rank()+1);
|
||||
bool loop
|
||||
= placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), edgep->fromp()->rank() + 1);
|
||||
if (!loop) {
|
||||
// No loop, we can keep it as uncutable
|
||||
// Commit the new ranks we calculated
|
||||
// Just cleanup the list. If this is slow, we can add another set of
|
||||
// user counters to avoid cleaning up the list.
|
||||
while (workBeginp()) {
|
||||
workPop();
|
||||
}
|
||||
while (workBeginp()) workPop();
|
||||
} else {
|
||||
// Adding this edge would cause a loop, kill it
|
||||
edgep->cutable(true); // So graph still looks pretty
|
||||
|
|
@ -526,9 +532,9 @@ bool GraphAcyc::placeIterate(GraphAcycVertex* vertexp, uint32_t currentRank) {
|
|||
}
|
||||
vertexp->rank(currentRank);
|
||||
// Follow all edges and increase their ranks
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (edgep->weight() && !edgep->cutable()) {
|
||||
if (placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), currentRank+1)) {
|
||||
if (placeIterate(static_cast<GraphAcycVertex*>(edgep->top()), currentRank + 1)) {
|
||||
// We don't need to reset user(); we'll use a different placeStep for the next edge
|
||||
return true; // Loop detected
|
||||
}
|
||||
|
|
@ -551,33 +557,33 @@ void GraphAcyc::main() {
|
|||
// edges (and thus can't represent loops - if we did the unbreakable
|
||||
// marking right, anyways)
|
||||
buildGraph(m_origGraphp);
|
||||
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_pre");
|
||||
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_pre");
|
||||
|
||||
// Perform simple optimizations before any cuttings
|
||||
simplify(false);
|
||||
if (debug()>=5) m_breakGraph.dumpDotFilePrefixed("acyc_simp");
|
||||
if (debug() >= 5) m_breakGraph.dumpDotFilePrefixed("acyc_simp");
|
||||
|
||||
UINFO(4, " Cutting trivial loops\n");
|
||||
simplify(true);
|
||||
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_mid");
|
||||
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_mid");
|
||||
|
||||
UINFO(4, " Ranking\n");
|
||||
m_breakGraph.rank(&V3GraphEdge::followNotCutable);
|
||||
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_rank");
|
||||
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_rank");
|
||||
|
||||
UINFO(4, " Placement\n");
|
||||
place();
|
||||
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_place");
|
||||
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_place");
|
||||
|
||||
UINFO(4, " Final Ranking\n");
|
||||
// Only needed to assert there are no loops in completed graph
|
||||
m_breakGraph.rank(&V3GraphEdge::followAlwaysTrue);
|
||||
if (debug()>=6) m_breakGraph.dumpDotFilePrefixed("acyc_done");
|
||||
if (debug() >= 6) m_breakGraph.dumpDotFilePrefixed("acyc_done");
|
||||
}
|
||||
|
||||
void V3Graph::acyclic(V3EdgeFuncP edgeFuncp) {
|
||||
UINFO(4, "Acyclic\n");
|
||||
GraphAcyc acyc (this, edgeFuncp);
|
||||
GraphAcyc acyc(this, edgeFuncp);
|
||||
acyc.main();
|
||||
UINFO(4, "Acyclic done\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,15 +36,15 @@ void V3Graph::deleteCutableOnlyEdges() {
|
|||
|
||||
// Vertex::m_user begin: indicates can be deleted
|
||||
// Pass 1, mark those. Don't delete now, as we don't want to rip out whole trees
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->user(true);
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (!edgep->cutable()) {
|
||||
vertexp->user(false); // Can't delete it
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (!edgep->cutable()) {
|
||||
vertexp->user(false); // Can't delete it
|
||||
break;
|
||||
|
|
@ -54,10 +54,10 @@ void V3Graph::deleteCutableOnlyEdges() {
|
|||
|
||||
// Pass 2, delete those marked
|
||||
// Rather than doing a delete() we set the weight to 0 which disconnects the edge.
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
if (vertexp->user()) {
|
||||
//UINFO(7,"Disconnect "<<vertexp->name()<<endl);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
// UINFO(7, "Disconnect " << vertexp->name() << endl);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edgep->cut();
|
||||
}
|
||||
}
|
||||
|
|
@ -71,21 +71,21 @@ void V3Graph::deleteCutableOnlyEdges() {
|
|||
// Algorithms - weakly connected components
|
||||
|
||||
class GraphRemoveRedundant : GraphAlg<> {
|
||||
bool m_sumWeights; ///< Sum, rather then maximize weights
|
||||
bool m_sumWeights; ///< Sum, rather then maximize weights
|
||||
private:
|
||||
void main() {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
vertexIterate(vertexp);
|
||||
}
|
||||
}
|
||||
void vertexIterate(V3GraphVertex* vertexp) {
|
||||
// Clear marks
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edgep->top()->userp(NULL);
|
||||
}
|
||||
// Mark edges and detect duplications
|
||||
for (V3GraphEdge* nextp, *edgep = vertexp->outBeginp(); edgep; edgep=nextp) {
|
||||
for (V3GraphEdge *nextp, *edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp();
|
||||
if (followEdge(edgep)) {
|
||||
V3GraphVertex* outVertexp = edgep->top();
|
||||
|
|
@ -100,7 +100,8 @@ private:
|
|||
saveOld = true; // old !cutable more important than new
|
||||
} else {
|
||||
saveOld = true;
|
||||
if (!m_sumWeights && (prevEdgep->weight() < edgep->weight())) { // Keep max weight
|
||||
if (!m_sumWeights
|
||||
&& (prevEdgep->weight() < edgep->weight())) { // Keep max weight
|
||||
prevEdgep->weight(edgep->weight());
|
||||
}
|
||||
}
|
||||
|
|
@ -116,9 +117,11 @@ private:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GraphRemoveRedundant(V3Graph* graphp, V3EdgeFuncP edgeFuncp, bool sumWeights)
|
||||
: GraphAlg<>(graphp, edgeFuncp), m_sumWeights(sumWeights) {
|
||||
: GraphAlg<>(graphp, edgeFuncp)
|
||||
, m_sumWeights(sumWeights) {
|
||||
main();
|
||||
}
|
||||
~GraphRemoveRedundant() {}
|
||||
|
|
@ -141,33 +144,26 @@ public:
|
|||
: GraphAlg<>(graphp, NULL) {}
|
||||
void go() {
|
||||
GraphPathChecker checker(m_graphp);
|
||||
for (V3GraphVertex* vxp = m_graphp->verticesBeginp();
|
||||
vxp; vxp = vxp->verticesNextp()) {
|
||||
for (V3GraphVertex* vxp = m_graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
V3GraphEdge* deletep = NULL;
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (deletep) VL_DO_CLEAR(deletep->unlinkDelete(), deletep = NULL);
|
||||
// It should be safe to modify the graph, despite using
|
||||
// the GraphPathChecker, as none of the modifications will
|
||||
// change what can be reached from what, nor should they
|
||||
// change the rank or CP of any node.
|
||||
if (checker.isTransitiveEdge(edgep)) {
|
||||
deletep = edgep;
|
||||
}
|
||||
}
|
||||
if (deletep) {
|
||||
VL_DO_DANGLING(deletep->unlinkDelete(), deletep);
|
||||
if (checker.isTransitiveEdge(edgep)) deletep = edgep;
|
||||
}
|
||||
if (deletep) VL_DO_DANGLING(deletep->unlinkDelete(), deletep);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
VL_UNCOPYABLE(GraphAlgRemoveTransitiveEdges);
|
||||
};
|
||||
|
||||
void V3Graph::removeTransitiveEdges() {
|
||||
GraphAlgRemoveTransitiveEdges(this).go();
|
||||
}
|
||||
void V3Graph::removeTransitiveEdges() { GraphAlgRemoveTransitiveEdges(this).go(); }
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
|
|
@ -180,9 +176,9 @@ private:
|
|||
m_graphp->clearColors();
|
||||
// Color graph
|
||||
uint32_t currentColor = 0;
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
currentColor ++;
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
currentColor++;
|
||||
vertexIterate(vertexp, currentColor);
|
||||
}
|
||||
}
|
||||
|
|
@ -192,17 +188,14 @@ private:
|
|||
// then visit each of its edges, giving them the same color
|
||||
if (vertexp->color()) return; // Already colored it
|
||||
vertexp->color(currentColor);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
vertexIterate(edgep->top(), currentColor);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (followEdge(edgep)) vertexIterate(edgep->top(), currentColor);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
vertexIterate(edgep->fromp(), currentColor);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (followEdge(edgep)) vertexIterate(edgep->fromp(), currentColor);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GraphAlgWeakly(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
|
||||
: GraphAlg<>(graphp, edgeFuncp) {
|
||||
|
|
@ -211,9 +204,7 @@ public:
|
|||
~GraphAlgWeakly() {}
|
||||
};
|
||||
|
||||
void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) {
|
||||
GraphAlgWeakly(this, edgeFuncp);
|
||||
}
|
||||
void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgWeakly(this, edgeFuncp); }
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
|
|
@ -231,14 +222,14 @@ private:
|
|||
// Vertex::color // Output subtree number (fully processed)
|
||||
|
||||
// Clear info
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->color(0);
|
||||
vertexp->user(0);
|
||||
}
|
||||
// Color graph
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (!vertexp->user()) {
|
||||
m_currentDfs++;
|
||||
vertexIterate(vertexp);
|
||||
|
|
@ -246,10 +237,10 @@ private:
|
|||
}
|
||||
// If there's a single vertex of a color, it doesn't need a subgraph
|
||||
// This simplifies the consumer's code, and reduces graph debugging clutter
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
bool onecolor = true;
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
if (vertexp->color() == edgep->top()->color()) {
|
||||
onecolor = false;
|
||||
|
|
@ -265,7 +256,7 @@ private:
|
|||
uint32_t thisDfsNum = m_currentDfs++;
|
||||
vertexp->user(thisDfsNum);
|
||||
vertexp->color(0);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
V3GraphVertex* top = edgep->top();
|
||||
if (!top->user()) { // Dest not computed yet
|
||||
|
|
@ -291,6 +282,7 @@ private:
|
|||
m_callTrace.push_back(vertexp);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
GraphAlgStrongly(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
|
||||
: GraphAlg<>(graphp, edgeFuncp) {
|
||||
|
|
@ -300,9 +292,7 @@ public:
|
|||
~GraphAlgStrongly() {}
|
||||
};
|
||||
|
||||
void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) {
|
||||
GraphAlgStrongly(this, edgeFuncp);
|
||||
}
|
||||
void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgStrongly(this, edgeFuncp); }
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
|
|
@ -314,16 +304,14 @@ private:
|
|||
// Rank each vertex, ignoring cutable edges
|
||||
// Vertex::m_user begin: 1 indicates processing, 2 indicates completed
|
||||
// Clear existing ranks
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
vertexp->rank(0);
|
||||
vertexp->user(0);
|
||||
}
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
if (!vertexp->user()) {
|
||||
vertexIterate(vertexp, 1);
|
||||
}
|
||||
for (V3GraphVertex* vertexp = m_graphp->verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (!vertexp->user()) { vertexIterate(vertexp, 1); }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -339,13 +327,14 @@ private:
|
|||
if (vertexp->rank() >= currentRank) return; // Already processed it
|
||||
vertexp->user(1);
|
||||
vertexp->rank(currentRank);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
vertexIterate(edgep->top(), currentRank + vertexp->rankAdder());
|
||||
}
|
||||
}
|
||||
vertexp->user(2);
|
||||
}
|
||||
|
||||
public:
|
||||
GraphAlgRank(V3Graph* graphp, V3EdgeFuncP edgeFuncp)
|
||||
: GraphAlg<>(graphp, edgeFuncp) {
|
||||
|
|
@ -354,13 +343,9 @@ public:
|
|||
~GraphAlgRank() {}
|
||||
};
|
||||
|
||||
void V3Graph::rank() {
|
||||
GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue);
|
||||
}
|
||||
void V3Graph::rank() { GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue); }
|
||||
|
||||
void V3Graph::rank(V3EdgeFuncP edgeFuncp) {
|
||||
GraphAlgRank(this, edgeFuncp);
|
||||
}
|
||||
void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank(this, edgeFuncp); }
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
|
|
@ -389,7 +374,7 @@ private:
|
|||
m_callTrace[currentRank++] = vertexp;
|
||||
|
||||
if (vertexp->user() == 1) {
|
||||
for (unsigned i=0; i<currentRank; i++) {
|
||||
for (unsigned i = 0; i < currentRank; i++) { //
|
||||
m_graphp->loopsVertexCb(m_callTrace[i]);
|
||||
}
|
||||
m_done = true;
|
||||
|
|
@ -397,13 +382,12 @@ private:
|
|||
}
|
||||
if (vertexp->user() == 2) return; // Already processed it
|
||||
vertexp->user(1);
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep=edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
vertexIterate(edgep->top(), currentRank);
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (followEdge(edgep)) vertexIterate(edgep->top(), currentRank);
|
||||
}
|
||||
vertexp->user(2);
|
||||
}
|
||||
|
||||
public:
|
||||
GraphAlgRLoops(V3Graph* graphp, V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp)
|
||||
: GraphAlg<>(graphp, edgeFuncp) {
|
||||
|
|
@ -417,7 +401,6 @@ void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) {
|
|||
GraphAlgRLoops(this, edgeFuncp, vertexp);
|
||||
}
|
||||
|
||||
|
||||
//######################################################################
|
||||
//######################################################################
|
||||
// Algorithms - subtrees
|
||||
|
|
@ -434,14 +417,12 @@ private:
|
|||
newVertexp = vertexp->clone(m_loopGraphp);
|
||||
vertexp->userp(newVertexp);
|
||||
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp();
|
||||
edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
if (followEdge(edgep)) {
|
||||
V3GraphEdge* newEdgep = static_cast<V3GraphEdge*>(edgep->userp());
|
||||
if (!newEdgep) {
|
||||
V3GraphVertex* newTop = vertexIterateAll(edgep->top());
|
||||
newEdgep = edgep->clone(m_loopGraphp, newVertexp,
|
||||
newTop);
|
||||
newEdgep = edgep->clone(m_loopGraphp, newVertexp, newTop);
|
||||
edgep->userp(newEdgep);
|
||||
}
|
||||
}
|
||||
|
|
@ -451,21 +432,21 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp,
|
||||
V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp)
|
||||
: GraphAlg<>(graphp, edgeFuncp), m_loopGraphp(loopGraphp) {
|
||||
GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp, V3EdgeFuncP edgeFuncp,
|
||||
V3GraphVertex* vertexp)
|
||||
: GraphAlg<>(graphp, edgeFuncp)
|
||||
, m_loopGraphp(loopGraphp) {
|
||||
// Vertex::m_userp - New vertex if we have seen this vertex already
|
||||
// Edge::m_userp - New edge if we have seen this edge already
|
||||
m_graphp->userClearVertices();
|
||||
m_graphp->userClearEdges();
|
||||
(void) vertexIterateAll(vertexp);
|
||||
(void)vertexIterateAll(vertexp);
|
||||
}
|
||||
~GraphAlgSubtrees() {}
|
||||
};
|
||||
|
||||
//! Report the entire connected graph with a loop or loops
|
||||
void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp,
|
||||
V3Graph* loopGraphp) {
|
||||
void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp) {
|
||||
GraphAlgSubtrees(this, loopGraphp, edgeFuncp, vertexp);
|
||||
}
|
||||
|
||||
|
|
@ -474,7 +455,7 @@ void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp,
|
|||
// Algorithms - make non cutable
|
||||
|
||||
void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
// Only need one direction, we'll always see the other at some point...
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (edgep->cutable() && edgep->weight() && (edgeFuncp)(edgep)) {
|
||||
|
|
@ -489,12 +470,12 @@ void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) {
|
|||
// Algorithms - sorting
|
||||
|
||||
struct GraphSortVertexCmp {
|
||||
inline bool operator() (const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const {
|
||||
inline bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const {
|
||||
return lhsp->sortCmp(rhsp) < 0;
|
||||
}
|
||||
};
|
||||
struct GraphSortEdgeCmp {
|
||||
inline bool operator() (const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
|
||||
inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const {
|
||||
return lhsp->sortCmp(rhsp) < 0;
|
||||
}
|
||||
};
|
||||
|
|
@ -502,12 +483,12 @@ struct GraphSortEdgeCmp {
|
|||
void V3Graph::sortVertices() {
|
||||
// Sort list of vertices by rank, then fanout
|
||||
std::vector<V3GraphVertex*> vertices;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
vertices.push_back(vertexp);
|
||||
}
|
||||
std::stable_sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
|
||||
this->verticesUnlink();
|
||||
for (std::vector<V3GraphVertex*>::iterator it = vertices.begin(); it!=vertices.end(); ++it) {
|
||||
for (std::vector<V3GraphVertex*>::iterator it = vertices.begin(); it != vertices.end(); ++it) {
|
||||
(*it)->verticesPushBack(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -515,7 +496,7 @@ void V3Graph::sortVertices() {
|
|||
void V3Graph::sortEdges() {
|
||||
// Sort edges by rank then fanout of node they point to
|
||||
std::vector<V3GraphEdge*> edges;
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
// Make a vector
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
edges.push_back(edgep);
|
||||
|
|
@ -527,7 +508,8 @@ void V3Graph::sortEdges() {
|
|||
// We know the vector contains all of the edges that were
|
||||
// there originally (didn't delete or add)
|
||||
vertexp->outUnlink();
|
||||
for (std::vector<V3GraphEdge*>::const_iterator it = edges.begin(); it!=edges.end(); ++it) {
|
||||
for (std::vector<V3GraphEdge*>::const_iterator it = edges.begin(); it != edges.end();
|
||||
++it) {
|
||||
(*it)->outPushBack();
|
||||
}
|
||||
// Prep for next
|
||||
|
|
@ -544,7 +526,7 @@ void V3Graph::sortEdges() {
|
|||
// (Results in better dcache packing.)
|
||||
|
||||
void V3Graph::order() {
|
||||
UINFO(2,"Order:\n");
|
||||
UINFO(2, "Order:\n");
|
||||
|
||||
// Compute rankings again
|
||||
rank(&V3GraphEdge::followAlwaysTrue);
|
||||
|
|
@ -555,10 +537,8 @@ void V3Graph::orderPreRanked() {
|
|||
// Compute fanouts
|
||||
// Vertex::m_user begin: 1 indicates processing, 2 indicates completed
|
||||
userClearVertices();
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
if (!vertexp->user()) {
|
||||
orderDFSIterate(vertexp);
|
||||
}
|
||||
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) {
|
||||
if (!vertexp->user()) orderDFSIterate(vertexp);
|
||||
}
|
||||
|
||||
// Sort list of vertices by rank, then fanout. Fanout is a bit of a
|
||||
|
|
@ -581,7 +561,7 @@ double V3Graph::orderDFSIterate(V3GraphVertex* vertexp) {
|
|||
}
|
||||
// Just count inbound edges
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
if (edgep->weight()) fanout ++;
|
||||
if (edgep->weight()) ++fanout;
|
||||
}
|
||||
vertexp->fanout(fanout);
|
||||
vertexp->user(2);
|
||||
|
|
|
|||
|
|
@ -38,9 +38,7 @@ protected:
|
|||
|
||||
// Utilities
|
||||
void dump() {
|
||||
if (debug()>=9) {
|
||||
m_graph.dumpDotFilePrefixed("v3graphtest_"+name());
|
||||
}
|
||||
if (debug() >= 9) m_graph.dumpDotFilePrefixed("v3graphtest_" + name());
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -56,9 +54,11 @@ public:
|
|||
|
||||
class V3GraphTestVertex : public V3GraphVertex {
|
||||
string m_name;
|
||||
|
||||
public:
|
||||
V3GraphTestVertex(V3Graph* graphp, const string& name)
|
||||
: V3GraphVertex(graphp), m_name(name) {}
|
||||
: V3GraphVertex(graphp)
|
||||
, m_name(name) {}
|
||||
virtual ~V3GraphTestVertex() {}
|
||||
// ACCESSORS
|
||||
virtual string name() const { return m_name; }
|
||||
|
|
@ -84,13 +84,13 @@ public:
|
|||
V3Graph* gp = &m_graph;
|
||||
// Verify we break edges at a good point
|
||||
// A simple alg would make 3 breaks, below only requires b->i to break
|
||||
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
|
||||
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
|
||||
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
|
||||
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
|
||||
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
|
||||
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
|
||||
V3GraphTestVertex* q = new V3GraphTestVarVertex(gp, "q");
|
||||
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
|
||||
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
|
||||
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
|
||||
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
|
||||
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
|
||||
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
|
||||
V3GraphTestVertex* q = new V3GraphTestVarVertex(gp, "q");
|
||||
new V3GraphEdge(gp, i, a, 2, true);
|
||||
new V3GraphEdge(gp, a, b, 2, true);
|
||||
new V3GraphEdge(gp, b, g1, 2, true);
|
||||
|
|
@ -106,11 +106,11 @@ public:
|
|||
gp->stronglyConnected(&V3GraphEdge::followAlwaysTrue);
|
||||
dump();
|
||||
|
||||
UASSERT(i->color()!=a->color() && a->color() != g2->color() && g2->color() != q->color(),
|
||||
UASSERT(i->color() != a->color() && a->color() != g2->color() && g2->color() != q->color(),
|
||||
"SelfTest: Separate colors not assigned");
|
||||
UASSERT(a->color()==b->color() && a->color()==g1->color(),
|
||||
UASSERT(a->color() == b->color() && a->color() == g1->color(),
|
||||
"SelfTest: Strongly connected nodes not colored together");
|
||||
UASSERT(g2->color()==g3->color(),
|
||||
UASSERT(g2->color() == g3->color(),
|
||||
"SelfTest: Strongly connected nodes not colored together");
|
||||
}
|
||||
};
|
||||
|
|
@ -122,12 +122,12 @@ public:
|
|||
V3Graph* gp = &m_graph;
|
||||
// Verify we break edges at a good point
|
||||
// A simple alg would make 3 breaks, below only requires b->i to break
|
||||
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
|
||||
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
|
||||
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
|
||||
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
|
||||
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
|
||||
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
|
||||
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "*INPUTS*");
|
||||
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "a");
|
||||
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "b");
|
||||
V3GraphTestVertex* g1 = new V3GraphTestVarVertex(gp, "g1");
|
||||
V3GraphTestVertex* g2 = new V3GraphTestVarVertex(gp, "g2");
|
||||
V3GraphTestVertex* g3 = new V3GraphTestVarVertex(gp, "g3");
|
||||
new V3GraphEdge(gp, i, a, 2, true);
|
||||
new V3GraphEdge(gp, a, b, 2, true);
|
||||
new V3GraphEdge(gp, b, g1, 2, true);
|
||||
|
|
@ -149,20 +149,20 @@ public:
|
|||
virtual void runTest() {
|
||||
V3Graph* gp = &m_graph;
|
||||
|
||||
V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk");
|
||||
V3GraphTestVertex* clk = new V3GraphTestVarVertex(gp, "$clk");
|
||||
|
||||
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "$a");
|
||||
V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp, "$a_dly");
|
||||
V3GraphTestVertex* a_dlyblk= new V3GraphTestVarVertex(gp, "$a_dlyblk");
|
||||
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "$b");
|
||||
V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp, "$b_dly");
|
||||
V3GraphTestVertex* b_dlyblk= new V3GraphTestVarVertex(gp, "$b_dlyblk");
|
||||
V3GraphTestVertex* c = new V3GraphTestVarVertex(gp, "$c");
|
||||
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "$i");
|
||||
V3GraphTestVertex* a = new V3GraphTestVarVertex(gp, "$a");
|
||||
V3GraphTestVertex* a_dly = new V3GraphTestVarVertex(gp, "$a_dly");
|
||||
V3GraphTestVertex* a_dlyblk = new V3GraphTestVarVertex(gp, "$a_dlyblk");
|
||||
V3GraphTestVertex* b = new V3GraphTestVarVertex(gp, "$b");
|
||||
V3GraphTestVertex* b_dly = new V3GraphTestVarVertex(gp, "$b_dly");
|
||||
V3GraphTestVertex* b_dlyblk = new V3GraphTestVarVertex(gp, "$b_dlyblk");
|
||||
V3GraphTestVertex* c = new V3GraphTestVarVertex(gp, "$c");
|
||||
V3GraphTestVertex* i = new V3GraphTestVarVertex(gp, "$i");
|
||||
|
||||
V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp, "$a_pre");
|
||||
V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp, "$b_pre");
|
||||
V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp, "$c_pre");
|
||||
V3GraphTestVertex* ap = new V3GraphTestVarVertex(gp, "$a_pre");
|
||||
V3GraphTestVertex* bp = new V3GraphTestVarVertex(gp, "$b_pre");
|
||||
V3GraphTestVertex* cp = new V3GraphTestVarVertex(gp, "$c_pre");
|
||||
|
||||
V3GraphTestVertex* n;
|
||||
|
||||
|
|
@ -177,26 +177,27 @@ public:
|
|||
// Desired order between different _DLY blocks so we can elim temporaries
|
||||
// implemented by cutable "pre" signal dependencies
|
||||
|
||||
|
||||
n = new V3GraphTestVertex(gp, "*INPUTS*"); {
|
||||
n = new V3GraphTestVertex(gp, "*INPUTS*");
|
||||
{
|
||||
new V3GraphEdge(gp, n, clk, 2);
|
||||
new V3GraphEdge(gp, n, i, 2);
|
||||
}
|
||||
|
||||
V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp, "*posedge clk*"); {
|
||||
new V3GraphEdge(gp, clk, n, 2);
|
||||
}
|
||||
V3GraphTestVertex* posedge = n = new V3GraphTestVertex(gp, "*posedge clk*");
|
||||
{ new V3GraphEdge(gp, clk, n, 2); }
|
||||
|
||||
// AssignPre's VarRefs on LHS: generate special BLK
|
||||
// normal: VarRefs on LHS: generate normal
|
||||
// underSBlock: VarRefs on RHS: consume 'pre' (required to save cutable tests)
|
||||
n = new V3GraphTestVertex(gp, "a_dly<PRE=a"); {
|
||||
n = new V3GraphTestVertex(gp, "a_dly<PRE=a");
|
||||
{
|
||||
new V3GraphEdge(gp, n, a_dlyblk, 2); // Block ordering
|
||||
new V3GraphEdge(gp, n, a_dly, 2);
|
||||
new V3GraphEdge(gp, ap, n, 2, true); // DESIRED delayed ordering (inp is required)
|
||||
new V3GraphEdge(gp, posedge, n, 2);
|
||||
}
|
||||
n = new V3GraphTestVertex(gp, "b_dly<PRE=b"); {
|
||||
n = new V3GraphTestVertex(gp, "b_dly<PRE=b");
|
||||
{
|
||||
new V3GraphEdge(gp, n, b_dlyblk, 2); // Block ordering
|
||||
new V3GraphEdge(gp, n, b_dly, 2);
|
||||
new V3GraphEdge(gp, bp, n, 2, true); // DESIRED delayed ordering
|
||||
|
|
@ -207,7 +208,8 @@ public:
|
|||
// normal: VarRefs on LHS: generate normal
|
||||
// underSBlock: VarRefs on RHS: generate 'pre' signals (cutable)
|
||||
// SenItems: consume CLOCK dependency
|
||||
n = new V3GraphTestVertex(gp, "a_dly<=b|c"); {
|
||||
n = new V3GraphTestVertex(gp, "a_dly<=b|c");
|
||||
{
|
||||
new V3GraphEdge(gp, a_dlyblk, n, 2); // Block ordering in
|
||||
new V3GraphEdge(gp, n, a_dly, 2);
|
||||
// Note we don't include ap as we're generating a_dly
|
||||
|
|
@ -215,7 +217,8 @@ public:
|
|||
new V3GraphEdge(gp, n, cp, 2); // DESIRED delayed usage
|
||||
new V3GraphEdge(gp, posedge, n, 2);
|
||||
}
|
||||
n = new V3GraphTestVertex(gp, "b_dly<=a"); {
|
||||
n = new V3GraphTestVertex(gp, "b_dly<=a");
|
||||
{
|
||||
new V3GraphEdge(gp, b_dlyblk, n, 2); // Block ordering in
|
||||
new V3GraphEdge(gp, n, b_dly, 2);
|
||||
new V3GraphEdge(gp, n, ap, 2); // DESIRED delayed usage
|
||||
|
|
@ -225,12 +228,14 @@ public:
|
|||
// AssignPost's
|
||||
// normal: VarRefs on LHS: generate normal
|
||||
// underSBlock: VarRefs on RHS: consume normal
|
||||
n = new V3GraphTestVertex(gp, "a=POST=a_dly"); {
|
||||
n = new V3GraphTestVertex(gp, "a=POST=a_dly");
|
||||
{
|
||||
new V3GraphEdge(gp, n, a, 3);
|
||||
new V3GraphEdge(gp, a_dly, n, 3);
|
||||
new V3GraphEdge(gp, posedge, n, 2);
|
||||
}
|
||||
n = new V3GraphTestVertex(gp, "b=POST=b_dly"); {
|
||||
n = new V3GraphTestVertex(gp, "b=POST=b_dly");
|
||||
{
|
||||
new V3GraphEdge(gp, n, b, 3);
|
||||
new V3GraphEdge(gp, b_dly, n, 3);
|
||||
new V3GraphEdge(gp, posedge, n, 2);
|
||||
|
|
@ -258,9 +263,12 @@ public:
|
|||
//======================================================================
|
||||
|
||||
class DfaTestVertex : public DfaVertex {
|
||||
string m_name;
|
||||
string m_name;
|
||||
|
||||
public:
|
||||
DfaTestVertex(DfaGraph* graphp, const string& name) : DfaVertex(graphp), m_name(name) {}
|
||||
DfaTestVertex(DfaGraph* graphp, const string& name)
|
||||
: DfaVertex(graphp)
|
||||
, m_name(name) {}
|
||||
virtual ~DfaTestVertex() {}
|
||||
// ACCESSORS
|
||||
virtual string name() const { return m_name; }
|
||||
|
|
@ -274,29 +282,31 @@ public:
|
|||
DfaGraph* gp = &m_graph;
|
||||
|
||||
// NFA Pattern for ( (LR) | (L*R)) Z
|
||||
DfaTestVertex* st = new DfaTestVertex(gp, "*START*"); st->start(true);
|
||||
DfaTestVertex* sl = new DfaTestVertex(gp, "sL");
|
||||
DfaTestVertex* srs = new DfaTestVertex(gp, "sR*");
|
||||
DfaTestVertex* sls = new DfaTestVertex(gp, "sL*");
|
||||
DfaTestVertex* sr = new DfaTestVertex(gp, "sR");
|
||||
DfaTestVertex* sz = new DfaTestVertex(gp, "sZ");
|
||||
DfaTestVertex* sac = new DfaTestVertex(gp, "*ACCEPT*"); sac->accepting(true);
|
||||
DfaTestVertex* st = new DfaTestVertex(gp, "*START*");
|
||||
st->start(true);
|
||||
DfaTestVertex* sl = new DfaTestVertex(gp, "sL");
|
||||
DfaTestVertex* srs = new DfaTestVertex(gp, "sR*");
|
||||
DfaTestVertex* sls = new DfaTestVertex(gp, "sL*");
|
||||
DfaTestVertex* sr = new DfaTestVertex(gp, "sR");
|
||||
DfaTestVertex* sz = new DfaTestVertex(gp, "sZ");
|
||||
DfaTestVertex* sac = new DfaTestVertex(gp, "*ACCEPT*");
|
||||
sac->accepting(true);
|
||||
|
||||
VNUser L = VNUser::fromInt(0xaa);
|
||||
VNUser R = VNUser::fromInt(0xbb);
|
||||
VNUser Z = VNUser::fromInt(0xcc);
|
||||
|
||||
new DfaEdge(gp, st, sl, DfaEdge::EPSILON());
|
||||
new DfaEdge(gp, sl, srs, L);
|
||||
new DfaEdge(gp, st, sl, DfaEdge::EPSILON());
|
||||
new DfaEdge(gp, sl, srs, L);
|
||||
new DfaEdge(gp, srs, srs, R);
|
||||
new DfaEdge(gp, srs, sz, Z);
|
||||
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
|
||||
new DfaEdge(gp, srs, sz, Z);
|
||||
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
|
||||
|
||||
new DfaEdge(gp, st, sls, DfaEdge::EPSILON());
|
||||
new DfaEdge(gp, st, sls, DfaEdge::EPSILON());
|
||||
new DfaEdge(gp, sls, sls, L);
|
||||
new DfaEdge(gp, sls, sr, R);
|
||||
new DfaEdge(gp, sr, sz, Z);
|
||||
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
|
||||
new DfaEdge(gp, sls, sr, R);
|
||||
new DfaEdge(gp, sr, sz, Z);
|
||||
new DfaEdge(gp, sz, sac, DfaEdge::EPSILON());
|
||||
|
||||
dump();
|
||||
gp->nfaToDfa();
|
||||
|
|
@ -335,18 +345,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
#ifdef GRAPH_IMPORT
|
||||
# include "graph_export.cpp"
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
//======================================================================
|
||||
|
||||
void V3Graph::selfTest() {
|
||||
// Execute all of the tests
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// clang-format off
|
||||
{ V3GraphTestStrong test; test.run(); }
|
||||
{ V3GraphTestAcyc test; test.run(); }
|
||||
{ V3GraphTestVars test; test.run(); }
|
||||
{ V3GraphTestDfa test; test.run(); }
|
||||
{ V3GraphTestImport test; test.run(); }
|
||||
// clang-format on
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ private:
|
|||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNodeStmt::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
|
||||
//AstUser4InUse in V3Hashed.h
|
||||
// AstUser4InUse in V3Hashed.h
|
||||
|
||||
// STATE
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
bool m_cacheInUser4; // Use user4 to cache each V3Hash?
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
bool m_cacheInUser4; // Use user4 to cache each V3Hash?
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -55,10 +55,12 @@ private:
|
|||
void nodeHashIterate(AstNode* nodep) {
|
||||
V3Hash thisHash;
|
||||
if (!m_cacheInUser4 || !nodep->user4()) {
|
||||
UASSERT_OBJ(!(VN_IS(nodep->backp(), CFunc)
|
||||
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))), nodep,
|
||||
"Node "<<nodep->prettyTypeName()
|
||||
<<" in statement position but not marked stmt (node under function)");
|
||||
UASSERT_OBJ(
|
||||
!(VN_IS(nodep->backp(), CFunc)
|
||||
&& !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))),
|
||||
nodep,
|
||||
"Node " << nodep->prettyTypeName()
|
||||
<< " in statement position but not marked stmt (node under function)");
|
||||
V3Hash oldHash = m_lowerHash;
|
||||
{
|
||||
m_lowerHash = nodep->sameHash();
|
||||
|
|
@ -66,20 +68,19 @@ private:
|
|||
"sameHash function undefined (returns 0) for node under CFunc.");
|
||||
// For identical nodes, the type should be the same thus
|
||||
// dtypep should be the same too
|
||||
m_lowerHash = V3Hash(m_lowerHash, V3Hash(nodep->type()<<6,
|
||||
V3Hash(nodep->dtypep())));
|
||||
m_lowerHash
|
||||
= V3Hash(m_lowerHash, V3Hash(nodep->type() << 6, V3Hash(nodep->dtypep())));
|
||||
// Now update m_lowerHash for our children's (and next children) contributions
|
||||
iterateChildren(nodep);
|
||||
// Store the hash value
|
||||
nodep->user4(m_lowerHash.fullValue());
|
||||
//UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
|
||||
// UINFO(9, " hashnode "<<m_lowerHash<<" "<<nodep<<endl);
|
||||
}
|
||||
thisHash = m_lowerHash;
|
||||
m_lowerHash = oldHash;
|
||||
}
|
||||
// Update what will become the above node's hash
|
||||
m_lowerHash += m_cacheInUser4
|
||||
? V3Hashed::nodeHash(nodep) : thisHash;
|
||||
m_lowerHash += m_cacheInUser4 ? V3Hashed::nodeHash(nodep) : thisHash;
|
||||
}
|
||||
|
||||
//--------------------
|
||||
|
|
@ -120,10 +121,8 @@ V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
|
|||
}
|
||||
|
||||
void V3Hashed::hash(AstNode* nodep) {
|
||||
UINFO(8," hashI "<<nodep<<endl);
|
||||
if (!nodep->user4p()) {
|
||||
HashedVisitor visitor (nodep);
|
||||
}
|
||||
UINFO(8, " hashI " << nodep << endl);
|
||||
if (!nodep->user4p()) { HashedVisitor visitor(nodep); }
|
||||
}
|
||||
|
||||
bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
|
||||
|
|
@ -135,7 +134,7 @@ bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
|
|||
|
||||
void V3Hashed::erase(iterator it) {
|
||||
AstNode* nodep = iteratorNodep(it);
|
||||
UINFO(8," erase "<<nodep<<endl);
|
||||
UINFO(8, " erase " << nodep << endl);
|
||||
UASSERT_OBJ(nodep->user4p(), nodep, "Called removeNode on non-hashed node");
|
||||
m_hashMmap.erase(it);
|
||||
nodep->user4p(NULL); // So we don't allow removeNode again
|
||||
|
|
@ -149,24 +148,22 @@ void V3Hashed::check() {
|
|||
}
|
||||
|
||||
void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) {
|
||||
if (v3Global.opt.dumpTree()) {
|
||||
dumpFile(v3Global.debugFilename(nameComment)+".hash", tree);
|
||||
}
|
||||
if (v3Global.opt.dumpTree()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree);
|
||||
}
|
||||
|
||||
void V3Hashed::dumpFile(const string& filename, bool tree) {
|
||||
const vl_unique_ptr<std::ofstream> logp (V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write "<<filename);
|
||||
const vl_unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write " << filename);
|
||||
|
||||
std::map<int,int> dist;
|
||||
std::map<int, int> dist;
|
||||
|
||||
V3Hash lasthash;
|
||||
int num_in_bucket = 0;
|
||||
for (HashMmap::iterator it=begin(); 1; ++it) {
|
||||
if (it==end() || lasthash != it->first) {
|
||||
if (it!=end()) lasthash = it->first;
|
||||
for (HashMmap::iterator it = begin(); 1; ++it) {
|
||||
if (it == end() || lasthash != it->first) {
|
||||
if (it != end()) lasthash = it->first;
|
||||
if (num_in_bucket) {
|
||||
if (dist.find(num_in_bucket)==dist.end()) {
|
||||
if (dist.find(num_in_bucket) == dist.end()) {
|
||||
dist.insert(make_pair(num_in_bucket, 1));
|
||||
} else {
|
||||
++dist[num_in_bucket];
|
||||
|
|
@ -174,22 +171,23 @@ void V3Hashed::dumpFile(const string& filename, bool tree) {
|
|||
}
|
||||
num_in_bucket = 0;
|
||||
}
|
||||
if (it==end()) break;
|
||||
if (it == end()) break;
|
||||
num_in_bucket++;
|
||||
}
|
||||
*logp <<"\n*** STATS:\n"<<endl;
|
||||
*logp<<" #InBucket Occurrences\n";
|
||||
for (std::map<int,int>::iterator it=dist.begin(); it!=dist.end(); ++it) {
|
||||
*logp<<" "<<std::setw(9)<<it->first<<" "<<std::setw(12)<<it->second<<endl;
|
||||
*logp << "\n*** STATS:\n" << endl;
|
||||
*logp << " #InBucket Occurrences\n";
|
||||
for (std::map<int, int>::iterator it = dist.begin(); it != dist.end(); ++it) {
|
||||
*logp << " " << std::setw(9) << it->first << " " << std::setw(12) << it->second
|
||||
<< endl;
|
||||
}
|
||||
|
||||
*logp <<"\n*** Dump:\n"<<endl;
|
||||
for (HashMmap::iterator it=begin(); it!=end(); ++it) {
|
||||
*logp << "\n*** Dump:\n" << endl;
|
||||
for (HashMmap::iterator it = begin(); it != end(); ++it) {
|
||||
if (lasthash != it->first) {
|
||||
lasthash = it->first;
|
||||
*logp <<" "<<it->first<<endl;
|
||||
*logp << " " << it->first << endl;
|
||||
}
|
||||
*logp <<"\t"<<it->second<<endl;
|
||||
*logp << "\t" << it->second << endl;
|
||||
// Dumping the entire tree may make nearly N^2 sized dumps,
|
||||
// because the nodes under this one may also be in the hash table!
|
||||
if (tree) it->second->dumpTree(*logp, " ");
|
||||
|
|
@ -197,14 +195,13 @@ void V3Hashed::dumpFile(const string& filename, bool tree) {
|
|||
}
|
||||
|
||||
V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserSame* checkp) {
|
||||
UINFO(8," findD "<<nodep<<endl);
|
||||
UINFO(8, " findD " << nodep << endl);
|
||||
UASSERT_OBJ(nodep->user4p(), nodep, "Called findDuplicate on non-hashed node");
|
||||
std::pair<HashMmap::iterator,HashMmap::iterator> eqrange
|
||||
std::pair<HashMmap::iterator, HashMmap::iterator> eqrange
|
||||
= mmap().equal_range(nodeHash(nodep));
|
||||
for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
|
||||
AstNode* node2p = eqit->second;
|
||||
if (nodep != node2p
|
||||
&& (!checkp || checkp->isSame(nodep, node2p))
|
||||
if (nodep != node2p && (!checkp || checkp->isSame(nodep, node2p))
|
||||
&& sameNodes(nodep, node2p)) {
|
||||
return eqit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -127,11 +127,10 @@ private:
|
|||
}
|
||||
virtual void visit(AstPragma* nodep) VL_OVERRIDE {
|
||||
if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
|
||||
// UINFO(0,"PRAG MARK "<<m_modp<<endl);
|
||||
// UINFO(0, "PRAG MARK " << m_modp << endl);
|
||||
if (!m_modp) {
|
||||
nodep->v3error("Inline pragma not under a module"); // LCOV_EXCL_LINE
|
||||
} else if (m_modp->user2() == CIL_MAYBE
|
||||
|| m_modp->user2() == CIL_NOTSOFT) {
|
||||
} else if (m_modp->user2() == CIL_MAYBE || m_modp->user2() == CIL_NOTSOFT) {
|
||||
m_modp->user2(CIL_USER);
|
||||
}
|
||||
// Remove so don't propagate to upper cell...
|
||||
|
|
@ -199,14 +198,13 @@ private:
|
|||
// If a mod*#refs is < this # nodes, can inline it
|
||||
bool doit = ((allowed == CIL_USER)
|
||||
|| ((allowed == CIL_MAYBE)
|
||||
&& (refs == 1
|
||||
|| statements < INLINE_MODS_SMALLER
|
||||
&& (refs == 1 || statements < INLINE_MODS_SMALLER
|
||||
|| v3Global.opt.inlineMult() < 1
|
||||
|| refs * statements < v3Global.opt.inlineMult())));
|
||||
// Packages aren't really "under" anything so they confuse this algorithm
|
||||
if (VN_IS(modp, Package)) doit = false;
|
||||
UINFO(4, " Inline=" << doit << " Possible=" << allowed << " Refs=" << refs
|
||||
<< " Stmts=" << statements << " " << modp << endl);
|
||||
<< " Stmts=" << statements << " " << modp << endl);
|
||||
modp->user1(doit);
|
||||
}
|
||||
}
|
||||
|
|
@ -247,9 +245,7 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
nodep->user4p(nodep->clonep());
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE { nodep->user4p(nodep->clonep()); }
|
||||
//--------------------
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
|
|
@ -328,36 +324,30 @@ private:
|
|||
// remove the change detection on the output variable.
|
||||
UINFO(9, "public pin assign: " << exprvarrefp << endl);
|
||||
UASSERT_OBJ(!nodep->isNonOutput(), nodep, "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)));
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
} else if (nodep->isSigPublic() && VN_IS(nodep->dtypep(), UnpackArrayDType)) {
|
||||
// Public variable at this end and it is an unpacked array. We need to assign
|
||||
// instead of aliased, because otherwise it will pass V3Slice and invalid
|
||||
// code will be emitted.
|
||||
UINFO(9, "assign to public and unpacked: " << nodep << endl);
|
||||
m_modp->addStmtp(
|
||||
new AstAssignW(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
|
||||
new AstVarRef(nodep->fileline(), nodep, false)));
|
||||
} else if (nodep->isIfaceRef()) {
|
||||
m_modp->addStmtp(
|
||||
new AstAssignVarScope(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
exprvarrefp->varp(), false)));
|
||||
m_modp->addStmtp(new AstAssignVarScope(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
AstNode* nodebp = exprvarrefp->varp();
|
||||
nodep->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep->fileline());
|
||||
} else {
|
||||
// Do to inlining child's variable now within the same
|
||||
// module, so a AstVarRef not AstVarXRef below
|
||||
m_modp->addStmtp(
|
||||
new AstAssignAlias(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
exprvarrefp->varp(), false)));
|
||||
m_modp->addStmtp(new AstAssignAlias(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), nodep, true),
|
||||
new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
|
||||
AstNode* nodebp = exprvarrefp->varp();
|
||||
nodep->fileline()->modifyStateInherit(nodebp->fileline());
|
||||
nodebp->fileline()->modifyStateInherit(nodep->fileline());
|
||||
|
|
@ -406,7 +396,8 @@ private:
|
|||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->varp()->user2p() // It's being converted to an alias.
|
||||
&& !nodep->varp()->user3()
|
||||
&& !VN_IS(nodep->backp(), AssignAlias)) { // Don't constant propagate aliases (we just made)
|
||||
// Don't constant propagate aliases (we just made)
|
||||
&& !VN_IS(nodep->backp(), AssignAlias)) {
|
||||
AstConst* exprconstp = VN_CAST(nodep->varp()->user2p(), Const);
|
||||
AstVarRef* exprvarrefp = VN_CAST(nodep->varp()->user2p(), VarRef);
|
||||
if (exprconstp) {
|
||||
|
|
@ -551,10 +542,10 @@ private:
|
|||
}
|
||||
|
||||
// Clone original module
|
||||
if (debug() >= 9) { nodep->dumpTree(cout, "inlcell:"); }
|
||||
// if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "inlcell:");
|
||||
// if (debug() >= 9) nodep->modp()->dumpTree(cout, "oldmod:");
|
||||
AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
|
||||
if (debug() >= 9) { newmodp->dumpTree(cout, "newmod:"); }
|
||||
if (debug() >= 9) newmodp->dumpTree(cout, "newmod:");
|
||||
// Clear var markings and find cell cross references
|
||||
AstNode::user2ClearTree();
|
||||
AstNode::user4ClearTree();
|
||||
|
|
@ -575,8 +566,9 @@ private:
|
|||
UASSERT_OBJ(pinNewVarp, pinOldVarp, "Cloning failed");
|
||||
|
||||
AstNode* connectRefp = pinp->exprp();
|
||||
UASSERT_OBJ(VN_IS(connectRefp, Const) || VN_IS(connectRefp, VarRef), pinp,
|
||||
"Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
UASSERT_OBJ(
|
||||
VN_IS(connectRefp, Const) || VN_IS(connectRefp, VarRef), pinp,
|
||||
"Unknown interconnect type; pinReconnectSimple should have cleared up");
|
||||
V3Inst::checkOutputShort(pinp);
|
||||
|
||||
// Propagate any attributes across the interconnect
|
||||
|
|
@ -624,7 +616,7 @@ public:
|
|||
m_modp = NULL;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~InlineVisitor() {
|
||||
virtual ~InlineVisitor() { //
|
||||
V3Stats::addStat("Optimizations, Inlined cells", m_statCells);
|
||||
}
|
||||
};
|
||||
|
|
@ -668,8 +660,7 @@ private:
|
|||
if (!irdtp) continue;
|
||||
|
||||
AstCell* cellp;
|
||||
if ((cellp = VN_CAST(fromVarp->user1p(), Cell))
|
||||
|| (cellp = irdtp->cellp())) {
|
||||
if ((cellp = VN_CAST(fromVarp->user1p(), Cell)) || (cellp = irdtp->cellp())) {
|
||||
varp->user1p(cellp);
|
||||
string alias = m_scope + "__DOT__" + pinp->name();
|
||||
cellp->addIntfRefp(new AstIntfRef(pinp->fileline(), alias));
|
||||
|
|
|
|||
243
src/V3Inst.cpp
243
src/V3Inst.cpp
|
|
@ -41,19 +41,19 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared each Cell:
|
||||
// AstPin::user1p() -> bool. True if created assignment already
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstCell* m_cellp; // Current cell
|
||||
AstCell* m_cellp; // Current cell
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
UINFO(4, " CELL " << nodep << endl);
|
||||
m_cellp = nodep;
|
||||
//VV***** We reset user1p() on each cell!!!
|
||||
// VV***** We reset user1p() on each cell!!!
|
||||
AstNode::user1ClearTree();
|
||||
iterateChildren(nodep);
|
||||
m_cellp = NULL;
|
||||
|
|
@ -61,13 +61,13 @@ private:
|
|||
virtual void visit(AstPin* nodep) VL_OVERRIDE {
|
||||
// PIN(p,expr) -> ASSIGNW(VARXREF(p),expr) (if sub's input)
|
||||
// or ASSIGNW(expr,VARXREF(p)) (if sub's output)
|
||||
UINFO(4," PIN "<<nodep<<endl);
|
||||
UINFO(4, " PIN " << nodep << endl);
|
||||
if (!nodep->user1()) {
|
||||
// Simplify it
|
||||
V3Inst::pinReconnectSimple(nodep, m_cellp, false);
|
||||
}
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
if (debug()>=9) nodep->dumpTree(cout, " Pin_oldb: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " Pin_oldb: ");
|
||||
V3Inst::checkOutputShort(nodep);
|
||||
// Use user1p on the PIN to indicate we created an assign for this pin
|
||||
if (!nodep->user1SetOnce()) {
|
||||
|
|
@ -78,27 +78,28 @@ private:
|
|||
if (nodep->modVarp()->isInoutish()) {
|
||||
nodep->v3fatalSrc("Unsupported: Verilator is a 2-state simulator");
|
||||
} else if (nodep->modVarp()->isWritable()) {
|
||||
AstNode* rhsp = new AstVarXRef(exprp->fileline(),
|
||||
nodep->modVarp(), m_cellp->name(), false);
|
||||
AstNode* rhsp
|
||||
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
||||
AstAssignW* assp = new AstAssignW(exprp->fileline(), exprp, rhsp);
|
||||
m_cellp->addNextHere(assp);
|
||||
} else if (nodep->modVarp()->isNonOutput()) {
|
||||
// Don't bother moving constants now,
|
||||
// we'll be pushing the const down to the cell soon enough.
|
||||
AstNode* assp = new AstAssignW
|
||||
(exprp->fileline(),
|
||||
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
|
||||
exprp);
|
||||
AstNode* assp = new AstAssignW(
|
||||
exprp->fileline(),
|
||||
new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), true),
|
||||
exprp);
|
||||
m_cellp->addNextHere(assp);
|
||||
if (debug()>=9) assp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) assp->dumpTree(cout, " _new: ");
|
||||
} else if (nodep->modVarp()->isIfaceRef()
|
||||
|| (VN_IS(nodep->modVarp()->subDTypep(), UnpackArrayDType)
|
||||
&& VN_IS(VN_CAST(nodep->modVarp()->subDTypep(),
|
||||
UnpackArrayDType)->subDTypep(), IfaceRefDType))) {
|
||||
&& VN_IS(VN_CAST(nodep->modVarp()->subDTypep(), UnpackArrayDType)
|
||||
->subDTypep(),
|
||||
IfaceRefDType))) {
|
||||
// Create an AstAssignVarScope for Vars to Cells so we can
|
||||
// link with their scope later
|
||||
AstNode* lhsp = new AstVarXRef(exprp->fileline(),
|
||||
nodep->modVarp(), m_cellp->name(), false);
|
||||
AstNode* lhsp
|
||||
= new AstVarXRef(exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
|
||||
const AstVarRef* refp = VN_CAST(exprp, VarRef);
|
||||
const AstVarXRef* xrefp = VN_CAST(exprp, VarXRef);
|
||||
UASSERT_OBJ(refp || xrefp, exprp,
|
||||
|
|
@ -117,7 +118,8 @@ private:
|
|||
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
// If we support primitives, update V3Undriven to remove special case
|
||||
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. Use --bbox-unsup to ignore tables.");
|
||||
nodep->v3error("Unsupported: Verilog 1995 UDP Tables. "
|
||||
"Use --bbox-unsup to ignore tables.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,15 +147,15 @@ class InstDeModVarVisitor : public AstNVisitor {
|
|||
// Expand all module variables, and save names for later reference
|
||||
private:
|
||||
// STATE
|
||||
typedef std::map<string,AstVar*> VarNameMap;
|
||||
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
|
||||
typedef std::map<string, AstVar*> VarNameMap;
|
||||
VarNameMap m_modVarNameMap; // Per module, name of cloned variables
|
||||
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (VN_IS(nodep->dtypep(), IfaceRefDType)) {
|
||||
UINFO(8," dm-1-VAR "<<nodep<<endl);
|
||||
UINFO(8, " dm-1-VAR " << nodep << endl);
|
||||
insert(nodep);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -164,7 +166,7 @@ private:
|
|||
public:
|
||||
// METHODS
|
||||
void insert(AstVar* nodep) {
|
||||
UINFO(8," dmINSERT "<<nodep<<endl);
|
||||
UINFO(8, " dmINSERT " << nodep << endl);
|
||||
m_modVarNameMap.insert(make_pair(nodep->name(), nodep));
|
||||
}
|
||||
AstVar* find(const string& name) {
|
||||
|
|
@ -176,15 +178,17 @@ public:
|
|||
}
|
||||
}
|
||||
void dump() {
|
||||
for (VarNameMap::iterator it=m_modVarNameMap.begin(); it!=m_modVarNameMap.end(); ++it) {
|
||||
cout<<"-namemap: "<<it->first<<" -> "<<it->second<<endl;
|
||||
for (VarNameMap::iterator it = m_modVarNameMap.begin(); it != m_modVarNameMap.end();
|
||||
++it) {
|
||||
cout << "-namemap: " << it->first << " -> " << it->second << endl;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit InstDeModVarVisitor() {}
|
||||
void main(AstNodeModule* nodep) {
|
||||
UINFO(8," dmMODULE "<<nodep<<endl);
|
||||
UINFO(8, " dmMODULE " << nodep << endl);
|
||||
m_modVarNameMap.clear();
|
||||
iterate(nodep);
|
||||
}
|
||||
|
|
@ -197,11 +201,11 @@ class InstDeVisitor : public AstNVisitor {
|
|||
// Find all cells with arrays, and convert to non-arrayed
|
||||
private:
|
||||
// STATE
|
||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||
int m_instSelNum; // Current instantiation count 0..N-1
|
||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||
int m_instSelNum; // Current instantiation count 0..N-1
|
||||
InstDeModVarVisitor m_deModVars; // State of variables for current cell module
|
||||
|
||||
typedef std::map<string,AstVar*> VarNameMap;
|
||||
typedef std::map<string, AstVar*> VarNameMap;
|
||||
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
|
|
@ -209,12 +213,12 @@ private:
|
|||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (VN_IS(nodep->dtypep(), UnpackArrayDType)
|
||||
&& VN_IS(VN_CAST(nodep->dtypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
|
||||
UINFO(8," dv-vec-VAR "<<nodep<<endl);
|
||||
UINFO(8, " dv-vec-VAR " << nodep << endl);
|
||||
AstUnpackArrayDType* arrdtype = VN_CAST(nodep->dtypep(), UnpackArrayDType);
|
||||
AstNode* prevp = NULL;
|
||||
for (int i = arrdtype->lsb(); i <= arrdtype->msb(); ++i) {
|
||||
string varNewName = nodep->name() + "__BRA__" + cvtToStr(i) + "__KET__";
|
||||
UINFO(8,"VAR name insert "<<varNewName<<" "<<nodep<<endl);
|
||||
UINFO(8, "VAR name insert " << varNewName << " " << nodep << endl);
|
||||
if (!m_deModVars.find(varNewName)) {
|
||||
AstIfaceRefDType* ifaceRefp
|
||||
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType)->cloneTree(false);
|
||||
|
|
@ -234,13 +238,16 @@ private:
|
|||
}
|
||||
}
|
||||
if (prevp) nodep->addNextHere(prevp);
|
||||
if (prevp && debug()==9) { prevp->dumpTree(cout, "newintf: "); cout << endl; }
|
||||
if (prevp && debug() == 9) {
|
||||
prevp->dumpTree(cout, "newintf: ");
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
UINFO(4," CELL "<<nodep<<endl);
|
||||
UINFO(4, " CELL " << nodep << endl);
|
||||
// Find submodule vars
|
||||
UASSERT_OBJ(nodep->modp(), nodep, "Unlinked");
|
||||
m_deModVars.main(nodep->modp());
|
||||
|
|
@ -249,14 +256,14 @@ private:
|
|||
m_cellRangep = nodep->rangep();
|
||||
|
||||
AstVar* ifaceVarp = VN_CAST(nodep->nextp(), Var);
|
||||
bool isIface = ifaceVarp
|
||||
&& VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
|
||||
&& VN_IS(VN_CAST(ifaceVarp->dtypep(),
|
||||
UnpackArrayDType)->subDTypep(), IfaceRefDType);
|
||||
bool isIface = ifaceVarp && VN_IS(ifaceVarp->dtypep(), UnpackArrayDType)
|
||||
&& VN_IS(VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType)->subDTypep(),
|
||||
IfaceRefDType);
|
||||
|
||||
// Make all of the required clones
|
||||
for (int i = 0; i < m_cellRangep->elementsConst(); i++) {
|
||||
m_instSelNum = m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
|
||||
m_instSelNum
|
||||
= m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i;
|
||||
int instNum = m_cellRangep->lsbConst() + i;
|
||||
|
||||
AstCell* newp = nodep->cloneTree(false);
|
||||
|
|
@ -266,15 +273,16 @@ private:
|
|||
// Somewhat illogically, we need to rename the original name of the cell too.
|
||||
// as that is the name users expect for dotting
|
||||
// The spec says we add [x], but that won't work in C...
|
||||
newp->name(newp->name()+"__BRA__"+cvtToStr(instNum)+"__KET__");
|
||||
newp->origName(newp->origName()+"__BRA__"+cvtToStr(instNum)+"__KET__");
|
||||
UINFO(8," CELL loop "<<newp<<endl);
|
||||
newp->name(newp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
||||
newp->origName(newp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
||||
UINFO(8, " CELL loop " << newp << endl);
|
||||
|
||||
// If this AstCell is actually an interface instantiation, also clone the IfaceRef
|
||||
// within the same parent module as the cell
|
||||
if (isIface) {
|
||||
AstUnpackArrayDType* arrdtype = VN_CAST(ifaceVarp->dtypep(), UnpackArrayDType);
|
||||
AstIfaceRefDType* origIfaceRefp = VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
|
||||
AstIfaceRefDType* origIfaceRefp
|
||||
= VN_CAST(arrdtype->subDTypep(), IfaceRefDType);
|
||||
origIfaceRefp->cellp(NULL);
|
||||
AstVar* varNewp = ifaceVarp->cloneTree(false);
|
||||
AstIfaceRefDType* ifaceRefp
|
||||
|
|
@ -283,14 +291,21 @@ private:
|
|||
ifaceRefp->cellp(newp);
|
||||
ifaceRefp->cellName(newp->name());
|
||||
varNewp->name(varNewp->name() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum) + "__KET__");
|
||||
varNewp->origName(varNewp->origName() + "__BRA__" + cvtToStr(instNum)
|
||||
+ "__KET__");
|
||||
varNewp->dtypep(ifaceRefp);
|
||||
newp->addNextHere(varNewp);
|
||||
if (debug()==9) { varNewp->dumpTree(cout, "newintf: "); cout << endl; }
|
||||
if (debug() == 9) {
|
||||
varNewp->dumpTree(cout, "newintf: ");
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
// Fixup pins
|
||||
iterateAndNextNull(newp->pinsp());
|
||||
if (debug()==9) { newp->dumpTree(cout, "newcell: "); cout<<endl; }
|
||||
if (debug() == 9) {
|
||||
newp->dumpTree(cout, "newcell: ");
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Done. Delete original
|
||||
|
|
@ -299,7 +314,8 @@ private:
|
|||
ifaceVarp->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(ifaceVarp), ifaceVarp);
|
||||
}
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else {
|
||||
m_cellRangep = NULL;
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -310,66 +326,66 @@ private:
|
|||
// Any non-direct pins need reconnection with a part-select
|
||||
if (!nodep->exprp()) return; // No-connect
|
||||
if (m_cellRangep) {
|
||||
UINFO(4," PIN "<<nodep<<endl);
|
||||
UINFO(4, " PIN " << nodep << endl);
|
||||
int pinwidth = nodep->modVarp()->width();
|
||||
int expwidth = nodep->exprp()->width();
|
||||
std::pair<uint32_t,uint32_t> pinDim = nodep->modVarp()->dtypep()->dimensions(false);
|
||||
std::pair<uint32_t,uint32_t> expDim = nodep->exprp()->dtypep()->dimensions(false);
|
||||
UINFO(4," PINVAR "<<nodep->modVarp()<<endl);
|
||||
UINFO(4," EXP "<<nodep->exprp()<<endl);
|
||||
UINFO(4," pinwidth ew="<<expwidth<<" pw="<<pinwidth
|
||||
<<" ed="<<expDim.first<<","<<expDim.second
|
||||
<<" pd="<<pinDim.first<<","<<pinDim.second<<endl);
|
||||
if (expDim.first == pinDim.first && expDim.second == pinDim.second+1) {
|
||||
std::pair<uint32_t, uint32_t> pinDim = nodep->modVarp()->dtypep()->dimensions(false);
|
||||
std::pair<uint32_t, uint32_t> expDim = nodep->exprp()->dtypep()->dimensions(false);
|
||||
UINFO(4, " PINVAR " << nodep->modVarp() << endl);
|
||||
UINFO(4, " EXP " << nodep->exprp() << endl);
|
||||
UINFO(4, " pinwidth ew=" << expwidth << " pw=" << pinwidth << " ed=" << expDim.first
|
||||
<< "," << expDim.second << " pd=" << pinDim.first << ","
|
||||
<< pinDim.second << endl);
|
||||
if (expDim.first == pinDim.first && expDim.second == pinDim.second + 1) {
|
||||
// Connection to array, where array dimensions match the instant dimension
|
||||
AstRange* rangep = VN_CAST(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep();
|
||||
int arraySelNum = rangep->littleEndian()
|
||||
? (rangep->elementsConst() - 1 - m_instSelNum) : m_instSelNum;
|
||||
? (rangep->elementsConst() - 1 - m_instSelNum)
|
||||
: m_instSelNum;
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
exprp = new AstArraySel(exprp->fileline(), exprp, arraySelNum);
|
||||
nodep->exprp(exprp);
|
||||
} else if (expwidth == pinwidth) {
|
||||
// NOP: Arrayed instants: widths match so connect to each instance
|
||||
} else if (expwidth == pinwidth*m_cellRangep->elementsConst()) {
|
||||
} else if (expwidth == pinwidth * m_cellRangep->elementsConst()) {
|
||||
// Arrayed instants: one bit for each of the instants (each
|
||||
// assign is 1 pinwidth wide)
|
||||
if (m_cellRangep->littleEndian()) {
|
||||
nodep->exprp()->v3warn(
|
||||
LITENDIAN,
|
||||
"Little endian cell range connecting to vector: MSB < LSB of cell range: "
|
||||
<<m_cellRangep->lsbConst()<<":"<<m_cellRangep->msbConst());
|
||||
<< m_cellRangep->lsbConst() << ":" << m_cellRangep->msbConst());
|
||||
}
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
bool inputPin = nodep->modVarp()->isNonOutput();
|
||||
if (!inputPin && !VN_IS(exprp, VarRef)
|
||||
&& !VN_IS(exprp, Concat) // V3Const will collapse the SEL with the one we're about to make
|
||||
&& !VN_IS(exprp, Sel)) { // V3Const will collapse the SEL with the one we're about to make
|
||||
nodep->v3error("Unsupported: Per-bit array instantiations with output connections to non-wires.");
|
||||
if (!inputPin
|
||||
&& !VN_IS(exprp, VarRef)
|
||||
// V3Const will collapse the SEL with the one we're about to make
|
||||
&& !VN_IS(exprp, Concat) && !VN_IS(exprp, Sel)) {
|
||||
nodep->v3error("Unsupported: Per-bit array instantiations with output "
|
||||
"connections to non-wires.");
|
||||
// Note spec allows more complicated matches such as slices and such
|
||||
}
|
||||
exprp = new AstSel(exprp->fileline(), exprp,
|
||||
pinwidth*m_instSelNum,
|
||||
pinwidth);
|
||||
exprp = new AstSel(exprp->fileline(), exprp, pinwidth * m_instSelNum, pinwidth);
|
||||
nodep->exprp(exprp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Width mismatch; V3Width should have errored out.");
|
||||
}
|
||||
} else if (AstArraySel* arrselp = VN_CAST(nodep->exprp(), ArraySel)) {
|
||||
if (AstUnpackArrayDType* arrp = VN_CAST(arrselp->lhsp()->dtypep(), UnpackArrayDType)) {
|
||||
if (!VN_IS(arrp->subDTypep(), IfaceRefDType))
|
||||
return;
|
||||
if (!VN_IS(arrp->subDTypep(), IfaceRefDType)) return;
|
||||
|
||||
V3Const::constifyParamsEdit(arrselp->rhsp());
|
||||
const AstConst* constp = VN_CAST(arrselp->rhsp(), Const);
|
||||
if (!constp) {
|
||||
nodep->v3error("Unsupported: Non-constant index when passing interface to module");
|
||||
nodep->v3error(
|
||||
"Unsupported: Non-constant index when passing interface to module");
|
||||
return;
|
||||
}
|
||||
string index = AstNode::encodeNumber(constp->toSInt());
|
||||
AstVarRef* varrefp = VN_CAST(arrselp->lhsp(), VarRef);
|
||||
AstVarXRef* newp = new AstVarXRef(nodep->fileline(),
|
||||
varrefp->name()+"__BRA__"+index+"__KET__",
|
||||
"", true);
|
||||
AstVarXRef* newp = new AstVarXRef(
|
||||
nodep->fileline(), varrefp->name() + "__BRA__" + index + "__KET__", "", true);
|
||||
newp->dtypep(nodep->modVarp()->dtypep());
|
||||
newp->packagep(varrefp->packagep());
|
||||
arrselp->addNextHere(newp);
|
||||
|
|
@ -378,8 +394,7 @@ private:
|
|||
} else {
|
||||
AstVar* pinVarp = nodep->modVarp();
|
||||
AstUnpackArrayDType* pinArrp = VN_CAST(pinVarp->dtypep(), UnpackArrayDType);
|
||||
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType))
|
||||
return;
|
||||
if (!pinArrp || !VN_IS(pinArrp->subDTypep(), IfaceRefDType)) return;
|
||||
AstNode* prevp = NULL;
|
||||
AstNode* prevPinp = NULL;
|
||||
// Clone the var referenced by the pin, and clone each var referenced by the varref
|
||||
|
|
@ -406,9 +421,9 @@ private:
|
|||
}
|
||||
}
|
||||
if (!varNewp) {
|
||||
if (debug()>=9) m_deModVars.dump();
|
||||
if (debug() >= 9) m_deModVars.dump();
|
||||
nodep->v3fatalSrc("Module dearray failed for "
|
||||
<<AstNode::prettyNameQ(varNewName));
|
||||
<< AstNode::prettyNameQ(varNewName));
|
||||
}
|
||||
|
||||
// But clone the pin for each module instance
|
||||
|
|
@ -464,21 +479,22 @@ private:
|
|||
|
||||
static AstNode* extendOrSel(FileLine* fl, AstNode* rhsp, AstNode* cmpWidthp) {
|
||||
if (cmpWidthp->width() > rhsp->width()) {
|
||||
rhsp = (rhsp->isSigned()
|
||||
? static_cast<AstNode*>(new AstExtendS(fl, rhsp))
|
||||
: static_cast<AstNode*>(new AstExtend (fl, rhsp)));
|
||||
rhsp->dtypeFrom(cmpWidthp); // Need proper widthMin, which may differ from AstSel created above
|
||||
rhsp = (rhsp->isSigned() ? static_cast<AstNode*>(new AstExtendS(fl, rhsp))
|
||||
: static_cast<AstNode*>(new AstExtend(fl, rhsp)));
|
||||
// Need proper widthMin, which may differ from AstSel created above
|
||||
rhsp->dtypeFrom(cmpWidthp);
|
||||
} else if (cmpWidthp->width() < rhsp->width()) {
|
||||
rhsp = new AstSel(fl, rhsp, 0, cmpWidthp->width());
|
||||
rhsp->dtypeFrom(cmpWidthp); // Need proper widthMin, which may differ from AstSel created above
|
||||
// Need proper widthMin, which may differ from AstSel created above
|
||||
rhsp->dtypeFrom(cmpWidthp);
|
||||
}
|
||||
// else don't change dtype, as might be e.g. array of something
|
||||
return rhsp;
|
||||
}
|
||||
|
||||
public:
|
||||
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt) {
|
||||
static AstAssignW* pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate,
|
||||
bool alwaysCvt) {
|
||||
// If a pin connection is "simple" leave it as-is
|
||||
// Else create a intermediate wire to perform the interconnect
|
||||
// Return the new assignment, if one was made
|
||||
|
|
@ -504,40 +520,33 @@ public:
|
|||
AstAssignW* assignp = NULL;
|
||||
if (connectRefp) connBasicp = VN_CAST(connectRefp->varp()->dtypep(), BasicDType);
|
||||
//
|
||||
if (!alwaysCvt
|
||||
&& connectRefp
|
||||
&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
|
||||
if (!alwaysCvt && connectRefp && connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
|
||||
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
|
||||
// Done. Same data type
|
||||
} else if (!alwaysCvt
|
||||
&& connectRefp
|
||||
&& connectRefp->varp()->isIfaceRef()) {
|
||||
} else if (!alwaysCvt && connectRefp && connectRefp->varp()->isIfaceRef()) {
|
||||
// Done. Interface
|
||||
} else if (!alwaysCvt
|
||||
&& connectXRefp
|
||||
&& connectXRefp->varp()
|
||||
} else if (!alwaysCvt && connectXRefp && connectXRefp->varp()
|
||||
&& connectXRefp->varp()->isIfaceRef()) {
|
||||
} else if (!alwaysCvt
|
||||
&& connBasicp
|
||||
&& pinBasicp
|
||||
} else if (!alwaysCvt && connBasicp && pinBasicp
|
||||
&& connBasicp->width() == pinBasicp->width()
|
||||
&& connBasicp->lsb() == pinBasicp->lsb()
|
||||
&& !connectRefp->varp()->isSc() // Need the signal as a 'shell' to convert types
|
||||
&& !connectRefp->varp()
|
||||
->isSc() // Need the signal as a 'shell' to convert types
|
||||
&& connBasicp->width() == pinVarp->width()) {
|
||||
// Done. One to one interconnect won't need a temporary variable.
|
||||
} else if (!alwaysCvt && !forTristate && VN_IS(pinp->exprp(), Const)) {
|
||||
// Done. Constant.
|
||||
} else {
|
||||
// Make a new temp wire
|
||||
//if (1||debug()>=9) { pinp->dumpTree(cout, "-in_pin:"); }
|
||||
// if (1 || debug() >= 9) { pinp->dumpTree(cout, "-in_pin:"); }
|
||||
V3Inst::checkOutputShort(pinp);
|
||||
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
|
||||
string newvarname = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||
// Prevent name conflict if both tri & non-tri add signals
|
||||
+(forTristate?"t":"")
|
||||
+"__"+cellp->name()+"__"+pinp->name());
|
||||
AstVar* newvarp = new AstVar(pinVarp->fileline(),
|
||||
AstVarType::MODULETEMP, newvarname, pinVarp);
|
||||
string newvarname
|
||||
= (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp")
|
||||
// Prevent name conflict if both tri & non-tri add signals
|
||||
+ (forTristate ? "t" : "") + "__" + cellp->name() + "__" + pinp->name());
|
||||
AstVar* newvarp
|
||||
= new AstVar(pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
|
||||
// Important to add statement next to cell, in case there is a
|
||||
// generate with same named cell
|
||||
cellp->addNextHere(newvarp);
|
||||
|
|
@ -547,8 +556,8 @@ public:
|
|||
} else if (pinVarp->isWritable()) {
|
||||
// See also V3Inst
|
||||
AstNode* rhsp = new AstVarRef(pinp->fileline(), newvarp, false);
|
||||
UINFO(5,"pinRecon width "<<pinVarp->width()<<" >? "
|
||||
<<rhsp->width()<<" >? "<<pinexprp->width()<<endl);
|
||||
UINFO(5, "pinRecon width " << pinVarp->width() << " >? " << rhsp->width() << " >? "
|
||||
<< pinexprp->width() << endl);
|
||||
rhsp = extendOrSel(pinp->fileline(), rhsp, pinVarp);
|
||||
pinp->exprp(new AstVarRef(newvarp->fileline(), newvarp, true));
|
||||
AstNode* rhsSelp = extendOrSel(pinp->fileline(), rhsp, pinexprp);
|
||||
|
|
@ -556,13 +565,12 @@ public:
|
|||
} else {
|
||||
// V3 width should have range/extended to make the widths correct
|
||||
assignp = new AstAssignW(pinp->fileline(),
|
||||
new AstVarRef(pinp->fileline(), newvarp, true),
|
||||
pinexprp);
|
||||
new AstVarRef(pinp->fileline(), newvarp, true), pinexprp);
|
||||
pinp->exprp(new AstVarRef(pinexprp->fileline(), newvarp, false));
|
||||
}
|
||||
if (assignp) cellp->addNextHere(assignp);
|
||||
//if (debug()) { pinp->dumpTree(cout, "- out:"); }
|
||||
//if (debug()) { assignp->dumpTree(cout, "- aout:"); }
|
||||
// if (debug()) { pinp->dumpTree(cout, "- out:"); }
|
||||
// if (debug()) { assignp->dumpTree(cout, "- aout:"); }
|
||||
}
|
||||
return assignp;
|
||||
}
|
||||
|
|
@ -571,20 +579,19 @@ public:
|
|||
//######################################################################
|
||||
// Inst class functions
|
||||
|
||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp,
|
||||
bool forTristate, bool alwaysCvt) {
|
||||
AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, bool forTristate,
|
||||
bool alwaysCvt) {
|
||||
return InstStatic::pinReconnectSimple(pinp, cellp, forTristate, alwaysCvt);
|
||||
}
|
||||
|
||||
void V3Inst::checkOutputShort(AstPin* nodep) {
|
||||
if (nodep->modVarp()->direction() == VDirection::OUTPUT) {
|
||||
if (VN_IS(nodep->exprp(), Const)
|
||||
|| VN_IS(nodep->exprp(), Extend)
|
||||
if (VN_IS(nodep->exprp(), Const) || VN_IS(nodep->exprp(), Extend)
|
||||
|| (VN_IS(nodep->exprp(), Concat)
|
||||
&& (VN_IS(VN_CAST(nodep->exprp(), Concat)->lhsp(), Const)))) {
|
||||
// Uses v3warn for error, as might be found multiple times
|
||||
nodep->v3warn(E_PORTSHORT, "Output port is connected to a constant pin,"
|
||||
" electrical short");
|
||||
" electrical short");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -593,17 +600,13 @@ void V3Inst::checkOutputShort(AstPin* nodep) {
|
|||
// Inst class visitor
|
||||
|
||||
void V3Inst::instAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
InstVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ InstVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("inst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
void V3Inst::dearrayAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
InstDeVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ InstDeVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("dearray", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
|
|
|||
124
src/V3Life.cpp
124
src/V3Life.cpp
|
|
@ -42,7 +42,7 @@
|
|||
class LifeState {
|
||||
// NODE STATE
|
||||
// See below
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
public:
|
||||
|
|
@ -56,8 +56,8 @@ public:
|
|||
~LifeState() {
|
||||
V3Stats::addStatSum("Optimizations, Lifetime assign deletions", m_statAssnDel);
|
||||
V3Stats::addStatSum("Optimizations, Lifetime constant prop", m_statAssnCon);
|
||||
for (std::vector<AstNode*>::iterator it = m_unlinkps.begin();
|
||||
it != m_unlinkps.end(); ++it) {
|
||||
for (std::vector<AstNode*>::iterator it = m_unlinkps.begin(); it != m_unlinkps.end();
|
||||
++it) {
|
||||
(*it)->unlinkFrBack();
|
||||
(*it)->deleteTree();
|
||||
}
|
||||
|
|
@ -70,10 +70,12 @@ public:
|
|||
// Structure for each variable encountered
|
||||
|
||||
class LifeVarEntry {
|
||||
AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant
|
||||
AstConst* m_constp; // Known constant value
|
||||
bool m_setBeforeUse; // First access was a set (and thus block above may have a set that can be deleted
|
||||
bool m_everSet; // Was ever assigned (and thus above block may not preserve constant propagation)
|
||||
AstNodeAssign* m_assignp; // Last assignment to this varscope, NULL if no longer relevant
|
||||
AstConst* m_constp; // Known constant value
|
||||
// First access was a set (and thus block above may have a set that can be deleted
|
||||
bool m_setBeforeUse;
|
||||
// Was ever assigned (and thus above block may not preserve constant propagation)
|
||||
bool m_everSet;
|
||||
|
||||
inline void init(bool setBeforeUse) {
|
||||
m_assignp = NULL;
|
||||
|
|
@ -81,19 +83,23 @@ class LifeVarEntry {
|
|||
m_setBeforeUse = setBeforeUse;
|
||||
m_everSet = false;
|
||||
}
|
||||
|
||||
public:
|
||||
class SIMPLEASSIGN {};
|
||||
class COMPLEXASSIGN {};
|
||||
class CONSUMED {};
|
||||
|
||||
LifeVarEntry(SIMPLEASSIGN, AstNodeAssign* assp) {
|
||||
init(true); simpleAssign(assp);
|
||||
init(true);
|
||||
simpleAssign(assp);
|
||||
}
|
||||
explicit LifeVarEntry(COMPLEXASSIGN) {
|
||||
init(false); complexAssign();
|
||||
init(false);
|
||||
complexAssign();
|
||||
}
|
||||
explicit LifeVarEntry(CONSUMED) {
|
||||
init(false); consumed();
|
||||
init(false);
|
||||
consumed();
|
||||
}
|
||||
~LifeVarEntry() {}
|
||||
inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment
|
||||
|
|
@ -127,9 +133,9 @@ class LifeBlock {
|
|||
// LIFE MAP
|
||||
// For each basic block, we'll make a new map of what variables that if/else is changing
|
||||
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
|
||||
LifeMap m_map; // Current active lifetime map for current scope
|
||||
LifeBlock* m_aboveLifep; // Upper life, or NULL
|
||||
LifeState* m_statep; // Current global state
|
||||
LifeMap m_map; // Current active lifetime map for current scope
|
||||
LifeBlock* m_aboveLifep; // Upper life, or NULL
|
||||
LifeState* m_statep; // Current global state
|
||||
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
|
|
@ -148,11 +154,11 @@ public:
|
|||
// we just don't optimize any public sigs
|
||||
// Check the var entry, and remove if appropriate
|
||||
if (AstNode* oldassp = entp->assignp()) {
|
||||
UINFO(7," PREV: "<<oldassp<<endl);
|
||||
UINFO(7, " PREV: " << oldassp << endl);
|
||||
// Redundant assignment, in same level block
|
||||
// Don't delete it now as it will confuse iteration since it maybe WAY
|
||||
// above our current iteration point.
|
||||
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
|
||||
if (debug() > 4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
|
||||
entp->complexAssign();
|
||||
VL_DO_DANGLING(m_statep->pushUnlinkDeletep(oldassp), oldassp);
|
||||
++m_statep->m_statAssnDel;
|
||||
|
|
@ -161,8 +167,8 @@ public:
|
|||
}
|
||||
void simpleAssign(AstVarScope* nodep, AstNodeAssign* assp) {
|
||||
// Do we have a old assignment we can nuke?
|
||||
UINFO(4," ASSIGNof: "<<nodep<<endl);
|
||||
UINFO(7," new: "<<assp<<endl);
|
||||
UINFO(4, " ASSIGNof: " << nodep << endl);
|
||||
UINFO(7, " new: " << assp << endl);
|
||||
LifeMap::iterator it = m_map.find(nodep);
|
||||
if (it != m_map.end()) {
|
||||
checkRemoveAssign(it);
|
||||
|
|
@ -170,10 +176,10 @@ public:
|
|||
} else {
|
||||
m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::SIMPLEASSIGN(), assp)));
|
||||
}
|
||||
//lifeDump();
|
||||
// lifeDump();
|
||||
}
|
||||
void complexAssign(AstVarScope* nodep) {
|
||||
UINFO(4," clearof: "<<nodep<<endl);
|
||||
UINFO(4, " clearof: " << nodep << endl);
|
||||
LifeMap::iterator it = m_map.find(nodep);
|
||||
if (it != m_map.end()) {
|
||||
it->second.complexAssign();
|
||||
|
|
@ -189,14 +195,14 @@ public:
|
|||
if (!varrefp->varp()->isSigPublic()) {
|
||||
// Aha, variable is constant; substitute in.
|
||||
// We'll later constant propagate
|
||||
UINFO(4," replaceconst: "<<varrefp<<endl);
|
||||
UINFO(4, " replaceconst: " << varrefp << endl);
|
||||
varrefp->replaceWith(constp->cloneTree(false));
|
||||
VL_DO_DANGLING(varrefp->deleteTree(), varrefp);
|
||||
++m_statep->m_statAssnCon;
|
||||
return; // **DONE, no longer a var reference**
|
||||
}
|
||||
}
|
||||
UINFO(4," usage: "<<nodep<<endl);
|
||||
UINFO(4, " usage: " << nodep << endl);
|
||||
it->second.consumed();
|
||||
} else {
|
||||
m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::CONSUMED())));
|
||||
|
|
@ -205,7 +211,7 @@ public:
|
|||
void complexAssignFind(AstVarScope* nodep) {
|
||||
LifeMap::iterator it = m_map.find(nodep);
|
||||
if (it != m_map.end()) {
|
||||
UINFO(4," casfind: "<<it->first<<endl);
|
||||
UINFO(4, " casfind: " << it->first << endl);
|
||||
it->second.complexAssign();
|
||||
} else {
|
||||
m_map.insert(make_pair(nodep, LifeVarEntry(LifeVarEntry::COMPLEXASSIGN())));
|
||||
|
|
@ -222,7 +228,7 @@ public:
|
|||
void lifeToAbove() {
|
||||
// Any varrefs under a if/else branch affect statements outside and after the if/else
|
||||
if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level");
|
||||
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
|
||||
for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
AstVarScope* nodep = it->first;
|
||||
m_aboveLifep->complexAssignFind(nodep);
|
||||
if (it->second.everSet()) {
|
||||
|
|
@ -236,36 +242,33 @@ public:
|
|||
}
|
||||
void dualBranch(LifeBlock* life1p, LifeBlock* life2p) {
|
||||
// Find any common sets on both branches of IF and propagate upwards
|
||||
//life1p->lifeDump();
|
||||
//life2p->lifeDump();
|
||||
// life1p->lifeDump();
|
||||
// life2p->lifeDump();
|
||||
AstNode::user1ClearTree(); // user1p() used on entire tree
|
||||
for (LifeMap::iterator it = life1p->m_map.begin(); it!=life1p->m_map.end(); ++it) {
|
||||
for (LifeMap::iterator it = life1p->m_map.begin(); it != life1p->m_map.end(); ++it) {
|
||||
// When the if branch sets a var before it's used, mark that variable
|
||||
if (it->second.setBeforeUse()) it->first->user1(1);
|
||||
}
|
||||
for (LifeMap::iterator it = life2p->m_map.begin(); it!=life2p->m_map.end(); ++it) {
|
||||
for (LifeMap::iterator it = life2p->m_map.begin(); it != life2p->m_map.end(); ++it) {
|
||||
// When the else branch sets a var before it's used
|
||||
AstVarScope* nodep = it->first;
|
||||
if (it->second.setBeforeUse() && nodep->user1()) {
|
||||
// Both branches set the var, we can remove the assignment before the IF.
|
||||
UINFO(4,"DUALBRANCH "<<nodep<<endl);
|
||||
UINFO(4, "DUALBRANCH " << nodep << endl);
|
||||
LifeMap::iterator itab = m_map.find(nodep);
|
||||
if (itab != m_map.end()) {
|
||||
checkRemoveAssign(itab);
|
||||
}
|
||||
if (itab != m_map.end()) checkRemoveAssign(itab);
|
||||
}
|
||||
}
|
||||
//this->lifeDump();
|
||||
// this->lifeDump();
|
||||
}
|
||||
// DEBUG
|
||||
void lifeDump() {
|
||||
UINFO(5, " LifeMap:"<<endl);
|
||||
for (LifeMap::iterator it = m_map.begin(); it!=m_map.end(); ++it) {
|
||||
UINFO(5, " Ent: "
|
||||
<<(it->second.setBeforeUse()?"[F] ":" ")
|
||||
<<it->first<<endl);
|
||||
if (it->second.assignp()) {
|
||||
UINFO(5, " Ass: "<<it->second.assignp()<<endl);
|
||||
UINFO(5, " LifeMap:" << endl);
|
||||
for (LifeMap::iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
UINFO(5, " Ent: " << (it->second.setBeforeUse() ? "[F] " : " ") << it->first
|
||||
<< endl);
|
||||
if (it->second.assignp()) { //
|
||||
UINFO(5, " Ass: " << it->second.assignp() << endl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -277,16 +280,16 @@ public:
|
|||
class LifeVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
LifeState* m_statep; // Current state
|
||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||
bool m_noopt; // Disable optimization of variables in this block
|
||||
bool m_tracingCall; // Iterating into a CCall to a CFunc
|
||||
LifeState* m_statep; // Current state
|
||||
bool m_sideEffect; // Side effects discovered in assign RHS
|
||||
bool m_noopt; // Disable optimization of variables in this block
|
||||
bool m_tracingCall; // Iterating into a CCall to a CFunc
|
||||
|
||||
// LIFE MAP
|
||||
// For each basic block, we'll make a new map of what variables that if/else is changing
|
||||
typedef std::map<AstVarScope*, LifeVarEntry> LifeMap;
|
||||
// cppcheck-suppress memleak // cppcheck bug - it is deleted
|
||||
LifeBlock* m_lifep; // Current active lifetime map for current scope
|
||||
LifeBlock* m_lifep; // Current active lifetime map for current scope
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -333,11 +336,11 @@ private:
|
|||
|
||||
//---- Track control flow changes
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
UINFO(4," IF "<<nodep<<endl);
|
||||
UINFO(4, " IF " << nodep << endl);
|
||||
// Condition is part of PREVIOUS block
|
||||
iterateAndNextNull(nodep->condp());
|
||||
LifeBlock* prevLifep = m_lifep;
|
||||
LifeBlock* ifLifep = new LifeBlock(prevLifep, m_statep);
|
||||
LifeBlock* ifLifep = new LifeBlock(prevLifep, m_statep);
|
||||
LifeBlock* elseLifep = new LifeBlock(prevLifep, m_statep);
|
||||
{
|
||||
m_lifep = ifLifep;
|
||||
|
|
@ -348,7 +351,7 @@ private:
|
|||
iterateAndNextNull(nodep->elsesp());
|
||||
}
|
||||
m_lifep = prevLifep;
|
||||
UINFO(4," join "<<endl);
|
||||
UINFO(4, " join " << endl);
|
||||
// Find sets on both flows
|
||||
m_lifep->dualBranch(ifLifep, elseLifep);
|
||||
// For the next assignments, clear any variables that were read or written in the block
|
||||
|
|
@ -380,7 +383,7 @@ private:
|
|||
iterateAndNextNull(nodep->incsp());
|
||||
}
|
||||
m_lifep = prevLifep;
|
||||
UINFO(4," joinfor"<<endl);
|
||||
UINFO(4, " joinfor" << endl);
|
||||
// For the next assignments, clear any variables that were read or written in the block
|
||||
condLifep->lifeToAbove();
|
||||
bodyLifep->lifeToAbove();
|
||||
|
|
@ -401,22 +404,23 @@ private:
|
|||
m_lifep = prevLifep;
|
||||
m_noopt = prev_noopt;
|
||||
}
|
||||
UINFO(4," joinjump"<<endl);
|
||||
UINFO(4, " joinjump" << endl);
|
||||
// For the next assignments, clear any variables that were read or written in the block
|
||||
bodyLifep->lifeToAbove();
|
||||
VL_DO_DANGLING(delete bodyLifep, bodyLifep);
|
||||
}
|
||||
virtual void visit(AstNodeCCall* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," CCALL "<<nodep<<endl);
|
||||
// UINFO(4, " CCALL " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
// Enter the function and trace it
|
||||
if (!nodep->funcp()->entryPoint()) { // else is non-inline or public function we optimize separately
|
||||
// else is non-inline or public function we optimize separately
|
||||
if (!nodep->funcp()->entryPoint()) {
|
||||
m_tracingCall = true;
|
||||
iterate(nodep->funcp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
//UINFO(4," CFUNC "<<nodep<<endl);
|
||||
// UINFO(4, " CFUNC " << nodep << endl);
|
||||
if (!m_tracingCall && !nodep->entryPoint()) return;
|
||||
m_tracingCall = false;
|
||||
if (nodep->dpiImport() && !nodep->pure()) {
|
||||
|
|
@ -439,7 +443,7 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
LifeVisitor(AstNode* nodep, LifeState* statep) {
|
||||
UINFO(4," LifeVisitor on "<<nodep<<endl);
|
||||
UINFO(4, " LifeVisitor on " << nodep << endl);
|
||||
m_statep = statep;
|
||||
m_sideEffect = false;
|
||||
m_noopt = false;
|
||||
|
|
@ -463,26 +467,26 @@ class LifeTopVisitor : public AstNVisitor {
|
|||
// finding code within.
|
||||
private:
|
||||
// STATE
|
||||
LifeState* m_statep; // Current state
|
||||
LifeState* m_statep; // Current state
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
if (nodep->entryPoint()) {
|
||||
// Usage model 1: Simulate all C code, doing lifetime analysis
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
LifeVisitor visitor(nodep, m_statep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
// Usage model 2: Cleanup basic blocks
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
LifeVisitor visitor(nodep, m_statep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
// Usage model 2: Cleanup basic blocks
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
LifeVisitor visitor(nodep, m_statep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
// Usage model 2: Cleanup basic blocks
|
||||
LifeVisitor visitor (nodep, m_statep);
|
||||
LifeVisitor visitor(nodep, m_statep);
|
||||
}
|
||||
virtual void visit(AstVar*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
|
|
@ -502,10 +506,10 @@ public:
|
|||
// Life class functions
|
||||
|
||||
void V3Life::lifeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
LifeState state;
|
||||
LifeTopVisitor visitor (nodep, &state);
|
||||
LifeTopVisitor visitor(nodep, &state);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("life", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
class LifePostElimVisitor : public AstNVisitor {
|
||||
private:
|
||||
bool m_tracingCall; // Iterating into a CCall to a CFunc
|
||||
bool m_tracingCall; // Iterating into a CCall to a CFunc
|
||||
|
||||
// NODE STATE
|
||||
// INPUT:
|
||||
|
|
@ -58,7 +58,7 @@ private:
|
|||
AstVarScope* vscp = nodep->varScopep();
|
||||
UASSERT_OBJ(vscp, nodep, "Scope not assigned");
|
||||
if (AstVarScope* newvscp = reinterpret_cast<AstVarScope*>(vscp->user4p())) {
|
||||
UINFO(9, " Replace "<<nodep<<" to "<<newvscp<<endl);
|
||||
UINFO(9, " Replace " << nodep << " to " << newvscp << endl);
|
||||
AstVarRef* newrefp = new AstVarRef(nodep->fileline(), newvscp, nodep->lvalue());
|
||||
nodep->replaceWith(newrefp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -105,11 +105,15 @@ public:
|
|||
struct LifeLocation {
|
||||
const ExecMTask* mtaskp;
|
||||
uint32_t sequence;
|
||||
|
||||
public:
|
||||
LifeLocation() : mtaskp(NULL), sequence(0) {}
|
||||
LifeLocation()
|
||||
: mtaskp(NULL)
|
||||
, sequence(0) {}
|
||||
LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_)
|
||||
: mtaskp(mtaskp_), sequence(sequence_) {}
|
||||
bool operator< (const LifeLocation& b) const {
|
||||
: mtaskp(mtaskp_)
|
||||
, sequence(sequence_) {}
|
||||
bool operator<(const LifeLocation& b) const {
|
||||
unsigned a_id = mtaskp ? mtaskp->id() : 0;
|
||||
unsigned b_id = b.mtaskp ? b.mtaskp->id() : 0;
|
||||
if (a_id < b_id) { return true; }
|
||||
|
|
@ -121,9 +125,11 @@ public:
|
|||
struct LifePostLocation {
|
||||
LifeLocation loc;
|
||||
AstAssignPost* nodep;
|
||||
LifePostLocation() : nodep(NULL) {}
|
||||
LifePostLocation()
|
||||
: nodep(NULL) {}
|
||||
LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_)
|
||||
: loc(loc_), nodep(nodep_) {}
|
||||
: loc(loc_)
|
||||
, nodep(nodep_) {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -134,27 +140,27 @@ private:
|
|||
// NODE STATE
|
||||
// Cleared on entire tree
|
||||
// AstVarScope::user4() -> AstVarScope*: Passed to LifePostElim to substitute this var
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser4InUse m_inuser4;
|
||||
|
||||
// STATE
|
||||
uint32_t m_sequence; // Sequence number of assigns/varrefs,
|
||||
uint32_t m_sequence; // Sequence number of assigns/varrefs,
|
||||
// // local to the current MTask.
|
||||
const ExecMTask* m_execMTaskp; // Current ExecMTask being processed,
|
||||
const ExecMTask* m_execMTaskp; // Current ExecMTask being processed,
|
||||
// // or NULL for serial code.
|
||||
VDouble0 m_statAssnDel; // Statistic tracking
|
||||
bool m_tracingCall; // Currently tracing a CCall to a CFunc
|
||||
VDouble0 m_statAssnDel; // Statistic tracking
|
||||
bool m_tracingCall; // Currently tracing a CCall to a CFunc
|
||||
|
||||
// Map each varscope to one or more locations where it's accessed.
|
||||
// These maps will not include any ASSIGNPOST accesses:
|
||||
typedef vl_unordered_map<const AstVarScope*, std::set<LifeLocation> > LocMap;
|
||||
LocMap m_reads; // VarScope read locations
|
||||
LocMap m_writes; // VarScope write locations
|
||||
LocMap m_reads; // VarScope read locations
|
||||
LocMap m_writes; // VarScope write locations
|
||||
|
||||
// Map each dly var to its AstAssignPost* node and the location thereof
|
||||
typedef vl_unordered_map<const AstVarScope*, LifePostLocation> PostLocMap;
|
||||
PostLocMap m_assignposts; // AssignPost dly var locations
|
||||
PostLocMap m_assignposts; // AssignPost dly var locations
|
||||
|
||||
const V3Graph* m_mtasksGraphp; // Mtask tracking graph
|
||||
const V3Graph* m_mtasksGraphp; // Mtask tracking graph
|
||||
vl_unique_ptr<GraphPathChecker> m_checker;
|
||||
|
||||
// METHODS
|
||||
|
|
@ -164,8 +170,7 @@ private:
|
|||
if (a.mtaskp == b.mtaskp) return a.sequence < b.sequence;
|
||||
return m_checker->pathExistsFrom(a.mtaskp, b.mtaskp);
|
||||
}
|
||||
bool outsideCriticalArea(LifeLocation loc,
|
||||
const std::set<LifeLocation>& dlyVarAssigns,
|
||||
bool outsideCriticalArea(LifeLocation loc, const std::set<LifeLocation>& dlyVarAssigns,
|
||||
LifeLocation assignPostLoc) {
|
||||
// If loc is before all of dlyVarAssigns, return true.
|
||||
// ("Before" means certain to be ordered before them at execution time.)
|
||||
|
|
@ -189,8 +194,7 @@ private:
|
|||
return true;
|
||||
}
|
||||
void squashAssignposts() {
|
||||
for (PostLocMap::iterator it = m_assignposts.begin();
|
||||
it != m_assignposts.end(); ++it) {
|
||||
for (PostLocMap::iterator it = m_assignposts.begin(); it != m_assignposts.end(); ++it) {
|
||||
LifePostLocation* app = &it->second;
|
||||
AstVarRef* lhsp = VN_CAST(app->nodep->lhsp(), VarRef); // original var
|
||||
AstVarRef* rhsp = VN_CAST(app->nodep->rhsp(), VarRef); // dly var
|
||||
|
|
@ -246,7 +250,7 @@ private:
|
|||
if (!canScrunch) continue;
|
||||
|
||||
// Delete and mark so LifePostElimVisitor will get it
|
||||
UINFO(4," DELETE "<<app->nodep<<endl);
|
||||
UINFO(4, " DELETE " << app->nodep << endl);
|
||||
dlyVarp->user4p(origVarp);
|
||||
VL_DO_DANGLING(app->nodep->unlinkFrBack()->deleteTree(), app->nodep);
|
||||
++m_statAssnDel;
|
||||
|
|
@ -262,8 +266,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
|
||||
if (v3Global.opt.mtasks()) {
|
||||
UASSERT_OBJ(m_mtasksGraphp, nodep,
|
||||
"Should have initted m_mtasksGraphp by now");
|
||||
UASSERT_OBJ(m_mtasksGraphp, nodep, "Should have initted m_mtasksGraphp by now");
|
||||
m_checker.reset(new GraphPathChecker(m_mtasksGraphp));
|
||||
} else {
|
||||
UASSERT_OBJ(!m_mtasksGraphp, nodep,
|
||||
|
|
@ -277,7 +280,7 @@ private:
|
|||
squashAssignposts();
|
||||
|
||||
// Replace any node4p varscopes with the new scope
|
||||
LifePostElimVisitor visitor (nodep);
|
||||
LifePostElimVisitor visitor(nodep);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
// Consumption/generation of a variable,
|
||||
|
|
@ -325,8 +328,8 @@ private:
|
|||
virtual void visit(AstExecGraph* nodep) VL_OVERRIDE {
|
||||
// Treat the ExecGraph like a call to each mtask body
|
||||
m_mtasksGraphp = nodep->depGraphp();
|
||||
for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp();
|
||||
mtaskVxp; mtaskVxp = mtaskVxp->verticesNextp()) {
|
||||
for (V3GraphVertex* mtaskVxp = m_mtasksGraphp->verticesBeginp(); mtaskVxp;
|
||||
mtaskVxp = mtaskVxp->verticesNextp()) {
|
||||
ExecMTask* mtaskp = dynamic_cast<ExecMTask*>(mtaskVxp);
|
||||
m_execMTaskp = mtaskp;
|
||||
m_sequence = 0;
|
||||
|
|
@ -361,10 +364,8 @@ public:
|
|||
// LifePost class functions
|
||||
|
||||
void V3LifePost::lifepostAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// Mark redundant AssignPost
|
||||
{
|
||||
LifePostDlyVisitor visitor(nodep);
|
||||
} // Destruct before checking
|
||||
{ LifePostDlyVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("life_post", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,16 +51,18 @@ public:
|
|||
|
||||
class LinkCellsVertex : public V3GraphVertex {
|
||||
AstNodeModule* m_modp;
|
||||
|
||||
public:
|
||||
LinkCellsVertex(V3Graph* graphp, AstNodeModule* modp)
|
||||
: V3GraphVertex(graphp), m_modp(modp) {}
|
||||
: V3GraphVertex(graphp)
|
||||
, m_modp(modp) {}
|
||||
virtual ~LinkCellsVertex() {}
|
||||
AstNodeModule* modp() const { return m_modp; }
|
||||
virtual string name() const { return modp()->name(); }
|
||||
virtual FileLine* fileline() const { return modp()->fileline(); }
|
||||
// Recursive modules get space for maximum recursion
|
||||
virtual uint32_t rankAdder() const {
|
||||
return m_modp->recursiveClone() ? (1+v3Global.opt.moduleRecursionDepth()) : 1;
|
||||
return m_modp->recursiveClone() ? (1 + v3Global.opt.moduleRecursionDepth()) : 1;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -74,10 +76,12 @@ public:
|
|||
|
||||
void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) {
|
||||
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(vertexp)) {
|
||||
vvertexp->modp()->v3error("Unsupported: Recursive multiple modules (module instantiates something leading back to itself): "
|
||||
<<vvertexp->modp()->prettyNameQ()<<endl
|
||||
<<V3Error::warnMore()
|
||||
<<"... note: self-recursion (module instantiating itself directly) is supported.");
|
||||
vvertexp->modp()->v3error(
|
||||
"Unsupported: Recursive multiple modules (module instantiates "
|
||||
"something leading back to itself): "
|
||||
<< vvertexp->modp()->prettyNameQ() << endl
|
||||
<< V3Error::warnMore()
|
||||
<< "... note: self-recursion (module instantiating itself directly) is supported.");
|
||||
V3Error::abortIfErrors();
|
||||
} else { // Everything should match above, but...
|
||||
v3fatalSrc("Recursive instantiations");
|
||||
|
|
@ -97,19 +101,19 @@ private:
|
|||
// AstCell::user2() // bool clone renaming completed
|
||||
// Allocated across all readFiles in V3Global::readFiles:
|
||||
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
VInFilter* m_filterp; // Parser filter
|
||||
V3ParseSym* m_parseSymp; // Parser symbol table
|
||||
VInFilter* m_filterp; // Parser filter
|
||||
V3ParseSym* m_parseSymp; // Parser symbol table
|
||||
|
||||
// Below state needs to be preserved between each module call.
|
||||
AstNodeModule* m_modp; // Current module
|
||||
VSymGraph m_mods; // Symbol table of all module names
|
||||
LinkCellsGraph m_graph; // Linked graph of all cell interconnects
|
||||
LibraryVertex* m_libVertexp; // Vertex at root of all libraries
|
||||
V3GraphVertex* m_topVertexp; // Vertex of top module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
VSymGraph m_mods; // Symbol table of all module names
|
||||
LinkCellsGraph m_graph; // Linked graph of all cell interconnects
|
||||
LibraryVertex* m_libVertexp; // Vertex at root of all libraries
|
||||
V3GraphVertex* m_topVertexp; // Vertex of top module
|
||||
vl_unordered_set<string> m_declfnWarned; // Files we issued DECLFILENAME on
|
||||
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -117,16 +121,17 @@ private:
|
|||
// METHODS
|
||||
V3GraphVertex* vertex(AstNodeModule* nodep) {
|
||||
// Return corresponding vertex for this module
|
||||
if (!nodep->user1p()) {
|
||||
nodep->user1p(new LinkCellsVertex(&m_graph, nodep));
|
||||
}
|
||||
if (!nodep->user1p()) nodep->user1p(new LinkCellsVertex(&m_graph, nodep));
|
||||
return (nodep->user1u().toGraphVertex());
|
||||
}
|
||||
|
||||
AstNodeModule* findModuleSym(const string& modName) {
|
||||
VSymEnt* foundp = m_mods.rootp()->findIdFallback(modName);
|
||||
if (!foundp) return NULL;
|
||||
else return VN_CAST(foundp->nodep(), NodeModule);
|
||||
if (!foundp) {
|
||||
return NULL;
|
||||
} else {
|
||||
return VN_CAST(foundp->nodep(), NodeModule);
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeModule* resolveModule(AstNode* nodep, const string& modName) {
|
||||
|
|
@ -136,7 +141,7 @@ private:
|
|||
// If file not found, make AstNotFoundModule, rather than error out.
|
||||
// We'll throw the error when we know the module will really be needed.
|
||||
string prettyName = AstNode::prettyName(modName);
|
||||
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
|
||||
V3Parse parser(v3Global.rootp(), m_filterp, m_parseSymp);
|
||||
// true below -> other simulators treat modules in link-found files as library cells
|
||||
parser.parseFile(nodep->fileline(), prettyName, true, "");
|
||||
V3Error::abortIfErrors();
|
||||
|
|
@ -147,7 +152,7 @@ private:
|
|||
if (!modp) {
|
||||
// This shouldn't throw a message as parseFile will create
|
||||
// a AstNotFoundModule for us
|
||||
nodep->v3error("Can't resolve module reference: '"<<prettyName<<"'");
|
||||
nodep->v3error("Can't resolve module reference: '" << prettyName << "'");
|
||||
}
|
||||
}
|
||||
return modp;
|
||||
|
|
@ -162,11 +167,11 @@ private:
|
|||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
|
||||
m_graph.dumpDotFilePrefixed("linkcells");
|
||||
m_graph.rank();
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) {
|
||||
if (LinkCellsVertex* vvertexp = dynamic_cast<LinkCellsVertex*>(itp)) {
|
||||
// +1 so we leave level 1 for the new wrapper we'll make in a moment
|
||||
AstNodeModule* modp = vvertexp->modp();
|
||||
modp->level(vvertexp->rank()+1);
|
||||
modp->level(vvertexp->rank() + 1);
|
||||
if (vvertexp == m_topVertexp && modp->level() != 2) {
|
||||
AstNodeModule* abovep = NULL;
|
||||
if (V3GraphEdge* edgep = vvertexp->inBeginp()) {
|
||||
|
|
@ -175,15 +180,16 @@ private:
|
|||
abovep = eFromVertexp->modp();
|
||||
}
|
||||
}
|
||||
v3error("Specified --top-module '"<<v3Global.opt.topModule()
|
||||
<<"' isn't at the top level, it's under another cell '"
|
||||
<<(abovep ? abovep->prettyName() : "UNKNOWN")<<"'");
|
||||
v3error("Specified --top-module '"
|
||||
<< v3Global.opt.topModule()
|
||||
<< "' isn't at the top level, it's under another cell '"
|
||||
<< (abovep ? abovep->prettyName() : "UNKNOWN") << "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.opt.topModule()!=""
|
||||
&& !m_topVertexp) {
|
||||
v3error("Specified --top-module '"<<v3Global.opt.topModule()<<"' was not found in design.");
|
||||
if (v3Global.opt.topModule() != "" && !m_topVertexp) {
|
||||
v3error("Specified --top-module '" << v3Global.opt.topModule()
|
||||
<< "' was not found in design.");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
|
|
@ -200,9 +206,9 @@ private:
|
|||
if (m_declfnWarned.find(nodep->fileline()->filename()) == m_declfnWarned.end()) {
|
||||
m_declfnWarned.insert(nodep->fileline()->filename());
|
||||
nodep->v3warn(DECLFILENAME, "Filename '"
|
||||
<< nodep->fileline()->filebasenameNoExt()
|
||||
<< "' does not match " << nodep->typeName()
|
||||
<< " name: " << nodep->prettyNameQ());
|
||||
<< nodep->fileline()->filebasenameNoExt()
|
||||
<< "' does not match " << nodep->typeName()
|
||||
<< " name: " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
if (VN_IS(nodep, Iface) || VN_IS(nodep, Package)) {
|
||||
|
|
@ -215,7 +221,7 @@ private:
|
|||
nodep->inLibrary(false); // Safer to make sure it doesn't disappear
|
||||
}
|
||||
if (v3Global.opt.topModule() == "" ? nodep->inLibrary() // Library cells are lower
|
||||
: !topMatch) { // Any non-specified module is lower
|
||||
: !topMatch) { // Any non-specified module is lower
|
||||
// Put under a fake vertex so that the graph ranking won't indicate
|
||||
// this is a top level module
|
||||
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
|
||||
|
|
@ -230,7 +236,7 @@ private:
|
|||
|
||||
virtual void visit(AstIfaceRefDType* nodep) VL_OVERRIDE {
|
||||
// Cell: Resolve its filename. If necessary, parse it.
|
||||
UINFO(4,"Link IfaceRef: "<<nodep<<endl);
|
||||
UINFO(4, "Link IfaceRef: " << nodep << endl);
|
||||
// Use findIdUpward instead of findIdFlat; it doesn't matter for now
|
||||
// but we might support modules-under-modules someday.
|
||||
AstNodeModule* modp = resolveModule(nodep, nodep->ifaceName());
|
||||
|
|
@ -241,7 +247,7 @@ private:
|
|||
if (!nodep->cellp()) nodep->ifacep(VN_CAST(modp, Iface));
|
||||
} else if (VN_IS(modp, NotFoundModule)) { // Will error out later
|
||||
} else {
|
||||
nodep->v3error("Non-interface used as an interface: "<<nodep->prettyNameQ());
|
||||
nodep->v3error("Non-interface used as an interface: " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
// Note cannot do modport resolution here; modports are allowed underneath generates
|
||||
|
|
@ -260,7 +266,7 @@ private:
|
|||
// TODO this doesn't allow bind to dotted hier names, that would require
|
||||
// this move to post param, which would mean we do not auto-read modules
|
||||
// and means we cannot compute module levels until later.
|
||||
UINFO(4,"Link Bind: "<<nodep<<endl);
|
||||
UINFO(4, "Link Bind: " << nodep << endl);
|
||||
AstNodeModule* modp = resolveModule(nodep, nodep->name());
|
||||
if (modp) {
|
||||
AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext();
|
||||
|
|
@ -268,7 +274,8 @@ private:
|
|||
AstNodeModule* oldModp = m_modp;
|
||||
{
|
||||
m_modp = modp;
|
||||
modp->addStmtp(cellsp); // Important that this adds to end, as next iterate assumes does all cells
|
||||
// Important that this adds to end, as next iterate assumes does all cells
|
||||
modp->addStmtp(cellsp);
|
||||
iterateAndNextNull(cellsp);
|
||||
}
|
||||
m_modp = oldModp;
|
||||
|
|
@ -281,19 +288,18 @@ private:
|
|||
// Execute only once. Complication is that cloning may result in
|
||||
// user1 being set (for pre-clone) so check if user1() matches the
|
||||
// m_mod, if 0 never did it, if !=, it is an unprocessed clone
|
||||
bool cloned = (nodep->user1p() && nodep->user1p()!=m_modp);
|
||||
if (nodep->user1p()==m_modp) return; // AstBind and AstNodeModule may call a cell twice
|
||||
bool cloned = (nodep->user1p() && nodep->user1p() != m_modp);
|
||||
if (nodep->user1p() == m_modp) return; // AstBind and AstNodeModule may call a cell twice
|
||||
nodep->user1p(m_modp);
|
||||
//
|
||||
if (!nodep->modp() || cloned) {
|
||||
UINFO(4,"Link Cell: "<<nodep<<endl);
|
||||
UINFO(4, "Link Cell: " << nodep << endl);
|
||||
// Use findIdFallback instead of findIdFlat; it doesn't matter for now
|
||||
// but we might support modules-under-modules someday.
|
||||
AstNodeModule* cellmodp = resolveModule(nodep, nodep->modName());
|
||||
if (cellmodp) {
|
||||
if (cellmodp == m_modp
|
||||
|| cellmodp->user2p() == m_modp) {
|
||||
UINFO(1,"Self-recursive module "<<cellmodp<<endl);
|
||||
if (cellmodp == m_modp || cellmodp->user2p() == m_modp) {
|
||||
UINFO(1, "Self-recursive module " << cellmodp << endl);
|
||||
cellmodp->recursive(true);
|
||||
nodep->recursive(true);
|
||||
if (!cellmodp->recursiveClone()) {
|
||||
|
|
@ -307,27 +313,25 @@ private:
|
|||
AstNodeModule* otherModp = VN_CAST(cellmodp->user2p(), NodeModule);
|
||||
if (!otherModp) {
|
||||
otherModp = cellmodp->cloneTree(false);
|
||||
otherModp->name(otherModp->name()+"__Vrcm");
|
||||
otherModp->name(otherModp->name() + "__Vrcm");
|
||||
otherModp->user1p(NULL); // Need new vertex
|
||||
otherModp->user2p(cellmodp);
|
||||
otherModp->recursiveClone(true);
|
||||
// user1 etc will retain its pre-clone value
|
||||
cellmodp->user2p(otherModp);
|
||||
v3Global.rootp()->addModulep(otherModp);
|
||||
new V3GraphEdge(&m_graph, vertex(cellmodp),
|
||||
vertex(otherModp), 1, false);
|
||||
new V3GraphEdge(&m_graph, vertex(cellmodp), vertex(otherModp), 1,
|
||||
false);
|
||||
}
|
||||
cellmodp = otherModp;
|
||||
nodep->modp(cellmodp);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// In the Vrcm, which needs to point back to Vrcm flavor
|
||||
// The cell already has the correct resolution (to Vrcm)
|
||||
nodep->modp(cellmodp);
|
||||
// We don't create a V3GraphEdge (as it would be circular)
|
||||
}
|
||||
}
|
||||
else { // Non-recursive
|
||||
} else { // Non-recursive
|
||||
// Track module depths, so can sort list from parent down to children
|
||||
nodep->modp(cellmodp);
|
||||
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(cellmodp), 1, false);
|
||||
|
|
@ -336,19 +340,17 @@ private:
|
|||
}
|
||||
// Remove AstCell(AstPin("",NULL)), it's a side effect of how we parse "()"
|
||||
// the empty middle is identical to the empty rule that must find pins in "(,)".
|
||||
if (nodep->pinsp() && !nodep->pinsp()->nextp()
|
||||
&& nodep->pinsp()->name() == ""
|
||||
if (nodep->pinsp() && !nodep->pinsp()->nextp() && nodep->pinsp()->name() == ""
|
||||
&& !nodep->pinsp()->exprp()) {
|
||||
pushDeletep(nodep->pinsp()->unlinkFrBackWithNext());
|
||||
}
|
||||
if (nodep->paramsp() && !nodep->paramsp()->nextp()
|
||||
&& nodep->paramsp()->name() == ""
|
||||
if (nodep->paramsp() && !nodep->paramsp()->nextp() && nodep->paramsp()->name() == ""
|
||||
&& !nodep->paramsp()->exprp()) {
|
||||
pushDeletep(nodep->paramsp()->unlinkFrBackWithNext());
|
||||
}
|
||||
// Convert .* to list of pins
|
||||
bool pinStar = false;
|
||||
for (AstPin* nextp, *pinp = nodep->pinsp(); pinp; pinp=nextp) {
|
||||
for (AstPin *nextp, *pinp = nodep->pinsp(); pinp; pinp = nextp) {
|
||||
nextp = VN_CAST(pinp->nextp(), Pin);
|
||||
if (pinp->dotStar()) {
|
||||
if (pinStar) pinp->v3error("Duplicate .* in a cell");
|
||||
|
|
@ -358,40 +360,41 @@ private:
|
|||
}
|
||||
}
|
||||
// Convert unnamed pins to pin number based assignments
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (pinp->name()=="") pinp->name("__pinNumber"+cvtToStr(pinp->pinNum()));
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (pinp->name() == "") pinp->name("__pinNumber" + cvtToStr(pinp->pinNum()));
|
||||
}
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
pinp->param(true);
|
||||
if (pinp->name()=="") pinp->name("__paramNumber"+cvtToStr(pinp->pinNum()));
|
||||
if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum()));
|
||||
}
|
||||
if (nodep->modp()) {
|
||||
nodep->modName(nodep->modp()->name());
|
||||
// Note what pins exist
|
||||
vl_unordered_set<string> ports; // Symbol table of all connected port names
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (pinp->name() == "")
|
||||
pinp->v3error("Connect by position is illegal in .* connected cells");
|
||||
if (!pinp->exprp()) {
|
||||
if (pinp->name().substr(0, 11) == "__pinNumber") {
|
||||
pinp->v3warn(PINNOCONNECT, "Cell pin is not connected: "
|
||||
<<pinp->prettyNameQ());
|
||||
pinp->v3warn(PINNOCONNECT,
|
||||
"Cell pin is not connected: " << pinp->prettyNameQ());
|
||||
} else {
|
||||
pinp->v3warn(PINCONNECTEMPTY,
|
||||
"Cell pin connected by name with empty reference: "
|
||||
<<pinp->prettyNameQ());
|
||||
<< pinp->prettyNameQ());
|
||||
}
|
||||
}
|
||||
ports.insert(pinp->name());
|
||||
}
|
||||
// We search ports, rather than in/out declarations as they aren't resolved yet,
|
||||
// and it's easier to do it now than in V3LinkDot when we'd need to repeat steps.
|
||||
for (AstNode* portnodep = nodep->modp()->stmtsp();
|
||||
portnodep; portnodep=portnodep->nextp()) {
|
||||
for (AstNode* portnodep = nodep->modp()->stmtsp(); portnodep;
|
||||
portnodep = portnodep->nextp()) {
|
||||
if (const AstPort* portp = VN_CAST(portnodep, Port)) {
|
||||
if (ports.find(portp->name()) == ports.end()
|
||||
&& ports.find("__pinNumber"+cvtToStr(portp->pinNum())) == ports.end()) {
|
||||
&& ports.find("__pinNumber" + cvtToStr(portp->pinNum())) == ports.end()) {
|
||||
if (pinStar) {
|
||||
UINFO(9," need .* PORT "<<portp<<endl);
|
||||
UINFO(9, " need .* PORT " << portp << endl);
|
||||
// Create any not already connected
|
||||
AstPin* newp = new AstPin(nodep->fileline(), 0, portp->name(),
|
||||
new AstParseRef(nodep->fileline(),
|
||||
|
|
@ -400,8 +403,8 @@ private:
|
|||
newp->svImplicit(true);
|
||||
nodep->addPinsp(newp);
|
||||
} else { // warn on the CELL that needs it, not the port
|
||||
nodep->v3warn(PINMISSING, "Cell has missing pin: "
|
||||
<<portp->prettyNameQ());
|
||||
nodep->v3warn(PINMISSING,
|
||||
"Cell has missing pin: " << portp->prettyNameQ());
|
||||
AstPin* newp = new AstPin(nodep->fileline(), 0, portp->name(), NULL);
|
||||
nodep->addPinsp(newp);
|
||||
}
|
||||
|
|
@ -413,8 +416,9 @@ private:
|
|||
// Cell really is the parent's instantiation of an interface, not a normal module
|
||||
// Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
|
||||
// in the same way that a child does. Rename though to avoid conflict with cell.
|
||||
// This is quite similar to how classes work; when unpacked classes are better supported
|
||||
// may remap interfaces to be more like a class.
|
||||
// This is quite similar to how classes work; when unpacked
|
||||
// classes are better supported may remap interfaces to be more
|
||||
// like a class.
|
||||
if (!nodep->hasIfaceVar()) {
|
||||
string varName = nodep->name() + "__Viftop"; // V3LinkDot looks for this naming
|
||||
AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(),
|
||||
|
|
@ -425,8 +429,8 @@ private:
|
|||
AstVar* varp;
|
||||
if (nodep->rangep()) {
|
||||
AstNodeArrayDType* arrp
|
||||
= new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(),
|
||||
idtypep, nodep->rangep()->cloneTree(true));
|
||||
= new AstUnpackArrayDType(nodep->fileline(), VFlagChildDType(), idtypep,
|
||||
nodep->rangep()->cloneTree(true));
|
||||
varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName,
|
||||
VFlagChildDType(), arrp);
|
||||
} else {
|
||||
|
|
@ -438,10 +442,8 @@ private:
|
|||
nodep->hasIfaceVar(true);
|
||||
}
|
||||
}
|
||||
if (nodep->modp()) {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
UINFO(4," Link Cell done: "<<nodep<<endl);
|
||||
if (nodep->modp()) { iterateChildren(nodep); }
|
||||
UINFO(4, " Link Cell done: " << nodep << endl);
|
||||
}
|
||||
|
||||
// Accelerate the recursion
|
||||
|
|
@ -452,17 +454,18 @@ private:
|
|||
// METHODS
|
||||
void readModNames() {
|
||||
// Look at all modules, and store pointers to all module names
|
||||
for (AstNodeModule* nextp,* nodep = v3Global.rootp()->modulesp(); nodep; nodep=nextp) {
|
||||
for (AstNodeModule *nextp, *nodep = v3Global.rootp()->modulesp(); nodep; nodep = nextp) {
|
||||
nextp = VN_CAST(nodep->nextp(), NodeModule);
|
||||
AstNodeModule* foundp = findModuleSym(nodep->name());
|
||||
if (foundp && foundp != nodep) {
|
||||
if (!(foundp->fileline()->warnIsOff(V3ErrorCode::MODDUP)
|
||||
|| nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP))) {
|
||||
nodep->v3warn(MODDUP, "Duplicate declaration of module: "
|
||||
<<nodep->prettyNameQ()<<endl
|
||||
<<nodep->warnContextPrimary()<<endl
|
||||
<<foundp->warnOther()<<"... Location of original declaration"<<endl
|
||||
<<foundp->warnContextSecondary());
|
||||
<< nodep->prettyNameQ() << endl
|
||||
<< nodep->warnContextPrimary() << endl
|
||||
<< foundp->warnOther()
|
||||
<< "... Location of original declaration" << endl
|
||||
<< foundp->warnContextSecondary());
|
||||
}
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
|
|
@ -470,7 +473,7 @@ private:
|
|||
m_mods.rootp()->insert(nodep->name(), new VSymEnt(&m_mods, nodep));
|
||||
}
|
||||
}
|
||||
//if (debug()>=9) m_mods.dump(cout, "-syms: ");
|
||||
// if (debug() >= 9) m_mods.dump(cout, "-syms: ");
|
||||
}
|
||||
|
||||
public:
|
||||
|
|
@ -491,6 +494,6 @@ public:
|
|||
// Link class functions
|
||||
|
||||
void V3LinkCells::link(AstNetlist* nodep, VInFilter* filterp, V3ParseSym* parseSymp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
LinkCellsVisitor visitor (nodep, filterp, parseSymp);
|
||||
UINFO(4, __FUNCTION__ << ": " << endl);
|
||||
LinkCellsVisitor visitor(nodep, filterp, parseSymp);
|
||||
}
|
||||
|
|
|
|||
1284
src/V3LinkDot.cpp
1284
src/V3LinkDot.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -41,35 +41,37 @@ private:
|
|||
typedef std::vector<AstBegin*> BeginStack;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
AstWhile* m_loopp; // Current loop
|
||||
bool m_loopInc; // In loop increment
|
||||
int m_modRepeatNum; // Repeat counter
|
||||
BeginStack m_beginStack; // All begin blocks above current node
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
AstWhile* m_loopp; // Current loop
|
||||
bool m_loopInc; // In loop increment
|
||||
int m_modRepeatNum; // Repeat counter
|
||||
BeginStack m_beginStack; // All begin blocks above current node
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
AstJumpLabel* findAddLabel(AstNode* nodep, bool endOfIter) {
|
||||
// Put label under given node, and if WHILE optionally at end of iteration
|
||||
UINFO(4,"Create label for "<<nodep<<endl);
|
||||
UINFO(4, "Create label for " << nodep << endl);
|
||||
if (VN_IS(nodep, JumpLabel)) return VN_CAST(nodep, JumpLabel); // Done
|
||||
|
||||
AstNode* underp = NULL;
|
||||
bool under_and_next = true;
|
||||
if (VN_IS(nodep, Begin)) underp = VN_CAST(nodep, Begin)->stmtsp();
|
||||
else if (VN_IS(nodep, NodeFTask)) underp = VN_CAST(nodep, NodeFTask)->stmtsp();
|
||||
else if (VN_IS(nodep, While)) {
|
||||
bool under_and_next = true;
|
||||
if (VN_IS(nodep, Begin)) {
|
||||
underp = VN_CAST(nodep, Begin)->stmtsp();
|
||||
} else if (VN_IS(nodep, NodeFTask)) {
|
||||
underp = VN_CAST(nodep, NodeFTask)->stmtsp();
|
||||
} else if (VN_IS(nodep, While)) {
|
||||
if (endOfIter) {
|
||||
// Note we jump to end of bodysp; a FOR loop has its
|
||||
// increment under incsp() which we don't skip
|
||||
underp = VN_CAST(nodep, While)->bodysp();
|
||||
} else {
|
||||
underp = nodep; under_and_next = false; // IE we skip the entire while
|
||||
underp = nodep;
|
||||
under_and_next = false; // IE we skip the entire while
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown jump point for break/disable/continue");
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -78,7 +80,7 @@ private:
|
|||
// see t_func_return test.
|
||||
while (underp && VN_IS(underp, Var)) underp = underp->nextp();
|
||||
UASSERT_OBJ(underp, nodep, "Break/disable/continue not under expected statement");
|
||||
UINFO(5," Underpoint is "<<underp<<endl);
|
||||
UINFO(5, " Underpoint is " << underp << endl);
|
||||
|
||||
if (VN_IS(underp, JumpLabel)) {
|
||||
return VN_CAST(underp, JumpLabel);
|
||||
|
|
@ -86,17 +88,18 @@ private:
|
|||
AstJumpLabel* labelp = new AstJumpLabel(nodep->fileline(), NULL);
|
||||
|
||||
AstNRelinker repHandle;
|
||||
if (under_and_next) underp->unlinkFrBackWithNext(&repHandle);
|
||||
else underp->unlinkFrBack(&repHandle);
|
||||
if (under_and_next) {
|
||||
underp->unlinkFrBackWithNext(&repHandle);
|
||||
} else {
|
||||
underp->unlinkFrBack(&repHandle);
|
||||
}
|
||||
repHandle.relink(labelp);
|
||||
|
||||
labelp->addStmtsp(underp);
|
||||
// Keep any AstVars under the function not under the new JumpLabel
|
||||
for (AstNode* nextp, *varp=underp; varp; varp = nextp) {
|
||||
for (AstNode *nextp, *varp = underp; varp; varp = nextp) {
|
||||
nextp = varp->nextp();
|
||||
if (VN_IS(varp, Var)) {
|
||||
labelp->addPrev(varp->unlinkFrBack());
|
||||
}
|
||||
if (VN_IS(varp, Var)) labelp->addPrev(varp->unlinkFrBack());
|
||||
}
|
||||
return labelp;
|
||||
}
|
||||
|
|
@ -121,7 +124,7 @@ private:
|
|||
m_ftaskp = NULL;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
UINFO(8, " " << nodep << endl);
|
||||
m_beginStack.push_back(nodep);
|
||||
iterateChildren(nodep);
|
||||
m_beginStack.pop_back();
|
||||
|
|
@ -131,29 +134,24 @@ private:
|
|||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
string name = string("__Vrepeat")+cvtToStr(m_modRepeatNum++);
|
||||
string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++);
|
||||
// Spec says value is integral, if negative is ignored
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
nodep->findSigned32DType());
|
||||
varp->usedLoopIdx(true);
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, true),
|
||||
countp);
|
||||
AstNode* decp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
new AstVarRef(nodep->fileline(), varp, true), countp);
|
||||
AstNode* decp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* zerosp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);
|
||||
AstNode* condp = new AstGtS(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, false),
|
||||
zerosp);
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp,
|
||||
decp);
|
||||
AstNode* condp
|
||||
= new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false), zerosp);
|
||||
AstNode* bodysp = nodep->bodysp();
|
||||
if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
AstNode* newp = new AstWhile(nodep->fileline(), condp, bodysp, decp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
|
|
@ -178,67 +176,73 @@ private:
|
|||
AstFunc* funcp = VN_CAST(m_ftaskp, Func);
|
||||
if (!m_ftaskp) {
|
||||
nodep->v3error("Return isn't underneath a task or function");
|
||||
} else if (funcp && !nodep->lhsp()) {
|
||||
} else if (funcp && !nodep->lhsp()) {
|
||||
nodep->v3error("Return underneath a function should have return value");
|
||||
} else if (!funcp && nodep->lhsp()) {
|
||||
} else if (!funcp && nodep->lhsp()) {
|
||||
nodep->v3error("Return underneath a task shouldn't have return value");
|
||||
} else {
|
||||
if (funcp && nodep->lhsp()) {
|
||||
// Set output variable to return value
|
||||
nodep->addPrev(new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
VN_CAST(funcp->fvarp(), Var), true),
|
||||
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||
nodep->addPrev(new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), VN_CAST(funcp->fvarp(), Var), true),
|
||||
nodep->lhsp()->unlinkFrBackWithNext()));
|
||||
}
|
||||
// Jump to the end of the function call
|
||||
AstJumpLabel* labelp = findAddLabel(m_ftaskp, false);
|
||||
nodep->addPrev(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstBreak* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!m_loopp) { nodep->v3error("break isn't underneath a loop"); }
|
||||
else {
|
||||
if (!m_loopp) {
|
||||
nodep->v3error("break isn't underneath a loop");
|
||||
} else {
|
||||
// Jump to the end of the loop
|
||||
AstJumpLabel* labelp = findAddLabel(m_loopp, false);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstContinue* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!m_loopp) { nodep->v3error("continue isn't underneath a loop"); }
|
||||
else {
|
||||
if (!m_loopp) {
|
||||
nodep->v3error("continue isn't underneath a loop");
|
||||
} else {
|
||||
// Jump to the end of this iteration
|
||||
// If a "for" loop then need to still do the post-loop increment
|
||||
AstJumpLabel* labelp = findAddLabel(m_loopp, true);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstDisable* nodep) VL_OVERRIDE {
|
||||
UINFO(8," DISABLE "<<nodep<<endl);
|
||||
UINFO(8, " DISABLE " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
AstBegin* beginp = NULL;
|
||||
for (BeginStack::reverse_iterator it = m_beginStack.rbegin();
|
||||
it != m_beginStack.rend(); ++it) {
|
||||
UINFO(9," UNDERBLK "<<*it<<endl);
|
||||
for (BeginStack::reverse_iterator it = m_beginStack.rbegin(); it != m_beginStack.rend();
|
||||
++it) {
|
||||
UINFO(9, " UNDERBLK " << *it << endl);
|
||||
if ((*it)->name() == nodep->name()) {
|
||||
beginp = *it;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labeli: "); }
|
||||
if (!beginp) { nodep->v3error("disable isn't underneath a begin with name: "
|
||||
<<nodep->prettyNameQ()); }
|
||||
else {
|
||||
// if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labeli: "); }
|
||||
if (!beginp) {
|
||||
nodep->v3error("disable isn't underneath a begin with name: " << nodep->prettyNameQ());
|
||||
} else {
|
||||
// Jump to the end of the named begin
|
||||
AstJumpLabel* labelp = findAddLabel(beginp, false);
|
||||
nodep->addNextHere(new AstJumpGo(nodep->fileline(), labelp));
|
||||
}
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
//if (debug()>=9) { UINFO(0,"\n"); beginp->dumpTree(cout, " labelo: "); }
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
// if (debug() >= 9) { UINFO(0, "\n"); beginp->dumpTree(cout, " labelo: "); }
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (m_loopInc && nodep->varp()) nodep->varp()->usedLoopIdx(true);
|
||||
|
|
@ -263,9 +267,7 @@ public:
|
|||
// Task class functions
|
||||
|
||||
void V3LinkJump::linkJump(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
LinkJumpVisitor bvisitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ LinkJumpVisitor bvisitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("link", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
// Levelizing class functions
|
||||
|
||||
struct CmpLevel {
|
||||
inline bool operator() (const AstNodeModule* lhsp, const AstNodeModule* rhsp) const {
|
||||
inline bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const {
|
||||
return lhsp->level() < rhsp->level();
|
||||
}
|
||||
};
|
||||
|
|
@ -43,7 +43,7 @@ struct CmpLevel {
|
|||
void V3LinkLevel::modSortByLevel() {
|
||||
// Sort modules by levels, root down to lowest children
|
||||
// Calculate levels again in case we added modules
|
||||
UINFO(2,"modSortByLevel()\n");
|
||||
UINFO(2, "modSortByLevel()\n");
|
||||
|
||||
// level() was computed for us in V3LinkCells
|
||||
|
||||
|
|
@ -60,20 +60,21 @@ void V3LinkLevel::modSortByLevel() {
|
|||
AstNode* secp = tops[1]; // Complain about second one, as first often intended
|
||||
if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) {
|
||||
secp->v3warn(MULTITOP, "Multiple top level modules\n"
|
||||
<<secp->warnMore()
|
||||
<<"... Suggest see manual; fix the duplicates, or use --top-module to select top."
|
||||
<<V3Error::warnContextNone());
|
||||
<< secp->warnMore()
|
||||
<< "... Suggest see manual; fix the duplicates, or use "
|
||||
"--top-module to select top."
|
||||
<< V3Error::warnContextNone());
|
||||
for (ModVec::const_iterator it = tops.begin(); it != tops.end(); ++it) {
|
||||
AstNode* alsop = *it;
|
||||
std::cout<<secp->warnMore()<<"... Top module "<<alsop->prettyNameQ()<<endl
|
||||
<<alsop->warnContextSecondary();
|
||||
std::cout << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl
|
||||
<< alsop->warnContextSecondary();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reorder the netlist's modules to have modules in level sorted order
|
||||
stable_sort(mods.begin(), mods.end(), CmpLevel()); // Sort the vector
|
||||
UINFO(9,"modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
|
||||
UINFO(9, "modSortByLevel() sorted\n"); // Comment required for gcc4.6.3 / bug666
|
||||
for (ModVec::const_iterator it = mods.begin(); it != mods.end(); ++it) {
|
||||
AstNodeModule* nodep = *it;
|
||||
nodep->clearIter(); // Because we didn't iterate to find the node
|
||||
|
|
@ -85,7 +86,7 @@ void V3LinkLevel::modSortByLevel() {
|
|||
AstNodeModule* nodep = *it;
|
||||
v3Global.rootp()->addModulep(nodep);
|
||||
}
|
||||
UINFO(9,"modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666
|
||||
UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666
|
||||
V3Global::dumpCheckGlobalTree("cells", false, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
|
|
@ -93,11 +94,11 @@ void V3LinkLevel::modSortByLevel() {
|
|||
// Wrapping
|
||||
|
||||
void V3LinkLevel::wrapTop(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
// We do ONLY the top module
|
||||
AstNodeModule* oldmodp = rootp->modulesp();
|
||||
if (!oldmodp) { // Later V3LinkDot will warn
|
||||
UINFO(1,"No module found to wrap\n");
|
||||
UINFO(1, "No module found to wrap\n");
|
||||
return;
|
||||
}
|
||||
AstNodeModule* newmodp = new AstModule(oldmodp->fileline(), string("TOP"));
|
||||
|
|
@ -115,15 +116,13 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) {
|
|||
|
||||
// Instantiate all packages under the top wrapper
|
||||
// This way all later SCOPE based optimizations can ignore packages
|
||||
for (AstNodeModule* modp = rootp->modulesp(); modp; modp=VN_CAST(modp->nextp(), NodeModule)) {
|
||||
for (AstNodeModule* modp = rootp->modulesp(); modp;
|
||||
modp = VN_CAST(modp->nextp(), NodeModule)) {
|
||||
if (VN_IS(modp, Package)) {
|
||||
AstCell* cellp = new AstCell(modp->fileline(),
|
||||
modp->fileline(),
|
||||
AstCell* cellp = new AstCell(modp->fileline(), modp->fileline(),
|
||||
// Could add __03a__03a="::" to prevent conflict
|
||||
// with module names/"v"
|
||||
modp->name(),
|
||||
modp->name(),
|
||||
NULL, NULL, NULL);
|
||||
modp->name(), modp->name(), NULL, NULL, NULL);
|
||||
cellp->modp(modp);
|
||||
newmodp->addStmtp(cellp);
|
||||
}
|
||||
|
|
@ -142,13 +141,12 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|||
NameSet dupNames;
|
||||
// For all modules, skipping over new top
|
||||
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
|
||||
oldmodp && oldmodp->level() <= 2;
|
||||
oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
|
||||
oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
|
||||
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
|
||||
if (oldvarp->isIO()) {
|
||||
if (ioNames.find(oldvarp->name()) != ioNames.end()) {
|
||||
//UINFO(8, "Multitop dup I/O found: "<<oldvarp<<endl);
|
||||
// UINFO(8, "Multitop dup I/O found: " << oldvarp << endl);
|
||||
dupNames.insert(oldvarp->name());
|
||||
} else {
|
||||
ioNames.insert(oldvarp->name());
|
||||
|
|
@ -160,29 +158,26 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|||
|
||||
// For all modules, skipping over new top
|
||||
for (AstNodeModule* oldmodp = VN_CAST(rootp->modulesp()->nextp(), NodeModule);
|
||||
oldmodp && oldmodp->level() <= 2;
|
||||
oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
|
||||
oldmodp && oldmodp->level() <= 2; oldmodp = VN_CAST(oldmodp->nextp(), NodeModule)) {
|
||||
if (VN_IS(oldmodp, Package)) continue;
|
||||
// Add instance
|
||||
UINFO(5,"LOOP "<<oldmodp<<endl);
|
||||
AstCell* cellp = new AstCell(newmodp->fileline(),
|
||||
newmodp->fileline(),
|
||||
(!v3Global.opt.l2Name().empty()
|
||||
? v3Global.opt.l2Name() : oldmodp->name()),
|
||||
oldmodp->name(),
|
||||
NULL, NULL, NULL);
|
||||
UINFO(5, "LOOP " << oldmodp << endl);
|
||||
AstCell* cellp = new AstCell(
|
||||
newmodp->fileline(), newmodp->fileline(),
|
||||
(!v3Global.opt.l2Name().empty() ? v3Global.opt.l2Name() : oldmodp->name()),
|
||||
oldmodp->name(), NULL, NULL, NULL);
|
||||
cellp->modp(oldmodp);
|
||||
newmodp->addStmtp(cellp);
|
||||
|
||||
// Add pins
|
||||
for (AstNode* subnodep=oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
for (AstNode* subnodep = oldmodp->stmtsp(); subnodep; subnodep = subnodep->nextp()) {
|
||||
if (AstVar* oldvarp = VN_CAST(subnodep, Var)) {
|
||||
UINFO(8,"VARWRAP "<<oldvarp<<endl);
|
||||
UINFO(8, "VARWRAP " << oldvarp << endl);
|
||||
if (oldvarp->isIO()) {
|
||||
string name = oldvarp->name();
|
||||
if (dupNames.find(name) != dupNames.end()) {
|
||||
// __02E=. while __DOT__ looks nicer but will break V3LinkDot
|
||||
name = oldmodp->name()+"__02E"+name;
|
||||
name = oldmodp->name() + "__02E" + name;
|
||||
}
|
||||
|
||||
AstVar* varp = oldvarp->cloneTree(false);
|
||||
|
|
@ -196,7 +191,7 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|||
}
|
||||
if (varp->direction().isRefOrConstRef()) {
|
||||
varp->v3error("Unsupported: ref/const ref as primary input/output: "
|
||||
<<varp->prettyNameQ());
|
||||
<< varp->prettyNameQ());
|
||||
}
|
||||
if (varp->isIO() && v3Global.opt.systemC()) {
|
||||
varp->sc(true);
|
||||
|
|
@ -205,9 +200,9 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) {
|
|||
varp->trace(false);
|
||||
}
|
||||
|
||||
AstPin* pinp = new AstPin(oldvarp->fileline(), 0, varp->name(),
|
||||
new AstVarRef(varp->fileline(),
|
||||
varp, oldvarp->isWritable()));
|
||||
AstPin* pinp
|
||||
= new AstPin(oldvarp->fileline(), 0, varp->name(),
|
||||
new AstVarRef(varp->fileline(), varp, oldvarp->isWritable()));
|
||||
// Skip length and width comp; we know it's a direct assignment
|
||||
pinp->modVarp(oldvarp);
|
||||
cellp->addPinsp(pinp);
|
||||
|
|
|
|||
|
|
@ -41,24 +41,24 @@ private:
|
|||
// Cleared on netlist
|
||||
// AstNode::user1() -> bool. True if processed
|
||||
// AstNode::user2() -> bool. True if fileline recomputed
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// TYPES
|
||||
typedef std::map<std::pair<void*,string>,AstTypedef*> ImplTypedefMap;
|
||||
typedef std::map<std::pair<void*, string>, AstTypedef*> ImplTypedefMap;
|
||||
typedef std::set<FileLine*> FileLineSet;
|
||||
|
||||
// STATE
|
||||
AstVar* m_varp; // Variable we're under
|
||||
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
|
||||
FileLineSet m_filelines; // Filelines that have been seen
|
||||
bool m_inAlways; // Inside an always
|
||||
bool m_inGenerate; // Inside a generate
|
||||
bool m_needStart; // Need start marker on lower AstParse
|
||||
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current task
|
||||
AstNodeDType* m_dtypep; // Current data type
|
||||
AstVar* m_varp; // Variable we're under
|
||||
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
|
||||
FileLineSet m_filelines; // Filelines that have been seen
|
||||
bool m_inAlways; // Inside an always
|
||||
bool m_inGenerate; // Inside a generate
|
||||
bool m_needStart; // Need start marker on lower AstParse
|
||||
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current task
|
||||
AstNodeDType* m_dtypep; // Current data type
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -84,8 +84,11 @@ private:
|
|||
// Create a name for the enum, to aid debug and tracing
|
||||
// This name is not guaranteed to be globally unique (due to later parameterization)
|
||||
string above;
|
||||
if (m_modp && VN_IS(m_modp, Package)) above = m_modp->name()+"::";
|
||||
else if (m_modp) above = m_modp->name()+".";
|
||||
if (m_modp && VN_IS(m_modp, Package)) {
|
||||
above = m_modp->name() + "::";
|
||||
} else if (m_modp) {
|
||||
above = m_modp->name() + ".";
|
||||
}
|
||||
return above + typedefp->name();
|
||||
}
|
||||
return "";
|
||||
|
|
@ -115,16 +118,14 @@ private:
|
|||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
if (!nodep->user1SetOnce()) { // Process only once.
|
||||
cleanFileline(nodep);
|
||||
UINFO(5," "<<nodep<<endl);
|
||||
UINFO(5, " " << nodep << endl);
|
||||
AstNodeModule* upperValueModp = m_valueModp;
|
||||
m_valueModp = NULL;
|
||||
iterateChildren(nodep);
|
||||
m_valueModp = upperValueModp;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE {
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { visitIterateNodeDType(nodep); }
|
||||
virtual void visit(AstEnumDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->name() == "") {
|
||||
nodep->name(nameFromTypedef(nodep)); // Might still remain ""
|
||||
|
|
@ -142,7 +143,7 @@ private:
|
|||
cleanFileline(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (nodep->rangep()) {
|
||||
if (!VN_IS(nodep->rangep()->msbp(), Const)
|
||||
if (!VN_IS(nodep->rangep()->msbp(), Const) //
|
||||
|| !VN_IS(nodep->rangep()->lsbp(), Const)) {
|
||||
nodep->v3error("Enum ranges must be integral, per spec");
|
||||
}
|
||||
|
|
@ -151,18 +152,19 @@ private:
|
|||
int increment = (msb > lsb) ? -1 : 1;
|
||||
int offset_from_init = 0;
|
||||
AstNode* addp = NULL;
|
||||
for (int i=msb; i!=(lsb+increment); i+=increment, offset_from_init++) {
|
||||
for (int i = msb; i != (lsb + increment); i += increment, offset_from_init++) {
|
||||
string name = nodep->name() + cvtToStr(i);
|
||||
AstNode* valuep = NULL;
|
||||
if (nodep->valuep()) valuep = new AstAdd
|
||||
(nodep->fileline(),
|
||||
nodep->valuep()->cloneTree(true),
|
||||
new AstConst(nodep->fileline(),
|
||||
AstConst::Unsized32(),
|
||||
offset_from_init));
|
||||
if (nodep->valuep())
|
||||
valuep = new AstAdd(
|
||||
nodep->fileline(), nodep->valuep()->cloneTree(true),
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), offset_from_init));
|
||||
AstNode* newp = new AstEnumItem(nodep->fileline(), name, NULL, valuep);
|
||||
if (addp) addp = addp->addNextNull(newp);
|
||||
else addp = newp;
|
||||
if (addp) {
|
||||
addp = addp->addNextNull(newp);
|
||||
} else {
|
||||
addp = newp;
|
||||
}
|
||||
}
|
||||
nodep->replaceWith(addp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -175,15 +177,15 @@ private:
|
|||
// It's a parameter type. Use a different node type for this.
|
||||
AstNodeDType* dtypep = VN_CAST(nodep->valuep(), NodeDType);
|
||||
if (!dtypep) {
|
||||
nodep->v3error("Parameter type's initial value isn't a type: "
|
||||
<<nodep->prettyNameQ());
|
||||
nodep->v3error(
|
||||
"Parameter type's initial value isn't a type: " << nodep->prettyNameQ());
|
||||
nodep->unlinkFrBack();
|
||||
} else {
|
||||
dtypep->unlinkFrBack();
|
||||
AstNode* newp = new AstParamTypeDType(nodep->fileline(),
|
||||
nodep->varType(), nodep->name(),
|
||||
VFlagChildDType(), dtypep);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
AstNode* newp = new AstParamTypeDType(nodep->fileline(), nodep->varType(),
|
||||
nodep->name(), VFlagChildDType(), dtypep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -195,18 +197,15 @@ private:
|
|||
switch (nodep->varType()) {
|
||||
case AstVarType::VAR:
|
||||
case AstVarType::PORT:
|
||||
case AstVarType::WIRE:
|
||||
nodep->sigUserRWPublic(true);
|
||||
break;
|
||||
case AstVarType::WIRE: nodep->sigUserRWPublic(true); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
// We used modTrace before leveling, and we may now
|
||||
// want to turn it off now that we know the levelizations
|
||||
if (v3Global.opt.traceDepth()
|
||||
&& m_modp
|
||||
&& (m_modp->level()-1) > v3Global.opt.traceDepth()) {
|
||||
if (v3Global.opt.traceDepth() && m_modp
|
||||
&& (m_modp->level() - 1) > v3Global.opt.traceDepth()) {
|
||||
m_modp->modTrace(false);
|
||||
nodep->trace(false);
|
||||
}
|
||||
|
|
@ -237,15 +236,13 @@ private:
|
|||
// Making an AstAssign (vs AstAssignW) to a wire is an error, suppress it
|
||||
FileLine* newfl = new FileLine(fl);
|
||||
newfl->warnOff(V3ErrorCode::PROCASSWIRE, true);
|
||||
nodep->addNextHere
|
||||
(new AstInitial
|
||||
(newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
|
||||
nodep->valuep()->unlinkFrBack())));
|
||||
nodep->addNextHere(new AstInitial(
|
||||
newfl, new AstAssign(newfl, new AstVarRef(newfl, nodep->name(), true),
|
||||
nodep->valuep()->unlinkFrBack())));
|
||||
} // 3. Under blocks, it's an initial value to be under an assign
|
||||
else {
|
||||
nodep->addNextHere
|
||||
(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
|
||||
nodep->valuep()->unlinkFrBack()));
|
||||
nodep->addNextHere(new AstAssign(fl, new AstVarRef(fl, nodep->name(), true),
|
||||
nodep->valuep()->unlinkFrBack()));
|
||||
}
|
||||
}
|
||||
if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
|
||||
|
|
@ -253,7 +250,9 @@ private:
|
|||
// haven't made additional ones for interconnect yet, so assert is simple
|
||||
// What breaks later is we don't have a Scope/Cell representing
|
||||
// the interface to attach to
|
||||
if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module");
|
||||
if (m_modp->level() <= 2) {
|
||||
nodep->v3error("Unsupported: Interfaced port on top level module");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -265,69 +264,61 @@ private:
|
|||
UASSERT_OBJ(typep, nodep, "Attribute not attached to typedef");
|
||||
typep->attrPublic(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
nodep->v3warn(DEPRECATED, "sc_clock is deprecated and will be removed");
|
||||
m_varp->attrScClocked(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_CLOCK_ENABLE) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrClockEn(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true); m_varp->sigModPublic(true);
|
||||
m_varp->sigUserRWPublic(true);
|
||||
m_varp->sigModPublic(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RD) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRdPublic(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_PUBLIC_FLAT_RW) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->sigUserRWPublic(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrIsolateAssign(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_SFORMAT) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrSFormat(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_SPLIT_VAR) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
if (!VN_IS(m_modp, Module)) {
|
||||
m_varp->v3warn(SPLITVAR, m_varp->prettyNameQ() << " has split_var metacomment, "
|
||||
"but will not be split because it is not declared in a module.");
|
||||
m_varp->v3warn(
|
||||
SPLITVAR,
|
||||
m_varp->prettyNameQ()
|
||||
<< " has split_var metacomment, "
|
||||
"but will not be split because it is not declared in a module.");
|
||||
} else {
|
||||
m_varp->attrSplitVar(true);
|
||||
}
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_SC_BV) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrScBv(true);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_CLOCKER) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrClocker(VVarAttrClocker::CLOCKER_YES);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) {
|
||||
} else if (nodep->attrType() == AstAttrType::VAR_NO_CLOCKER) {
|
||||
UASSERT_OBJ(m_varp, nodep, "Attribute not attached to variable");
|
||||
m_varp->attrClocker(VVarAttrClocker::CLOCKER_NO);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
|
|
@ -351,36 +342,38 @@ private:
|
|||
|
||||
virtual void visit(AstDefImplicitDType* nodep) VL_OVERRIDE {
|
||||
cleanFileline(nodep);
|
||||
UINFO(8," DEFIMPLICIT "<<nodep<<endl);
|
||||
UINFO(8, " DEFIMPLICIT " << nodep << endl);
|
||||
// Must remember what names we've already created, and combine duplicates
|
||||
// so that for "var enum {...} a,b" a & b will share a common typedef
|
||||
// Unique name space under each containerp() so that an addition of
|
||||
// a new type won't change every verilated module.
|
||||
AstTypedef* defp = NULL;
|
||||
ImplTypedefMap::iterator it = m_implTypedef.find(make_pair(nodep->containerp(), nodep->name()));
|
||||
ImplTypedefMap::iterator it
|
||||
= m_implTypedef.find(make_pair(nodep->containerp(), nodep->name()));
|
||||
if (it != m_implTypedef.end()) {
|
||||
defp = it->second;
|
||||
} else {
|
||||
// Definition must be inserted right after the variable (etc) that needed it
|
||||
// AstVar, AstTypedef, AstNodeFTask are common containers
|
||||
AstNode* backp = nodep->backp();
|
||||
for (; backp; backp=backp->backp()) {
|
||||
if (VN_IS(backp, Var)) break;
|
||||
else if (VN_IS(backp, Typedef)) break;
|
||||
else if (VN_IS(backp, NodeFTask)) break;
|
||||
for (; backp; backp = backp->backp()) {
|
||||
if (VN_IS(backp, Var) || VN_IS(backp, Typedef) || VN_IS(backp, NodeFTask)) break;
|
||||
}
|
||||
UASSERT_OBJ(backp, nodep,
|
||||
"Implicit enum/struct type created under unexpected node type");
|
||||
AstNodeDType* dtypep = nodep->childDTypep(); dtypep->unlinkFrBack();
|
||||
if (VN_IS(backp, Typedef)) { // A typedef doesn't need us to make yet another level of typedefing
|
||||
AstNodeDType* dtypep = nodep->childDTypep();
|
||||
dtypep->unlinkFrBack();
|
||||
if (VN_IS(backp, Typedef)) {
|
||||
// A typedef doesn't need us to make yet another level of typedefing
|
||||
// For typedefs just remove the AstRefDType level of abstraction
|
||||
nodep->replaceWith(dtypep);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
return;
|
||||
} else {
|
||||
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL,
|
||||
VFlagChildDType(), dtypep);
|
||||
m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp));
|
||||
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, VFlagChildDType(),
|
||||
dtypep);
|
||||
m_implTypedef.insert(
|
||||
make_pair(make_pair(nodep->containerp(), defp->name()), defp));
|
||||
backp->addNextHere(defp);
|
||||
}
|
||||
}
|
||||
|
|
@ -391,19 +384,22 @@ private:
|
|||
virtual void visit(AstForeach* nodep) VL_OVERRIDE {
|
||||
// FOREACH(array,loopvars,body)
|
||||
// -> BEGIN(declare vars, loopa=lowest; WHILE(loopa<=highest, ... body))
|
||||
//nodep->dumpTree(cout, "-foreach-old:");
|
||||
// nodep->dumpTree(cout, "-foreach-old:");
|
||||
AstNode* newp = nodep->bodysp()->unlinkFrBackWithNext();
|
||||
AstNode* arrayp = nodep->arrayp();
|
||||
int dimension = 1;
|
||||
// Must do innermost (last) variable first
|
||||
AstNode* firstVarsp = nodep->varsp()->unlinkFrBackWithNext();
|
||||
AstNode* lastVarsp = firstVarsp;
|
||||
while (lastVarsp->nextp()) { lastVarsp = lastVarsp->nextp(); dimension++; }
|
||||
for (AstNode* varsp = lastVarsp; varsp; varsp=varsp->backp()) {
|
||||
UINFO(9,"foreachVar "<<varsp<<endl);
|
||||
while (lastVarsp->nextp()) {
|
||||
lastVarsp = lastVarsp->nextp();
|
||||
dimension++;
|
||||
}
|
||||
for (AstNode* varsp = lastVarsp; varsp; varsp = varsp->backp()) {
|
||||
UINFO(9, "foreachVar " << varsp << endl);
|
||||
FileLine* fl = varsp->fileline();
|
||||
AstNode* varp = new AstVar(fl, AstVarType::BLOCKTEMP,
|
||||
varsp->name(), nodep->findSigned32DType());
|
||||
AstNode* varp
|
||||
= new AstVar(fl, AstVarType::BLOCKTEMP, varsp->name(), nodep->findSigned32DType());
|
||||
// These will be the left and right dimensions and size of the array:
|
||||
AstNode* leftp = new AstAttrOf(fl, AstAttrType::DIM_LEFT,
|
||||
new AstVarRef(fl, arrayp->name(), false),
|
||||
|
|
@ -416,19 +412,16 @@ private:
|
|||
new AstConst(fl, dimension));
|
||||
AstNode* stmtsp = varp;
|
||||
// Assign left-dimension into the loop var:
|
||||
stmtsp->addNext(new AstAssign
|
||||
(fl, new AstVarRef(fl, varp->name(), true), leftp));
|
||||
stmtsp->addNext(new AstAssign(fl, new AstVarRef(fl, varp->name(), true), leftp));
|
||||
// This will turn into a constant bool for static arrays
|
||||
AstNode* notemptyp = new AstGt(fl, sizep, new AstConst(fl, 0));
|
||||
// This will turn into a bool constant, indicating whether
|
||||
// we count the loop variable up or down:
|
||||
AstNode* countupp = new AstLte(fl, leftp->cloneTree(true),
|
||||
rightp->cloneTree(true));
|
||||
AstNode* countupp = new AstLte(fl, leftp->cloneTree(true), rightp->cloneTree(true));
|
||||
AstNode* comparep = new AstCond(
|
||||
fl, countupp->cloneTree(true),
|
||||
// Left increments up to right
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), false),
|
||||
rightp->cloneTree(true)),
|
||||
new AstLte(fl, new AstVarRef(fl, varp->name(), false), rightp->cloneTree(true)),
|
||||
// Left decrements down to right
|
||||
new AstGte(fl, new AstVarRef(fl, varp->name(), false), rightp));
|
||||
// This will reduce to comparep for static arrays
|
||||
|
|
@ -436,16 +429,15 @@ private:
|
|||
AstNode* incp = new AstAssign(
|
||||
fl, new AstVarRef(fl, varp->name(), true),
|
||||
new AstAdd(fl, new AstVarRef(fl, varp->name(), false),
|
||||
new AstCond(fl, countupp,
|
||||
new AstConst(fl, 1),
|
||||
new AstConst(fl, -1))));
|
||||
new AstCond(fl, countupp, new AstConst(fl, 1), new AstConst(fl, -1))));
|
||||
stmtsp->addNext(new AstWhile(fl, condp, newp, incp));
|
||||
newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true);
|
||||
dimension--;
|
||||
}
|
||||
//newp->dumpTree(cout, "-foreach-new:");
|
||||
// newp->dumpTree(cout, "-foreach-new:");
|
||||
VL_DO_DANGLING(firstVarsp->deleteTree(), firstVarsp);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
|
|
@ -472,23 +464,15 @@ private:
|
|||
iterateChildren(nodep);
|
||||
m_valueModp = upperValueModp;
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
m_inAlways = true;
|
||||
visitIterateNoValueMod(nodep);
|
||||
m_inAlways = false;
|
||||
}
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
|
||||
visitIterateNoValueMod(nodep);
|
||||
}
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
|
||||
virtual void visit(AstRestrict* nodep) VL_OVERRIDE { visitIterateNoValueMod(nodep); }
|
||||
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
V3Config::applyCoverageBlock(m_modp, nodep);
|
||||
|
|
@ -502,10 +486,8 @@ private:
|
|||
// It's not FOR(BEGIN(...)) but we earlier changed it to BEGIN(FOR(...))
|
||||
if (nodep->genforp() && nodep->name() == "") {
|
||||
nodep->name("genblk");
|
||||
}
|
||||
else if (nodep->generate() && nodep->name() == ""
|
||||
&& (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf))
|
||||
&& !nestedIf) {
|
||||
} else if (nodep->generate() && nodep->name() == ""
|
||||
&& (VN_IS(backp, CaseItem) || VN_IS(backp, GenIf)) && !nestedIf) {
|
||||
nodep->name("genblk");
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -542,9 +524,7 @@ public:
|
|||
// Link class functions
|
||||
|
||||
void V3LinkParse::linkParse(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
LinkParseVisitor visitor(rootp);
|
||||
} // Destruct before checking
|
||||
UINFO(4, __FUNCTION__ << ": " << endl);
|
||||
{ LinkParseVisitor visitor(rootp); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("linkparse", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ private:
|
|||
// TODO: could move to V3LinkParse to get them out of the way of elaboration
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Module: Create sim table for entire module and iterate
|
||||
UINFO(8,"MODULE "<<nodep<<endl);
|
||||
UINFO(8, "MODULE " << nodep << endl);
|
||||
if (nodep->dead()) return;
|
||||
AstNodeModule* origModp = m_modp;
|
||||
int origSenitemCvtNum = m_senitemCvtNum;
|
||||
|
|
@ -110,9 +110,7 @@ private:
|
|||
|
||||
virtual void visit(AstNodeVarRef* nodep) VL_OVERRIDE {
|
||||
// VarRef: Resolve its reference
|
||||
if (nodep->varp()) {
|
||||
nodep->varp()->usedParam(true);
|
||||
}
|
||||
if (nodep->varp()) { nodep->varp()->usedParam(true); }
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
|
@ -123,9 +121,7 @@ private:
|
|||
m_ftaskp = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_ftaskp = NULL;
|
||||
if (nodep->dpiExport()) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
if (nodep->dpiExport()) { nodep->scopeNamep(new AstScopeName(nodep->fileline())); }
|
||||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -142,34 +138,29 @@ private:
|
|||
// This is a bit unfortunate as we haven't done width resolution
|
||||
// and any width errors will look a bit odd, but it works.
|
||||
AstNode* sensp = nodep->sensp();
|
||||
if (sensp
|
||||
&& !VN_IS(sensp, NodeVarRef)
|
||||
&& !VN_IS(sensp, Const)) {
|
||||
if (sensp && !VN_IS(sensp, NodeVarRef) && !VN_IS(sensp, Const)) {
|
||||
// Make a new temp wire
|
||||
string newvarname = "__Vsenitemexpr"+cvtToStr(++m_senitemCvtNum);
|
||||
AstVar* newvarp = new AstVar(sensp->fileline(),
|
||||
AstVarType::MODULETEMP, newvarname,
|
||||
string newvarname = "__Vsenitemexpr" + cvtToStr(++m_senitemCvtNum);
|
||||
AstVar* newvarp = new AstVar(sensp->fileline(), AstVarType::MODULETEMP, newvarname,
|
||||
VFlagLogicPacked(), 1);
|
||||
// We can't just add under the module, because we may be
|
||||
// inside a generate, begin, etc.
|
||||
// We know a SenItem should be under a SenTree/Always etc,
|
||||
// we we'll just hunt upwards
|
||||
AstNode* addwherep = nodep; // Add to this element's next
|
||||
while (VN_IS(addwherep, SenItem)
|
||||
|| VN_IS(addwherep, SenTree)) {
|
||||
while (VN_IS(addwherep, SenItem) || VN_IS(addwherep, SenTree)) {
|
||||
addwherep = addwherep->backp();
|
||||
}
|
||||
if (!VN_IS(addwherep, Always)) { // Assertion perhaps?
|
||||
sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under some complicated block");
|
||||
sensp->v3error("Unsupported: Non-single-bit pos/negedge clock statement under "
|
||||
"some complicated block");
|
||||
addwherep = m_modp;
|
||||
}
|
||||
addwherep->addNext(newvarp);
|
||||
|
||||
sensp->replaceWith(new AstVarRef(sensp->fileline(), newvarp, false));
|
||||
AstAssignW* assignp = new AstAssignW
|
||||
(sensp->fileline(),
|
||||
new AstVarRef(sensp->fileline(), newvarp, true),
|
||||
sensp);
|
||||
AstAssignW* assignp = new AstAssignW(
|
||||
sensp->fileline(), new AstVarRef(sensp->fileline(), newvarp, true), sensp);
|
||||
addwherep->addNext(assignp);
|
||||
}
|
||||
} else { // Old V1995 sensitivity list; we'll probably mostly ignore
|
||||
|
|
@ -178,18 +169,21 @@ private:
|
|||
did = 0;
|
||||
if (AstNodeSel* selp = VN_CAST(nodep->sensp(), NodeSel)) {
|
||||
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
selp->replaceWith(fromp);
|
||||
VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
did = 1;
|
||||
}
|
||||
// NodeSel doesn't include AstSel....
|
||||
if (AstSel* selp = VN_CAST(nodep->sensp(), Sel)) {
|
||||
AstNode* fromp = selp->fromp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
selp->replaceWith(fromp);
|
||||
VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
did = 1;
|
||||
}
|
||||
if (AstNodePreSel* selp = VN_CAST(nodep->sensp(), NodePreSel)) {
|
||||
AstNode* fromp = selp->lhsp()->unlinkFrBack();
|
||||
selp->replaceWith(fromp); VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
selp->replaceWith(fromp);
|
||||
VL_DO_DANGLING(selp->deleteTree(), selp);
|
||||
did = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -213,10 +207,12 @@ private:
|
|||
// So we replicate it in another node
|
||||
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep);
|
||||
if (AstNodeVarRef* varrefp = VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone
|
||||
if (AstNodeVarRef* varrefp
|
||||
= VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||
varrefp->cloneTree(false)));
|
||||
} else if (AstUnlinkedRef* uvxrp = VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone
|
||||
} else if (AstUnlinkedRef* uvxrp
|
||||
= VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone
|
||||
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
|
||||
uvxrp->cloneTree(false)));
|
||||
} else if (AstMemberSel* fromp = VN_CAST(basefromp, MemberSel)) {
|
||||
|
|
@ -227,11 +223,11 @@ private:
|
|||
fromp->cloneTree(false)));
|
||||
} else if (VN_IS(basefromp, Replicate)) {
|
||||
// From {...}[...] syntax in IEEE 2017
|
||||
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
|
||||
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
|
||||
nodep->v3error("Unsupported: Select of concatenation");
|
||||
nodep = NULL;
|
||||
} else {
|
||||
if (basefromp) { UINFO(1," Related node: "<<basefromp<<endl); }
|
||||
if (basefromp) { UINFO(1, " Related node: " << basefromp << endl); }
|
||||
nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from");
|
||||
}
|
||||
}
|
||||
|
|
@ -253,20 +249,21 @@ private:
|
|||
if (nodep->pragType() == AstPragmaType::PUBLIC_MODULE) {
|
||||
UASSERT_OBJ(m_modp, nodep, "PUBLIC_MODULE not under a module");
|
||||
m_modp->modPublic(true);
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (nodep->pragType() == AstPragmaType::PUBLIC_TASK) {
|
||||
UASSERT_OBJ(m_ftaskp, nodep, "PUBLIC_TASK not under a task");
|
||||
m_ftaskp->taskPublic(true);
|
||||
m_modp->modPublic(true); // Need to get to the task...
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
|
||||
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize better without
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (nodep->pragType() == AstPragmaType::COVERAGE_BLOCK_OFF) {
|
||||
if (!v3Global.opt.coverageLine()) { // No need for block statements; may optimize
|
||||
// better without
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
|
@ -278,10 +275,10 @@ private:
|
|||
string fmt;
|
||||
for (string::const_iterator it = format.begin(); it != format.end(); ++it) {
|
||||
char ch = *it;
|
||||
if (!inPct && ch=='%') {
|
||||
if (!inPct && ch == '%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
} else if (inPct && (isdigit(ch) || ch=='.' || ch=='-')) {
|
||||
} else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
|
|
@ -290,15 +287,21 @@ private:
|
|||
case '%': // %% - just output a %
|
||||
break;
|
||||
case 'm': // %m - auto insert "name"
|
||||
if (isScan) { nodep->v3error("Unsupported: %m in $fscanf"); fmt = ""; }
|
||||
if (isScan) {
|
||||
nodep->v3error("Unsupported: %m in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
break;
|
||||
case 'l': // %l - auto insert "library"
|
||||
if (isScan) { nodep->v3error("Unsupported: %l in $fscanf"); fmt = ""; }
|
||||
if (isScan) {
|
||||
nodep->v3error("Unsupported: %l in $fscanf");
|
||||
fmt = "";
|
||||
}
|
||||
if (m_modp) fmt = VString::quotePercent(m_modp->prettyName());
|
||||
break;
|
||||
default: // Most operators, just move to next argument
|
||||
if (!V3Number::displayedFmtLegal(ch)) {
|
||||
nodep->v3error("Unknown $display-like format code: '%"<<ch<<"'");
|
||||
nodep->v3error("Unknown $display-like format code: '%" << ch << "'");
|
||||
} else {
|
||||
if (!argp) {
|
||||
nodep->v3error("Missing arguments for $display-like format");
|
||||
|
|
@ -322,10 +325,10 @@ private:
|
|||
skipCount--;
|
||||
continue;
|
||||
}
|
||||
AstConst *constp = VN_CAST(argp, Const);
|
||||
AstConst* constp = VN_CAST(argp, Const);
|
||||
bool isFromString = (constp) ? constp->num().isFromString() : false;
|
||||
if (isFromString) {
|
||||
int numchars = argp->dtypep()->width()/8;
|
||||
int numchars = argp->dtypep()->width() / 8;
|
||||
string str(numchars, ' ');
|
||||
// now scan for % operators
|
||||
bool inpercent = false;
|
||||
|
|
@ -338,23 +341,18 @@ private:
|
|||
} else if (inpercent) {
|
||||
inpercent = 0;
|
||||
switch (c) {
|
||||
case '0': case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
case '.':
|
||||
inpercent = true;
|
||||
break;
|
||||
case '%':
|
||||
break;
|
||||
case '0' ... '9':
|
||||
case '.': inpercent = true; break;
|
||||
case '%': break;
|
||||
default:
|
||||
if (V3Number::displayedFmtLegal(c)) {
|
||||
skipCount++;
|
||||
}
|
||||
if (V3Number::displayedFmtLegal(c)) { skipCount++; }
|
||||
}
|
||||
}
|
||||
}
|
||||
newFormat.append(str);
|
||||
AstNode *nextp = argp->nextp();
|
||||
argp->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(argp), argp);
|
||||
AstNode* nextp = argp->nextp();
|
||||
argp->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(argp), argp);
|
||||
argp = nextp;
|
||||
} else {
|
||||
newFormat.append("%?"); // V3Width to figure it out
|
||||
|
|
@ -366,7 +364,9 @@ private:
|
|||
}
|
||||
|
||||
void expectDescriptor(AstNode* nodep, AstNodeVarRef* filep) {
|
||||
if (!filep) nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
|
||||
if (!filep) {
|
||||
nodep->v3error("Unsupported: $fopen/$fclose/$f* descriptor must be a simple variable");
|
||||
}
|
||||
if (filep && filep->varp()) filep->varp()->attrFileDescr(true);
|
||||
}
|
||||
|
||||
|
|
@ -402,7 +402,8 @@ private:
|
|||
iterateChildren(nodep);
|
||||
// Cleanup old-school displays without format arguments
|
||||
if (!nodep->hasFormat()) {
|
||||
UASSERT_OBJ(nodep->text()=="", nodep, "Non-format $sformatf should have \"\" format");
|
||||
UASSERT_OBJ(nodep->text() == "", nodep,
|
||||
"Non-format $sformatf should have \"\" format");
|
||||
if (VN_IS(nodep->exprsp(), Const)
|
||||
&& VN_CAST(nodep->exprsp(), Const)->num().isFromString()) {
|
||||
AstConst* fmtp = VN_CAST(nodep->exprsp()->unlinkFrBack(), Const);
|
||||
|
|
@ -421,14 +422,14 @@ private:
|
|||
}
|
||||
|
||||
virtual void visit(AstUdpTable* nodep) VL_OVERRIDE {
|
||||
UINFO(5,"UDPTABLE "<<nodep<<endl);
|
||||
UINFO(5, "UDPTABLE " << nodep << endl);
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
// We don't warn until V3Inst, so that UDPs that are in libraries and
|
||||
// never used won't result in any warnings.
|
||||
} else {
|
||||
// Massive hack, just tie off all outputs so our analysis can proceed
|
||||
AstVar* varoutp = NULL;
|
||||
for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
for (AstNode* stmtp = m_modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->isReadOnly()) {
|
||||
} else if (varp->isWritable()) {
|
||||
|
|
@ -438,16 +439,15 @@ private:
|
|||
varoutp = varp;
|
||||
// Tie off
|
||||
m_modp->addStmtp(new AstAssignW(
|
||||
varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true),
|
||||
new AstConst(varp->fileline(),
|
||||
AstConst::LogicFalse())));
|
||||
varp->fileline(), new AstVarRef(varp->fileline(), varp, true),
|
||||
new AstConst(varp->fileline(), AstConst::LogicFalse())));
|
||||
} else {
|
||||
varp->v3error("Only inputs and outputs are allowed in udp modules");
|
||||
}
|
||||
}
|
||||
}
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -531,7 +531,7 @@ public:
|
|||
// Link class functions
|
||||
|
||||
void V3LinkResolve::linkResolve(AstNetlist* rootp) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
UINFO(4, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
LinkResolveVisitor visitor(rootp);
|
||||
LinkBotupVisitor visitorb(rootp);
|
||||
|
|
|
|||
1165
src/V3Number.cpp
1165
src/V3Number.cpp
File diff suppressed because it is too large
Load Diff
402
src/V3Number.h
402
src/V3Number.h
|
|
@ -39,22 +39,27 @@ class AstNode;
|
|||
|
||||
class V3Number {
|
||||
// Large 4-state number handling
|
||||
int m_width; // Width as specified/calculated.
|
||||
bool m_sized:1; // True if the user specified the width, else we track it.
|
||||
bool m_signed:1; // True if signed value
|
||||
bool m_double:1; // True if double real value
|
||||
bool m_isString:1; // True if string
|
||||
bool m_fromString:1; // True if from string literal
|
||||
bool m_autoExtend:1; // True if SystemVerilog extend-to-any-width
|
||||
FileLine* m_fileline;
|
||||
AstNode* m_nodep; // Parent node
|
||||
std::vector<uint32_t> m_value; // The Value, with bit 0 being in bit 0 of this vector (unless X/Z)
|
||||
int m_width; // Width as specified/calculated.
|
||||
bool m_sized : 1; // True if the user specified the width, else we track it.
|
||||
bool m_signed : 1; // True if signed value
|
||||
bool m_double : 1; // True if double real value
|
||||
bool m_isString : 1; // True if string
|
||||
bool m_fromString : 1; // True if from string literal
|
||||
bool m_autoExtend : 1; // True if SystemVerilog extend-to-any-width
|
||||
FileLine* m_fileline;
|
||||
AstNode* m_nodep; // Parent node
|
||||
std::vector<uint32_t> m_value; // Value, with bit 0 in bit 0 of this vector (unless X/Z)
|
||||
std::vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
|
||||
string m_stringVal; // If isString, the value of the string
|
||||
string m_stringVal; // If isString, the value of the string
|
||||
// METHODS
|
||||
V3Number& setSingleBits(char value);
|
||||
V3Number& setString(const string& str) { m_isString = true; m_stringVal = str; return *this; }
|
||||
V3Number& setString(const string& str) {
|
||||
m_isString = true;
|
||||
m_stringVal = str;
|
||||
return *this;
|
||||
}
|
||||
void opCleanThis(bool warnOnTruncation = false);
|
||||
|
||||
public:
|
||||
void nodep(AstNode* nodep) { setNames(nodep); }
|
||||
FileLine* fileline() const { return m_fileline; }
|
||||
|
|
@ -64,79 +69,87 @@ public:
|
|||
V3Number& setLongS(vlsint32_t value);
|
||||
V3Number& setDouble(double value);
|
||||
void setBit(int bit, char value) { // Note must be pre-zeroed!
|
||||
if (bit>=m_width) return;
|
||||
uint32_t mask = (1UL<<(bit&31));
|
||||
if (value=='0' || value==0) {
|
||||
m_value [bit/32] &= ~mask;
|
||||
m_valueX[bit/32] &= ~mask;
|
||||
} else if (value=='1'|| value==1) {
|
||||
m_value [bit/32] |= mask;
|
||||
m_valueX[bit/32] &= ~mask;
|
||||
} else if (value=='z'|| value==2) {
|
||||
m_value [bit/32] &= ~mask;
|
||||
m_valueX[bit/32] |= mask;
|
||||
if (bit >= m_width) return;
|
||||
uint32_t mask = (1UL << (bit & 31));
|
||||
if (value == '0' || value == 0) {
|
||||
m_value[bit / 32] &= ~mask;
|
||||
m_valueX[bit / 32] &= ~mask;
|
||||
} else if (value == '1' || value == 1) {
|
||||
m_value[bit / 32] |= mask;
|
||||
m_valueX[bit / 32] &= ~mask;
|
||||
} else if (value == 'z' || value == 2) {
|
||||
m_value[bit / 32] &= ~mask;
|
||||
m_valueX[bit / 32] |= mask;
|
||||
} else { // X
|
||||
m_value [bit/32] |= mask;
|
||||
m_valueX[bit/32] |= mask;
|
||||
m_value[bit / 32] |= mask;
|
||||
m_valueX[bit / 32] |= mask;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
char bitIs(int bit) const {
|
||||
if (bit>=m_width || bit<0) {
|
||||
if (bit >= m_width || bit < 0) {
|
||||
// We never sign extend
|
||||
return '0';
|
||||
}
|
||||
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
|
||||
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
|
||||
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
|
||||
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
|
||||
}
|
||||
char bitIsExtend(int bit, int lbits) const {
|
||||
// lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less
|
||||
if (bit<0) return '0';
|
||||
UASSERT(lbits<=m_width, "Extend of wrong size");
|
||||
if (bit>=lbits) {
|
||||
bit = lbits ? lbits-1 : 0;
|
||||
if (bit < 0) return '0';
|
||||
UASSERT(lbits <= m_width, "Extend of wrong size");
|
||||
if (bit >= lbits) {
|
||||
bit = lbits ? lbits - 1 : 0;
|
||||
// We do sign extend
|
||||
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
|
||||
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] );
|
||||
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
|
||||
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
|
||||
}
|
||||
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
|
||||
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
|
||||
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
|
||||
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
|
||||
}
|
||||
bool bitIs0(int bit) const {
|
||||
if (bit<0) return false;
|
||||
if (bit>=m_width) return !bitIsXZ(m_width-1);
|
||||
return ( (m_value[bit/32] & (1UL<<(bit&31)))==0
|
||||
&& !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return !bitIsXZ(m_width - 1);
|
||||
return ((m_value[bit / 32] & (1UL << (bit & 31))) == 0
|
||||
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
bool bitIs1(int bit) const {
|
||||
if (bit<0) return false;
|
||||
if (bit>=m_width) return false;
|
||||
return ( (m_value[bit/32] & (1UL<<(bit&31)))
|
||||
&& !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return false;
|
||||
return ((m_value[bit / 32] & (1UL << (bit & 31)))
|
||||
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
bool bitIs1Extend(int bit) const {
|
||||
if (bit<0) return false;
|
||||
if (bit>=m_width) return bitIs1Extend(m_width-1);
|
||||
return ( (m_value[bit/32] & (1UL<<(bit&31)))
|
||||
&& !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return bitIs1Extend(m_width - 1);
|
||||
return ((m_value[bit / 32] & (1UL << (bit & 31)))
|
||||
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
bool bitIsX(int bit) const {
|
||||
if (bit<0) return false;
|
||||
if (bit>=m_width) return bitIsZ(m_width-1);
|
||||
return ( (m_value[bit/32] & (1UL<<(bit&31)))
|
||||
&& (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return bitIsZ(m_width - 1);
|
||||
return ((m_value[bit / 32] & (1UL << (bit & 31)))
|
||||
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
bool bitIsXZ(int bit) const {
|
||||
if (bit<0) return false;
|
||||
if (bit>=m_width) return bitIsXZ(m_width-1);
|
||||
return ( (m_valueX[bit/32] & (1UL<<(bit&31))));
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return bitIsXZ(m_width - 1);
|
||||
return ((m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
bool bitIsZ(int bit) const {
|
||||
if (bit<0) return false;
|
||||
if (bit>=m_width) return bitIsZ(m_width-1);
|
||||
return ( (~m_value[bit/32] & (1UL<<(bit&31)))
|
||||
&& (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||||
if (bit < 0) return false;
|
||||
if (bit >= m_width) return bitIsZ(m_width - 1);
|
||||
return ((~m_value[bit / 32] & (1UL << (bit & 31)))
|
||||
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
|
||||
}
|
||||
uint32_t bitsValue(int lsb, int nbits) const {
|
||||
uint32_t v = 0;
|
||||
for (int bitn=0; bitn<nbits; bitn++) { v |= (bitIs1(lsb+bitn)<<bitn); }
|
||||
for (int bitn = 0; bitn < nbits; bitn++) { v |= (bitIs1(lsb + bitn) << bitn); }
|
||||
return v;
|
||||
}
|
||||
|
||||
int words() const { return ((width()+31)/32); }
|
||||
int words() const { return ((width() + 31) / 32); }
|
||||
uint32_t hiWordMask() const { return VL_MASK_I(width()); }
|
||||
|
||||
V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
|
||||
|
|
@ -145,8 +158,10 @@ public:
|
|||
// CONSTRUCTORS
|
||||
explicit V3Number(AstNode* nodep) { init(nodep, 1); }
|
||||
V3Number(AstNode* nodep, int width) { init(nodep, width); } // 0=unsized
|
||||
V3Number(AstNode* nodep, int width, uint32_t value, bool sized=true) {
|
||||
init(nodep, width, sized); m_value[0] = value; opCleanThis();
|
||||
V3Number(AstNode* nodep, int width, uint32_t value, bool sized = true) {
|
||||
init(nodep, width, sized);
|
||||
m_value[0] = value;
|
||||
opCleanThis();
|
||||
}
|
||||
// Create from a verilog 32'hxxxx number.
|
||||
V3Number(AstNode* nodep, const char* sourcep) { V3NumberCreate(nodep, sourcep, NULL); }
|
||||
|
|
@ -155,7 +170,10 @@ public:
|
|||
class VerilogStringLiteral {}; // For creator type-overload selection
|
||||
V3Number(VerilogStringLiteral, AstNode* nodep, const string& str);
|
||||
class String {};
|
||||
V3Number(String, AstNode* nodep, const string& value) { init(nodep, 0); setString(value); }
|
||||
V3Number(String, AstNode* nodep, const string& value) {
|
||||
init(nodep, 0);
|
||||
setString(value);
|
||||
}
|
||||
explicit V3Number(const V3Number* nump, int width = 1) {
|
||||
init(NULL, width);
|
||||
m_fileline = nump->fileline();
|
||||
|
|
@ -169,7 +187,7 @@ public:
|
|||
|
||||
private:
|
||||
void V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl);
|
||||
void init(AstNode* nodep, int swidth, bool sized=true) {
|
||||
void init(AstNode* nodep, int swidth, bool sized = true) {
|
||||
setNames(nodep);
|
||||
m_signed = false;
|
||||
m_double = false;
|
||||
|
|
@ -177,23 +195,27 @@ private:
|
|||
m_autoExtend = false;
|
||||
m_fromString = false;
|
||||
width(swidth, sized);
|
||||
for (int i=0; i<words(); i++) m_value[i] = m_valueX[i] = 0;
|
||||
for (int i = 0; i < words(); i++) m_value[i] = m_valueX[i] = 0;
|
||||
}
|
||||
void setNames(AstNode* nodep);
|
||||
static string displayPad(size_t fmtsize, char pad, bool left, const string& in);
|
||||
string displayed(FileLine* fl, const string& vformat) const;
|
||||
string displayed(const string& vformat) const {
|
||||
return displayed(m_fileline, vformat);
|
||||
}
|
||||
string displayed(const string& vformat) const { return displayed(m_fileline, vformat); }
|
||||
|
||||
public:
|
||||
void v3errorEnd(std::ostringstream& sstr) const;
|
||||
void width(int width, bool sized=true) {
|
||||
void width(int width, bool sized = true) {
|
||||
// Set width. Only set m_width here, as we need to tweak vector size
|
||||
if (width) { m_sized = sized; m_width = width; }
|
||||
else { m_sized = false; m_width = 1; }
|
||||
if (VL_UNLIKELY(m_value.size() < (unsigned)(words()+1))) {
|
||||
m_value.resize(words()+1);
|
||||
m_valueX.resize(words()+1);
|
||||
if (width) {
|
||||
m_sized = sized;
|
||||
m_width = width;
|
||||
} else {
|
||||
m_sized = false;
|
||||
m_width = 1;
|
||||
}
|
||||
if (VL_UNLIKELY(m_value.size() < (unsigned)(words() + 1))) {
|
||||
m_value.resize(words() + 1);
|
||||
m_valueX.resize(words() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +228,7 @@ public:
|
|||
V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc
|
||||
|
||||
// ACCESSORS
|
||||
string ascii(bool prefixed=true, bool cleanVerilog=false) const;
|
||||
string ascii(bool prefixed = true, bool cleanVerilog = false) const;
|
||||
string displayed(AstNode* nodep, const string& vformat) const;
|
||||
static bool displayedFmtLegal(char format); // Is this a valid format letter?
|
||||
int width() const { return m_width; }
|
||||
|
|
@ -214,26 +236,35 @@ public:
|
|||
bool sized() const { return m_sized; }
|
||||
bool autoExtend() const { return m_autoExtend; }
|
||||
bool isFromString() const { return m_fromString; }
|
||||
bool isSigned() const { return m_signed; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
|
||||
bool isDouble() const { return m_double; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
|
||||
void isDouble(bool flag) { m_double = flag; } // Only if have 64 bit value loaded, and want to indicate it's real
|
||||
// Only correct for parsing of numbers from strings, otherwise not used
|
||||
// (use AstConst::isSigned())
|
||||
bool isSigned() const { return m_signed; }
|
||||
// Only correct for parsing of numbers from strings, otherwise not used
|
||||
// (use AstConst::isSigned())
|
||||
bool isDouble() const { return m_double; }
|
||||
// Only if have 64 bit value loaded, and want to indicate it's real
|
||||
void isDouble(bool flag) { m_double = flag; }
|
||||
bool isString() const { return m_isString; }
|
||||
void isString(bool flag) { m_isString = flag; }
|
||||
bool isNegative() const { return bitIs1(width()-1); }
|
||||
void isString(bool flag) { m_isString = flag; }
|
||||
bool isNegative() const { return bitIs1(width() - 1); }
|
||||
bool isFourState() const;
|
||||
bool hasZ() const {
|
||||
for(int i=0;i<words();i++) { if ((~m_value[i]) & m_valueX[i]) return true; }
|
||||
for (int i = 0; i < words(); i++) {
|
||||
if ((~m_value[i]) & m_valueX[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool isAllZ() const {
|
||||
for(int i=0;i<width();i++) { if (!bitIsZ(i)) return false; }
|
||||
for (int i = 0; i < width(); i++) {
|
||||
if (!bitIsZ(i)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool isEqZero() const;
|
||||
bool isNeqZero() const;
|
||||
bool isBitsZero(int msb, int lsb) const;
|
||||
bool isEqOne() const;
|
||||
bool isEqAllOnes(int optwidth=0) const;
|
||||
bool isEqAllOnes(int optwidth = 0) const;
|
||||
bool isCaseEq(const V3Number& rhs) const; // operator==
|
||||
bool isLt(const V3Number& rhs) const; // operator<
|
||||
bool isLtXZ(const V3Number& rhs) const; // operator< with XZ compared
|
||||
|
|
@ -252,7 +283,8 @@ public:
|
|||
uint32_t edataWord(int eword) const;
|
||||
uint8_t dataByte(int byte) const;
|
||||
uint32_t countOnes() const;
|
||||
uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
|
||||
uint32_t
|
||||
mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
|
||||
|
||||
// Operators
|
||||
bool operator<(const V3Number& rhs) const { return isLtXZ(rhs); }
|
||||
|
|
@ -261,127 +293,131 @@ public:
|
|||
static int log2b(uint32_t num);
|
||||
|
||||
typedef V3Number& (*UniopFuncp)(V3Number&);
|
||||
typedef V3Number& (*BiopFuncp) (V3Number&, V3Number&);
|
||||
typedef V3Number& (*BiopFuncp)(V3Number&, V3Number&);
|
||||
|
||||
// MATH
|
||||
// "this" is the output, as we need the output width before some computations
|
||||
V3Number& isTrue (const V3Number& lhs);
|
||||
V3Number& isTrue(const V3Number& lhs);
|
||||
V3Number& opBitsNonX(const V3Number& lhs); // 0/1->1, X/Z->0
|
||||
V3Number& opBitsOne (const V3Number& lhs); // 1->1, 0/X/Z->0
|
||||
V3Number& opBitsXZ (const V3Number& lhs); // 0/1->0, X/Z->1
|
||||
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
|
||||
V3Number& opBitsOne(const V3Number& lhs); // 1->1, 0/X/Z->0
|
||||
V3Number& opBitsXZ(const V3Number& lhs); // 0/1->0, X/Z->1
|
||||
V3Number& opBitsZ(const V3Number& lhs); // Z->1, 0/1/X->0
|
||||
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
|
||||
//
|
||||
V3Number& opAssign (const V3Number& lhs);
|
||||
V3Number& opAssign(const V3Number& lhs);
|
||||
V3Number& opAssignNonXZ(const V3Number& lhs, bool ignoreXZ = true);
|
||||
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
|
||||
V3Number& opExtendS(const V3Number& lhs, uint32_t lbits); // Sign extension
|
||||
V3Number& opExtendXZ(const V3Number& lhs, uint32_t lbits); // X/Z extension
|
||||
V3Number& opRedOr (const V3Number& lhs);
|
||||
V3Number& opRedAnd (const V3Number& lhs);
|
||||
V3Number& opRedXor (const V3Number& lhs);
|
||||
V3Number& opRedXnor (const V3Number& lhs);
|
||||
V3Number& opRedOr(const V3Number& lhs);
|
||||
V3Number& opRedAnd(const V3Number& lhs);
|
||||
V3Number& opRedXor(const V3Number& lhs);
|
||||
V3Number& opRedXnor(const V3Number& lhs);
|
||||
V3Number& opCountOnes(const V3Number& lhs);
|
||||
V3Number& opIsUnknown(const V3Number& lhs);
|
||||
V3Number& opOneHot (const V3Number& lhs);
|
||||
V3Number& opOneHot0 (const V3Number& lhs);
|
||||
V3Number& opCLog2 (const V3Number& lhs);
|
||||
V3Number& opClean (const V3Number& lhs, uint32_t bits);
|
||||
V3Number& opConcat (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLenN (const V3Number& lhs);
|
||||
V3Number& opRepl (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRepl (const V3Number& lhs, uint32_t rhsval);
|
||||
V3Number& opStreamL (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb);
|
||||
V3Number& opSel (const V3Number& lhs, uint32_t msbval, uint32_t lsbval);
|
||||
V3Number& opSelInto (const V3Number& lhs, const V3Number& lsb, int width);
|
||||
V3Number& opSelInto (const V3Number& lhs, int lsbval, int width);
|
||||
V3Number& opOneHot(const V3Number& lhs);
|
||||
V3Number& opOneHot0(const V3Number& lhs);
|
||||
V3Number& opCLog2(const V3Number& lhs);
|
||||
V3Number& opClean(const V3Number& lhs, uint32_t bits);
|
||||
V3Number& opConcat(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLenN(const V3Number& lhs);
|
||||
V3Number& opRepl(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRepl(const V3Number& lhs, uint32_t rhsval);
|
||||
V3Number& opStreamL(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb);
|
||||
V3Number& opSel(const V3Number& lhs, uint32_t msbval, uint32_t lsbval);
|
||||
V3Number& opSelInto(const V3Number& lhs, const V3Number& lsb, int width);
|
||||
V3Number& opSelInto(const V3Number& lhs, int lsbval, int width);
|
||||
V3Number& opToLowerN(const V3Number& lhs);
|
||||
V3Number& opToUpperN(const V3Number& lhs);
|
||||
V3Number& opCond (const V3Number& lhs, const V3Number& if1s, const V3Number& if0s);
|
||||
V3Number& opCaseEq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opBufIf1 (const V3Number& ens, const V3Number& if1s);
|
||||
V3Number& opCond(const V3Number& lhs, const V3Number& if1s, const V3Number& if0s);
|
||||
V3Number& opCaseEq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opCaseNeq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildEq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opWildNeq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opBufIf1(const V3Number& ens, const V3Number& if1s);
|
||||
// "standard" math
|
||||
V3Number& opNot (const V3Number& lhs);
|
||||
V3Number& opLogNot (const V3Number& lhs);
|
||||
V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogEq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogIf (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opAbsS (const V3Number& lhs);
|
||||
V3Number& opNegate (const V3Number& lhs);
|
||||
V3Number& opAdd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSub (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMul (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMulS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opDiv (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opDivS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opModDiv (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opModDivS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opPow (const V3Number& lhs, const V3Number& rhs, bool lsign=false, bool rsign=false);
|
||||
V3Number& opPowSU (const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs
|
||||
V3Number& opPowSS (const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs
|
||||
V3Number& opPowUS (const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs
|
||||
V3Number& opAnd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNot(const V3Number& lhs);
|
||||
V3Number& opLogNot(const V3Number& lhs);
|
||||
V3Number& opLogAnd(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogOr(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogEq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogIf(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opAbsS(const V3Number& lhs);
|
||||
V3Number& opNegate(const V3Number& lhs);
|
||||
V3Number& opAdd(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSub(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMul(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMulS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opDiv(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opDivS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opModDiv(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opModDivS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opPow(const V3Number& lhs, const V3Number& rhs, bool lsign = false,
|
||||
bool rsign = false);
|
||||
V3Number& opPowSU(const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs
|
||||
V3Number& opPowSS(const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs
|
||||
V3Number& opPowUS(const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs
|
||||
V3Number& opAnd(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opChangeXor(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXor (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXnor (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opOr (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRotR (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRotL (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry
|
||||
V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXor(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opXnor(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opOr(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRotR(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opRotL(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftR(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opShiftRS(const V3Number& lhs, const V3Number& rhs, // Arithmetic w/carry
|
||||
uint32_t lbits);
|
||||
V3Number& opShiftL(const V3Number& lhs, const V3Number& rhs);
|
||||
// Comparisons
|
||||
V3Number& opEq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeq (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGt (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opGte (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opLt (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opLte (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opEq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeq(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGt(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opGte(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opLt(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
V3Number& opLte(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteS(const V3Number& lhs, const V3Number& rhs); // Signed
|
||||
|
||||
// "D" - double (aka real) math
|
||||
V3Number& opIToRD (const V3Number& lhs);
|
||||
V3Number& opRToIS (const V3Number& lhs);
|
||||
V3Number& opIToRD(const V3Number& lhs);
|
||||
V3Number& opRToIS(const V3Number& lhs);
|
||||
V3Number& opRToIRoundS(const V3Number& lhs);
|
||||
V3Number& opRealToBits(const V3Number& lhs);
|
||||
V3Number& opBitsToRealD(const V3Number& lhs);
|
||||
V3Number& opNegateD (const V3Number& lhs);
|
||||
V3Number& opAddD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSubD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMulD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opDivD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opPowD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNegateD(const V3Number& lhs);
|
||||
V3Number& opAddD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSubD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opMulD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opDivD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opPowD(const V3Number& lhs, const V3Number& rhs);
|
||||
// Comparisons
|
||||
V3Number& opEqD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeqD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteD (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opEqD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeqD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtD(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteD(const V3Number& lhs, const V3Number& rhs);
|
||||
|
||||
// "N" - string operations
|
||||
V3Number& opAtoN (const V3Number& lhs, int base);
|
||||
V3Number& opPutcN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
|
||||
V3Number& opGetcN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSubstrN (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
|
||||
V3Number& opCompareNN(const V3Number& lhs,const V3Number& rhs, bool ignoreCase);
|
||||
V3Number& opConcatN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opReplN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opReplN (const V3Number& lhs, uint32_t rhsval);
|
||||
V3Number& opEqN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeqN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteN (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opAtoN(const V3Number& lhs, int base);
|
||||
V3Number& opPutcN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
|
||||
V3Number& opGetcN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSubstrN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
|
||||
V3Number& opCompareNN(const V3Number& lhs, const V3Number& rhs, bool ignoreCase);
|
||||
V3Number& opConcatN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opReplN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opReplN(const V3Number& lhs, uint32_t rhsval);
|
||||
V3Number& opEqN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opNeqN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGtN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opGteN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLtN(const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLteN(const V3Number& lhs, const V3Number& rhs);
|
||||
};
|
||||
inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) { return os<<rhs.ascii(); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) {
|
||||
return os << rhs.ascii();
|
||||
}
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
776
src/V3Order.cpp
776
src/V3Order.cpp
File diff suppressed because it is too large
Load Diff
365
src/V3Param.cpp
365
src/V3Param.cpp
|
|
@ -74,41 +74,42 @@ private:
|
|||
// // (0=not processed, 1=iterated, but no number,
|
||||
// // 65+ parameter numbered)
|
||||
// AstCell::user5p() // string* Generate portion of hierarchical name
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser5InUse m_inuser5;
|
||||
// User1/2/3 used by constant function simulations
|
||||
|
||||
// TYPES
|
||||
typedef std::deque<std::pair<AstIfaceRefDType*,AstIfaceRefDType*> > IfaceRefRefs; // Note may have duplicate entries
|
||||
// Note may have duplicate entries
|
||||
typedef std::deque<std::pair<AstIfaceRefDType*, AstIfaceRefDType*> > IfaceRefRefs;
|
||||
|
||||
// STATE
|
||||
typedef std::map<AstNode*,AstNode*> CloneMap;
|
||||
typedef std::map<AstNode*, AstNode*> CloneMap;
|
||||
struct ModInfo {
|
||||
AstNodeModule* m_modp; // Module with specified name
|
||||
CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
|
||||
AstNodeModule* m_modp; // Module with specified name
|
||||
CloneMap m_cloneMap; // Map of old-varp -> new cloned varp
|
||||
explicit ModInfo(AstNodeModule* modp) { m_modp = modp; }
|
||||
};
|
||||
typedef std::map<string,ModInfo> ModNameMap;
|
||||
ModNameMap m_modNameMap; // Hash of created module flavors by name
|
||||
typedef std::map<string, ModInfo> ModNameMap;
|
||||
ModNameMap m_modNameMap; // Hash of created module flavors by name
|
||||
|
||||
typedef std::map<string,string> LongMap;
|
||||
LongMap m_longMap; // Hash of very long names to unique identity number
|
||||
int m_longId;
|
||||
typedef std::map<string, string> LongMap;
|
||||
LongMap m_longMap; // Hash of very long names to unique identity number
|
||||
int m_longId;
|
||||
|
||||
typedef std::pair<int,string> ValueMapValue;
|
||||
typedef std::map<V3Hash,ValueMapValue> ValueMap;
|
||||
ValueMap m_valueMap; // Hash of node hash to (param value, name)
|
||||
int m_nextValue; // Next value to use in m_valueMap
|
||||
typedef std::pair<int, string> ValueMapValue;
|
||||
typedef std::map<V3Hash, ValueMapValue> ValueMap;
|
||||
ValueMap m_valueMap; // Hash of node hash to (param value, name)
|
||||
int m_nextValue; // Next value to use in m_valueMap
|
||||
|
||||
typedef std::multimap<int,AstNodeModule*> LevelModMap;
|
||||
LevelModMap m_todoModps; // Modules left to process
|
||||
typedef std::multimap<int, AstNodeModule*> LevelModMap;
|
||||
LevelModMap m_todoModps; // Modules left to process
|
||||
|
||||
typedef std::deque<AstCell*> CellList;
|
||||
CellList m_cellps; // Cells left to process (in this module)
|
||||
CellList m_cellps; // Cells left to process (in this module)
|
||||
|
||||
AstNodeModule* m_modp; // Current module being processed
|
||||
|
||||
string m_unlinkedTxt; // Text for AstUnlinkedRef
|
||||
string m_unlinkedTxt; // Text for AstUnlinkedRef
|
||||
|
||||
UnrollStateful m_unroller; // Loop unroller
|
||||
|
||||
|
|
@ -118,32 +119,32 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void makeSmallNames(AstNodeModule* modp) {
|
||||
std::vector<int> usedLetter; usedLetter.resize(256);
|
||||
std::vector<int> usedLetter;
|
||||
usedLetter.resize(256);
|
||||
// Pass 1, assign first letter to each gparam's name
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->isGParam()||varp->isIfaceRef()) {
|
||||
if (varp->isGParam() || varp->isIfaceRef()) {
|
||||
char ch = varp->name()[0];
|
||||
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
|
||||
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
|
||||
ch = toupper(ch);
|
||||
if (ch < 'A' || ch > 'Z') ch = 'Z';
|
||||
varp->user4(usedLetter[static_cast<int>(ch)] * 256 + ch);
|
||||
usedLetter[static_cast<int>(ch)]++;
|
||||
}
|
||||
} else if (AstParamTypeDType* typep = VN_CAST(stmtp, ParamTypeDType)) {
|
||||
char ch = 'T';
|
||||
typep->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
|
||||
typep->user4(usedLetter[static_cast<int>(ch)] * 256 + ch);
|
||||
usedLetter[static_cast<int>(ch)]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
string paramSmallName(AstNodeModule* modp, AstNode* varp) {
|
||||
if (varp->user4()<=1) {
|
||||
makeSmallNames(modp);
|
||||
}
|
||||
int index = varp->user4()/256;
|
||||
char ch = varp->user4()&255;
|
||||
if (varp->user4() <= 1) makeSmallNames(modp);
|
||||
int index = varp->user4() / 256;
|
||||
char ch = varp->user4() & 255;
|
||||
string st = cvtToStr(ch);
|
||||
while (index) {
|
||||
st += cvtToStr(char((index%25)+'A'));
|
||||
st += cvtToStr(char((index % 25) + 'A'));
|
||||
index /= 26;
|
||||
}
|
||||
return st;
|
||||
|
|
@ -155,19 +156,17 @@ private:
|
|||
key = ifrtp->cellp()->modp()->name();
|
||||
} else if (ifrtp->ifacep()) {
|
||||
key = ifrtp->ifacep()->name();
|
||||
} else {
|
||||
} else {
|
||||
nodep->v3fatalSrc("Can't parameterize interface without module name");
|
||||
}
|
||||
} else if (AstBasicDType* bdtp = VN_CAST(nodep, BasicDType)) {
|
||||
if (bdtp->isRanged()) {
|
||||
key += "["+cvtToStr(bdtp->left())+":"+cvtToStr(bdtp->right())+"]";
|
||||
key += "[" + cvtToStr(bdtp->left()) + ":" + cvtToStr(bdtp->right()) + "]";
|
||||
}
|
||||
}
|
||||
V3Hash hash = V3Hashed::uncachedHash(nodep);
|
||||
// Force hash collisions -- for testing only
|
||||
if (VL_UNLIKELY(v3Global.opt.debugCollision())) {
|
||||
hash = V3Hash();
|
||||
}
|
||||
if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash();
|
||||
int num;
|
||||
ValueMap::iterator it = m_valueMap.find(hash);
|
||||
if (it != m_valueMap.end() && it->second.second == key) {
|
||||
|
|
@ -176,20 +175,20 @@ private:
|
|||
num = m_nextValue++;
|
||||
m_valueMap[hash] = make_pair(num, key);
|
||||
}
|
||||
return string("z")+cvtToStr(num);
|
||||
return string("z") + cvtToStr(num);
|
||||
}
|
||||
void collectPins(CloneMap* clonemapp, AstNodeModule* modp) {
|
||||
// Grab all I/O so we can remap our pins later
|
||||
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||
if (AstVar* varp = VN_CAST(stmtp, Var)) {
|
||||
if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
|
||||
// Cloning saved a pointer to the new node for us, so just follow that link.
|
||||
AstVar* oldvarp = varp->clonep();
|
||||
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
|
||||
// UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp
|
||||
// <<" -> 0x"<<(uint32_t)varp<<endl);
|
||||
clonemapp->insert(make_pair(oldvarp, varp));
|
||||
}
|
||||
}
|
||||
else if (AstParamTypeDType* ptp = VN_CAST(stmtp, ParamTypeDType)) {
|
||||
} else if (AstParamTypeDType* ptp = VN_CAST(stmtp, ParamTypeDType)) {
|
||||
if (ptp->isGParam()) {
|
||||
AstParamTypeDType* oldptp = ptp->clonep();
|
||||
clonemapp->insert(make_pair(oldptp, ptp));
|
||||
|
|
@ -198,22 +197,20 @@ private:
|
|||
}
|
||||
}
|
||||
void relinkPins(CloneMap* clonemapp, AstPin* startpinp) {
|
||||
for (AstPin* pinp = startpinp; pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
for (AstPin* pinp = startpinp; pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (pinp->modVarp()) {
|
||||
// Find it in the clone structure
|
||||
//UINFO(8,"Clone find 0x"<<hex<<(uint32_t)pinp->modVarp()<<endl);
|
||||
// UINFO(8,"Clone find 0x"<<hex<<(uint32_t)pinp->modVarp()<<endl);
|
||||
CloneMap::iterator cloneiter = clonemapp->find(pinp->modVarp());
|
||||
UASSERT_OBJ(cloneiter != clonemapp->end(), pinp,
|
||||
"Couldn't find pin in clone list");
|
||||
pinp->modVarp(VN_CAST(cloneiter->second, Var));
|
||||
}
|
||||
else if (pinp->modPTypep()) {
|
||||
} else if (pinp->modPTypep()) {
|
||||
CloneMap::iterator cloneiter = clonemapp->find(pinp->modPTypep());
|
||||
UASSERT_OBJ(cloneiter != clonemapp->end(), pinp,
|
||||
"Couldn't find pin in clone list");
|
||||
pinp->modPTypep(VN_CAST(cloneiter->second, ParamTypeDType));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pinp->v3fatalSrc("Not linked?");
|
||||
}
|
||||
}
|
||||
|
|
@ -227,30 +224,31 @@ private:
|
|||
LevelModMap::iterator itm = m_todoModps.begin();
|
||||
AstNodeModule* nodep = itm->second;
|
||||
m_todoModps.erase(itm);
|
||||
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
|
||||
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it
|
||||
// again
|
||||
m_modp = nodep;
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
if (m_modp->hierName().empty()) m_modp->hierName(m_modp->origName());
|
||||
iterateChildren(nodep);
|
||||
// Note above iterate may add to m_todoModps
|
||||
//
|
||||
// Process interface cells, then non-interface which may ref an interface cell
|
||||
for (int nonIf=0; nonIf<2; ++nonIf) {
|
||||
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
|
||||
for (int nonIf = 0; nonIf < 2; ++nonIf) {
|
||||
for (CellList::iterator it = m_cellps.begin(); it != m_cellps.end(); ++it) {
|
||||
AstCell* cellp = *it;
|
||||
if ((nonIf==0 && VN_IS(cellp->modp(), Iface))
|
||||
|| (nonIf==1 && !VN_IS(cellp->modp(), Iface))) {
|
||||
string fullName (m_modp->hierName());
|
||||
if (string* genHierNamep = (string *) cellp->user5p()) {
|
||||
if ((nonIf == 0 && VN_IS(cellp->modp(), Iface))
|
||||
|| (nonIf == 1 && !VN_IS(cellp->modp(), Iface))) {
|
||||
string fullName(m_modp->hierName());
|
||||
if (string* genHierNamep = (string*)cellp->user5p()) {
|
||||
fullName += *genHierNamep;
|
||||
}
|
||||
visitCell(cellp, fullName);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
|
||||
for (CellList::iterator it = m_cellps.begin(); it != m_cellps.end(); ++it) {
|
||||
AstCell* cellp = *it;
|
||||
if (string* genHierNamep = (string *) cellp->user5p()) {
|
||||
if (string* genHierNamep = (string*)cellp->user5p()) {
|
||||
cellp->user5p(NULL);
|
||||
VL_DO_DANGLING(delete genHierNamep, genHierNamep);
|
||||
}
|
||||
|
|
@ -268,9 +266,10 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
if (nodep->dead()) {
|
||||
UINFO(4," MOD-dead. "<<nodep<<endl); // Marked by LinkDot
|
||||
UINFO(4, " MOD-dead. " << nodep << endl); // Marked by LinkDot
|
||||
} else if (nodep->recursiveClone()) {
|
||||
UINFO(4," MOD-recursive-dead. "<<nodep<<endl); // Fake, made for recursive elimination
|
||||
// Fake, made for recursive elimination
|
||||
UINFO(4, " MOD-recursive-dead. " << nodep << endl);
|
||||
nodep->dead(true); // So Dead checks won't count references to it
|
||||
} else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top
|
||||
|| VN_IS(nodep, Package)) { // Likewise haven't done wrapTopPackages yet
|
||||
|
|
@ -279,9 +278,10 @@ private:
|
|||
m_generateHierName = "";
|
||||
visitModules();
|
||||
} else if (nodep->user5()) {
|
||||
UINFO(4," MOD-done "<<nodep<<endl); // Already did it
|
||||
UINFO(4, " MOD-done " << nodep << endl); // Already did it
|
||||
} else {
|
||||
UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead
|
||||
// Should have been done by now, if not dead
|
||||
UINFO(4, " MOD-dead? " << nodep << endl);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep) VL_OVERRIDE {
|
||||
|
|
@ -298,20 +298,18 @@ private:
|
|||
if (nodep->isParam()) {
|
||||
if (!nodep->valuep()) {
|
||||
nodep->v3error("Parameter without initial value is never given value"
|
||||
<<" (IEEE 1800-2017 6.20.1): "
|
||||
<<nodep->prettyNameQ());
|
||||
<< " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ());
|
||||
} else {
|
||||
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
|
||||
if (!VN_IS(nodep->valuep(), Const)) { // Complex init, like an array
|
||||
// Make a new INITIAL to set the value.
|
||||
// This allows the normal array/struct handling code to properly
|
||||
// initialize the parameter.
|
||||
nodep->addNext(
|
||||
new AstInitial(nodep->fileline(),
|
||||
new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
nodep->valuep()->cloneTree(true))));
|
||||
nodep->addNext(new AstInitial(
|
||||
nodep->fileline(),
|
||||
new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), nodep, true),
|
||||
nodep->valuep()->cloneTree(true))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -325,11 +323,11 @@ private:
|
|||
for (; candp; candp = candp->nextp()) {
|
||||
if (nodep->name() == candp->name()) {
|
||||
if (AstVar* varp = VN_CAST(candp, Var)) {
|
||||
UINFO(9,"Found interface parameter: "<<varp<<endl);
|
||||
UINFO(9, "Found interface parameter: " << varp << endl);
|
||||
nodep->varp(varp);
|
||||
return true;
|
||||
} else if (AstPin* pinp = VN_CAST(candp, Pin)) {
|
||||
UINFO(9,"Found interface parameter: "<<pinp<<endl);
|
||||
UINFO(9, "Found interface parameter: " << pinp << endl);
|
||||
UASSERT_OBJ(pinp->exprp(), pinp, "Interface parameter pin missing expression");
|
||||
VL_DO_DANGLING(nodep->replaceWith(pinp->exprp()->cloneTree(false)), nodep);
|
||||
return true;
|
||||
|
|
@ -345,11 +343,10 @@ private:
|
|||
AstNode* backp = nodep;
|
||||
while ((backp = backp->backp())) {
|
||||
if (VN_IS(backp, NodeModule)) {
|
||||
UINFO(9,"Hit module boundary, done looking for interface"<<endl);
|
||||
UINFO(9, "Hit module boundary, done looking for interface" << endl);
|
||||
break;
|
||||
}
|
||||
if (VN_IS(backp, Var)
|
||||
&& VN_CAST(backp, Var)->isIfaceRef()
|
||||
if (VN_IS(backp, Var) && VN_CAST(backp, Var)->isIfaceRef()
|
||||
&& VN_CAST(backp, Var)->childDTypep()
|
||||
&& (VN_CAST(VN_CAST(backp, Var)->childDTypep(), IfaceRefDType)
|
||||
|| (VN_CAST(VN_CAST(backp, Var)->childDTypep(), UnpackArrayDType)
|
||||
|
|
@ -364,8 +361,8 @@ private:
|
|||
// Interfaces passed in on the port map have ifaces
|
||||
if (AstIface* ifacep = ifacerefp->ifacep()) {
|
||||
if (dotted == backp->name()) {
|
||||
UINFO(9,"Iface matching scope: "<<ifacep<<endl);
|
||||
if (ifaceParamReplace(nodep, ifacep->stmtsp())) {
|
||||
UINFO(9, "Iface matching scope: " << ifacep << endl);
|
||||
if (ifaceParamReplace(nodep, ifacep->stmtsp())) { //
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -373,8 +370,8 @@ private:
|
|||
// Interfaces declared in this module have cells
|
||||
else if (AstCell* cellp = ifacerefp->cellp()) {
|
||||
if (dotted == cellp->name()) {
|
||||
UINFO(9,"Iface matching scope: "<<cellp<<endl);
|
||||
if (ifaceParamReplace(nodep, cellp->paramsp())) {
|
||||
UINFO(9, "Iface matching scope: " << cellp << endl);
|
||||
if (ifaceParamReplace(nodep, cellp->paramsp())) { //
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -414,21 +411,21 @@ private:
|
|||
size_t pos = m_unlinkedTxt.find(replacestr);
|
||||
if (pos == string::npos) {
|
||||
nodep->v3error("Could not find array index in unlinked text: '"
|
||||
<<m_unlinkedTxt<<"' for node: "<<nodep);
|
||||
<< m_unlinkedTxt << "' for node: " << nodep);
|
||||
return;
|
||||
}
|
||||
m_unlinkedTxt.replace(pos, replacestr.length(),
|
||||
nodep->name()+"__BRA__"+index+"__KET__");
|
||||
nodep->name() + "__BRA__" + index + "__KET__");
|
||||
} else {
|
||||
nodep->v3error("Could not expand constant selection inside dotted reference: "
|
||||
<<nodep->selp()->prettyNameQ());
|
||||
<< nodep->selp()->prettyNameQ());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Statements
|
||||
virtual void visit(AstGenIf* nodep) VL_OVERRIDE {
|
||||
UINFO(9," GENIF "<<nodep<<endl);
|
||||
UINFO(9, " GENIF " << nodep << endl);
|
||||
iterateAndNextNull(nodep->condp());
|
||||
// We suppress errors when widthing params since short-circuiting in
|
||||
// the conditional evaluation may mean these error can never occur. We
|
||||
|
|
@ -437,9 +434,7 @@ private:
|
|||
// NOT recurse the body.
|
||||
V3Const::constifyGenerateParamsEdit(nodep->condp()); // condp may change
|
||||
if (const AstConst* constp = VN_CAST(nodep->condp(), Const)) {
|
||||
AstNode* keepp = (constp->isZero()
|
||||
? nodep->elsesp()
|
||||
: nodep->ifsp());
|
||||
AstNode* keepp = (constp->isZero() ? nodep->elsesp() : nodep->ifsp());
|
||||
if (keepp) {
|
||||
keepp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(keepp);
|
||||
|
|
@ -463,8 +458,8 @@ private:
|
|||
UASSERT_OBJ(forp, nodep, "Non-GENFOR under generate-for BEGIN");
|
||||
// We should have a GENFOR under here. We will be replacing the begin,
|
||||
// so process here rather than at the generate to avoid iteration problems
|
||||
UINFO(9," BEGIN "<<nodep<<endl);
|
||||
UINFO(9," GENFOR "<<forp<<endl);
|
||||
UINFO(9, " BEGIN " << nodep << endl);
|
||||
UINFO(9, " GENFOR " << forp << endl);
|
||||
V3Width::widthParamsEdit(forp); // Param typed widthing will NOT recurse the body
|
||||
// Outer wrapper around generate used to hold genvar, and to ensure genvar
|
||||
// doesn't conflict in V3LinkDot resolution with other genvars
|
||||
|
|
@ -494,7 +489,7 @@ private:
|
|||
nodep->v3fatalSrc("GENFOR should have been wrapped in BEGIN");
|
||||
}
|
||||
virtual void visit(AstGenCase* nodep) VL_OVERRIDE {
|
||||
UINFO(9," GENCASE "<<nodep<<endl);
|
||||
UINFO(9, " GENCASE " << nodep << endl);
|
||||
AstNode* keepp = NULL;
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
V3Case::caseLint(nodep);
|
||||
|
|
@ -503,9 +498,9 @@ private:
|
|||
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
|
||||
AstConst* exprp = VN_CAST(nodep->exprp(), Const);
|
||||
// Constify
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* ep = itemp->condsp(); ep; ) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* ep = itemp->condsp(); ep;) {
|
||||
AstNode* nextp = ep->nextp(); // May edit list
|
||||
iterateAndNextNull(ep);
|
||||
VL_DO_DANGLING(V3Const::constifyParamsEdit(ep), ep); // ep may change
|
||||
|
|
@ -513,16 +508,14 @@ private:
|
|||
}
|
||||
}
|
||||
// Item match
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->isDefault()) {
|
||||
for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) {
|
||||
for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
|
||||
if (const AstConst* ccondp = VN_CAST(ep, Const)) {
|
||||
V3Number match (nodep, 1);
|
||||
V3Number match(nodep, 1);
|
||||
match.opEq(ccondp->num(), exprp->num());
|
||||
if (!keepp && match.isNeqZero()) {
|
||||
keepp = itemp->bodysp();
|
||||
}
|
||||
if (!keepp && match.isNeqZero()) keepp = itemp->bodysp();
|
||||
} else {
|
||||
itemp->v3error("Generate Case item does not evaluate to constant");
|
||||
}
|
||||
|
|
@ -530,8 +523,8 @@ private:
|
|||
}
|
||||
}
|
||||
// Else default match
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (itemp->isDefault()) {
|
||||
if (!keepp) keepp = itemp->bodysp();
|
||||
}
|
||||
|
|
@ -540,8 +533,9 @@ private:
|
|||
if (keepp) {
|
||||
keepp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(keepp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
else nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
|
|
@ -569,9 +563,9 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
// We always run this, even if no parameters, as need to look for interfaces,
|
||||
// and remove any recursive references
|
||||
{
|
||||
UINFO(4,"De-parameterize: "<<nodep<<endl);
|
||||
UINFO(4, "De-parameterize: " << nodep << endl);
|
||||
// Create new module name with _'s between the constants
|
||||
if (debug()>=10) nodep->dumpTree(cout, "-cell: ");
|
||||
if (debug() >= 10) nodep->dumpTree(cout, "-cell: ");
|
||||
// Evaluate all module constants
|
||||
V3Const::constifyParamsEdit(nodep);
|
||||
AstNodeModule* srcModp = nodep->modp();
|
||||
|
|
@ -579,18 +573,19 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
|
||||
// Make sure constification worked
|
||||
// Must be a separate loop, as constant conversion may have changed some pointers.
|
||||
//if (debug()) nodep->dumpTree(cout, "-cel2: ");
|
||||
// if (debug()) nodep->dumpTree(cout, "-cel2: ");
|
||||
string longname = srcModp->name();
|
||||
bool any_overrides = false;
|
||||
if (nodep->recursive()) any_overrides = true; // Must always clone __Vrcm (recursive modules)
|
||||
// Must always clone __Vrcm (recursive modules)
|
||||
if (nodep->recursive()) any_overrides = true;
|
||||
longname += "_";
|
||||
if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: ");
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: ");
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (!pinp->exprp()) continue; // No-connect
|
||||
if (AstVar* modvarp = pinp->modVarp()) {
|
||||
if (!modvarp->isGParam()) {
|
||||
pinp->v3error("Attempted parameter setting of non-parameter: Param "
|
||||
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
|
||||
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||
} else if (VN_IS(pinp->exprp(), InitArray)
|
||||
&& VN_IS(modvarp->subDTypep(), UnpackArrayDType)) {
|
||||
// Array assigned to array
|
||||
|
|
@ -601,21 +596,19 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
AstConst* exprp = VN_CAST(pinp->exprp(), Const);
|
||||
AstConst* origp = VN_CAST(modvarp->valuep(), Const);
|
||||
if (!exprp) {
|
||||
//if (debug()) pinp->dumpTree(cout, "error:");
|
||||
// if (debug()) pinp->dumpTree(cout, "error:");
|
||||
pinp->v3error("Can't convert defparam value to constant: Param "
|
||||
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
|
||||
pinp->exprp()->replaceWith(
|
||||
new AstConst(pinp->fileline(),
|
||||
AstConst::WidthedValue(), modvarp->width(), 0));
|
||||
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||
pinp->exprp()->replaceWith(new AstConst(
|
||||
pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0));
|
||||
} else if (origp && exprp->sameTree(origp)) {
|
||||
// Setting parameter to its default value. Just ignore it.
|
||||
// This prevents making additional modules, and makes coverage more
|
||||
// obvious as it won't show up under a unique module page name.
|
||||
} else if (exprp->num().isDouble()
|
||||
|| exprp->num().isString()
|
||||
|| exprp->num().isFourState()) {
|
||||
longname += ("_" + paramSmallName(srcModp, modvarp)
|
||||
+ paramValueNumber(exprp));
|
||||
} else if (exprp->num().isDouble() || exprp->num().isString()
|
||||
|| exprp->num().isFourState()) {
|
||||
longname
|
||||
+= ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp));
|
||||
any_overrides = true;
|
||||
} else {
|
||||
longname += ("_" + paramSmallName(srcModp, modvarp)
|
||||
|
|
@ -628,75 +621,92 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
AstNodeDType* origp = modvarp->subDTypep();
|
||||
if (!exprp) {
|
||||
pinp->v3error("Parameter type pin value isn't a type: Param "
|
||||
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
|
||||
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||
} else if (!origp) {
|
||||
pinp->v3error("Parameter type variable isn't a type: Param "
|
||||
<<modvarp->prettyNameQ());
|
||||
<< modvarp->prettyNameQ());
|
||||
} else {
|
||||
UINFO(9,"Parameter type assignment expr="<<exprp<<" to "<<origp<<endl);
|
||||
UINFO(9,
|
||||
"Parameter type assignment expr=" << exprp << " to " << origp << endl);
|
||||
if (exprp->sameTree(origp)) {
|
||||
// Setting parameter to its default value. Just ignore it.
|
||||
// This prevents making additional modules, and makes coverage more
|
||||
// obvious as it won't show up under a unique module page name.
|
||||
} else {
|
||||
V3Const::constifyParamsEdit(exprp);
|
||||
longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
|
||||
longname
|
||||
+= "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp);
|
||||
any_overrides = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pinp->v3error("Parameter not found in sub-module: Param "
|
||||
<<pinp->prettyNameQ()<<" of "<<nodep->prettyNameQ());
|
||||
<< pinp->prettyNameQ() << " of " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
IfaceRefRefs ifaceRefRefs;
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
AstVar* modvarp = pinp->modVarp();
|
||||
if (modvarp->isIfaceRef()) {
|
||||
AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType);
|
||||
if (!portIrefp && VN_IS(modvarp->subDTypep(), UnpackArrayDType)) {
|
||||
portIrefp = VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType);
|
||||
portIrefp
|
||||
= VN_CAST(VN_CAST(modvarp->subDTypep(), UnpackArrayDType)->subDTypep(),
|
||||
IfaceRefDType);
|
||||
}
|
||||
|
||||
AstIfaceRefDType* pinIrefp = NULL;
|
||||
AstNode* exprp = pinp->exprp();
|
||||
if (exprp
|
||||
&& VN_IS(exprp, VarRef)
|
||||
&& VN_CAST(exprp, VarRef)->varp()
|
||||
if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
|
||||
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
|
||||
&& VN_IS(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType)) {
|
||||
pinIrefp = VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), IfaceRefDType);
|
||||
} else if (exprp
|
||||
&& exprp->op1p()
|
||||
&& VN_IS(exprp->op1p(), VarRef)
|
||||
} else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef)
|
||||
&& VN_CAST(exprp->op1p(), VarRef)->varp()
|
||||
&& VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()
|
||||
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)
|
||||
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep()
|
||||
&& VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
|
||||
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType);
|
||||
} else if (exprp
|
||||
&& VN_IS(exprp, VarRef)
|
||||
&& VN_CAST(exprp, VarRef)->varp()
|
||||
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
&& VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
->subDTypep()
|
||||
&& VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
->subDTypep(),
|
||||
IfaceRefDType)) {
|
||||
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
->subDTypep(),
|
||||
IfaceRefDType);
|
||||
} else if (exprp && VN_IS(exprp, VarRef) && VN_CAST(exprp, VarRef)->varp()
|
||||
&& VN_CAST(exprp, VarRef)->varp()->subDTypep()
|
||||
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)
|
||||
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep()
|
||||
&& VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType)) {
|
||||
pinIrefp = VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)->subDTypep(), IfaceRefDType);
|
||||
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
&& VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
->subDTypep()
|
||||
&& VN_CAST(VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(),
|
||||
UnpackArrayDType)
|
||||
->subDTypep(),
|
||||
IfaceRefDType)) {
|
||||
pinIrefp = VN_CAST(
|
||||
VN_CAST(VN_CAST(exprp, VarRef)->varp()->subDTypep(), UnpackArrayDType)
|
||||
->subDTypep(),
|
||||
IfaceRefDType);
|
||||
}
|
||||
|
||||
UINFO(9," portIfaceRef "<<portIrefp<<endl);
|
||||
UINFO(9, " portIfaceRef " << portIrefp << endl);
|
||||
|
||||
if (!portIrefp) {
|
||||
pinp->v3error("Interface port "<<modvarp->prettyNameQ()
|
||||
<<" is not an interface " << modvarp);
|
||||
pinp->v3error("Interface port " << modvarp->prettyNameQ()
|
||||
<< " is not an interface " << modvarp);
|
||||
} else if (!pinIrefp) {
|
||||
pinp->v3error("Interface port "<<modvarp->prettyNameQ()
|
||||
<<" is not connected to interface/modport pin expression");
|
||||
pinp->v3error("Interface port "
|
||||
<< modvarp->prettyNameQ()
|
||||
<< " is not connected to interface/modport pin expression");
|
||||
} else {
|
||||
UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
|
||||
UINFO(9, " pinIfaceRef " << pinIrefp << endl);
|
||||
if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
|
||||
UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
|
||||
UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl);
|
||||
longname += ("_" + paramSmallName(srcModp, pinp->modVarp())
|
||||
+ paramValueNumber(pinIrefp));
|
||||
any_overrides = true;
|
||||
|
|
@ -704,11 +714,11 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
if (portIrefp->ifacep() != pinIrefp->ifacep()
|
||||
// Might be different only due to param cloning, so check names too
|
||||
&& portIrefp->ifaceName() != pinIrefp->ifaceName()) {
|
||||
pinp->v3error("Port "<<pinp->prettyNameQ()<<" expects "
|
||||
<<AstNode::prettyNameQ(portIrefp->ifaceName())
|
||||
<<" interface but pin connects "
|
||||
<<AstNode::prettyNameQ(pinIrefp->ifaceName())
|
||||
<<" interface");
|
||||
pinp->v3error("Port " << pinp->prettyNameQ() << " expects "
|
||||
<< AstNode::prettyNameQ(portIrefp->ifaceName())
|
||||
<< " interface but pin connects "
|
||||
<< AstNode::prettyNameQ(pinIrefp->ifaceName())
|
||||
<< " interface");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -716,23 +726,24 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
}
|
||||
|
||||
if (!any_overrides) {
|
||||
UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
|
||||
UINFO(8, "Cell parameters all match original values, skipping expansion.\n");
|
||||
} else {
|
||||
// If the name is very long, we don't want to overwhelm the filename limit
|
||||
// We don't do this always, as it aids debugability to have intuitive naming.
|
||||
// TODO can use new V3Name hash replacement instead of this
|
||||
string newname = longname;
|
||||
if (longname.length()>30) {
|
||||
if (longname.length() > 30) {
|
||||
LongMap::iterator iter = m_longMap.find(longname);
|
||||
if (iter != m_longMap.end()) {
|
||||
newname = iter->second;
|
||||
} else {
|
||||
newname = srcModp->name();
|
||||
newname += "__pi"+cvtToStr(++m_longId); // We use all upper case above, so lower here can't conflict
|
||||
// We use all upper case above, so lower here can't conflict
|
||||
newname += "__pi" + cvtToStr(++m_longId);
|
||||
m_longMap.insert(make_pair(longname, newname));
|
||||
}
|
||||
}
|
||||
UINFO(4,"Name: "<<srcModp->name()<<"->"<<longname<<"->"<<newname<<endl);
|
||||
UINFO(4, "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl);
|
||||
|
||||
//
|
||||
// Already made this flavor?
|
||||
|
|
@ -750,11 +761,11 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
cellmodp->recursiveClone(false);
|
||||
nodep->recursive(false);
|
||||
// Recursion may need level cleanups
|
||||
if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level()+1);
|
||||
if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level() + 1);
|
||||
if ((cellmodp->level() - srcModp->level())
|
||||
>= (v3Global.opt.moduleRecursionDepth() - 2)) {
|
||||
nodep->v3error("Exceeded maximum --module-recursion-depth of "
|
||||
<<v3Global.opt.moduleRecursionDepth());
|
||||
<< v3Global.opt.moduleRecursionDepth());
|
||||
}
|
||||
// Keep tree sorted by level
|
||||
AstNodeModule* insertp = srcModp;
|
||||
|
|
@ -767,7 +778,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
m_modNameMap.insert(make_pair(cellmodp->name(), ModInfo(cellmodp)));
|
||||
iter = m_modNameMap.find(newname);
|
||||
CloneMap* clonemapp = &(iter->second.m_cloneMap);
|
||||
UINFO(4," De-parameterize to new: "<<cellmodp<<endl);
|
||||
UINFO(4, " De-parameterize to new: " << cellmodp << endl);
|
||||
|
||||
// Grab all I/O so we can remap our pins later
|
||||
// Note we allow multiple users of a parameterized model,
|
||||
|
|
@ -777,23 +788,23 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
relinkPins(clonemapp, nodep->paramsp());
|
||||
|
||||
// Fix any interface references
|
||||
for (IfaceRefRefs::iterator it=ifaceRefRefs.begin();
|
||||
it!=ifaceRefRefs.end(); ++it) {
|
||||
for (IfaceRefRefs::iterator it = ifaceRefRefs.begin(); it != ifaceRefRefs.end();
|
||||
++it) {
|
||||
AstIfaceRefDType* portIrefp = it->first;
|
||||
AstIfaceRefDType* pinIrefp = it->second;
|
||||
AstIfaceRefDType* cloneIrefp = portIrefp->clonep();
|
||||
UINFO(8," IfaceOld "<<portIrefp<<endl);
|
||||
UINFO(8," IfaceTo "<<pinIrefp<<endl);
|
||||
UINFO(8, " IfaceOld " << portIrefp << endl);
|
||||
UINFO(8, " IfaceTo " << pinIrefp << endl);
|
||||
UASSERT_OBJ(cloneIrefp, portIrefp,
|
||||
"parameter clone didn't hit AstIfaceRefDType");
|
||||
UINFO(8," IfaceClo "<<cloneIrefp<<endl);
|
||||
UINFO(8, " IfaceClo " << cloneIrefp << endl);
|
||||
cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
|
||||
UINFO(8," IfaceNew "<<cloneIrefp<<endl);
|
||||
UINFO(8, " IfaceNew " << cloneIrefp << endl);
|
||||
}
|
||||
|
||||
// Assign parameters to the constants specified
|
||||
// DOES clone() so must be finished with module clonep() before here
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=VN_CAST(pinp->nextp(), Pin)) {
|
||||
for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) {
|
||||
if (pinp->exprp()) {
|
||||
if (AstVar* modvarp = pinp->modVarp()) {
|
||||
AstNode* newp = pinp->exprp(); // Const or InitArray
|
||||
|
|
@ -801,8 +812,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree();
|
||||
// Set this parameter to value requested by cell
|
||||
modvarp->valuep(newp->cloneTree(false));
|
||||
}
|
||||
else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
|
||||
} else if (AstParamTypeDType* modptp = pinp->modPTypep()) {
|
||||
AstNodeDType* dtypep = VN_CAST(pinp->exprp(), NodeDType);
|
||||
UASSERT_OBJ(dtypep, pinp, "unlinked param dtype");
|
||||
if (modptp->childDTypep()) {
|
||||
|
|
@ -817,7 +827,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
}
|
||||
|
||||
} else {
|
||||
UINFO(4," De-parameterize to old: "<<cellmodp<<endl);
|
||||
UINFO(4, " De-parameterize to old: " << cellmodp << endl);
|
||||
}
|
||||
|
||||
// Have child use this module instead.
|
||||
|
|
@ -827,15 +837,16 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
// We need to relink the pins to the new module
|
||||
CloneMap* clonemapp = &(iter->second.m_cloneMap);
|
||||
relinkPins(clonemapp, nodep->pinsp());
|
||||
UINFO(8," Done with "<<cellmodp<<endl);
|
||||
UINFO(8, " Done with " << cellmodp << endl);
|
||||
} // if any_overrides
|
||||
|
||||
nodep->recursive(false);
|
||||
|
||||
// Delete the parameters from the cell; they're not relevant any longer.
|
||||
if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
|
||||
UINFO(8," Done with "<<nodep<<endl);
|
||||
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
|
||||
UINFO(8, " Done with " << nodep << endl);
|
||||
// if (debug() >= 10)
|
||||
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
|
||||
}
|
||||
|
||||
// Now remember to process the child module at the end of the module
|
||||
|
|
@ -846,9 +857,7 @@ void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) {
|
|||
// Param class functions
|
||||
|
||||
void V3Param::param(AstNetlist* rootp) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
ParamVisitor visitor (rootp);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ParamVisitor visitor(rootp); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("param", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 6);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
//
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict
|
||||
|
||||
//======================================================================
|
||||
|
|
@ -27,7 +26,7 @@
|
|||
|
||||
int V3ParseImp::bisonParse() {
|
||||
// Use --debugi-bison 9 to enable this
|
||||
if (PARSEP->debugBison()>=9) yydebug = 1;
|
||||
if (PARSEP->debugBison() >= 9) yydebug = 1;
|
||||
return yyparse();
|
||||
}
|
||||
|
||||
|
|
@ -36,8 +35,8 @@ const char* V3ParseImp::tokenName(int token) {
|
|||
static const char** nameTablep = NULL;
|
||||
if (!nameTablep) {
|
||||
int size;
|
||||
for (size = 0; yytname[size]; ++size) ;
|
||||
nameTablep = new const char* [size];
|
||||
for (size = 0; yytname[size]; ++size) {}
|
||||
nameTablep = new const char*[size];
|
||||
// Workaround bug in bison's which have '!' in yytname but not token values
|
||||
int iout = 0;
|
||||
for (int i = 0; yytname[i]; ++i) {
|
||||
|
|
@ -46,9 +45,11 @@ const char* V3ParseImp::tokenName(int token) {
|
|||
}
|
||||
}
|
||||
if (token >= 255) {
|
||||
return nameTablep[token-255];
|
||||
return nameTablep[token - 255];
|
||||
} else {
|
||||
static char ch[2]; ch[0] = token; ch[1] = '\0';
|
||||
static char ch[2];
|
||||
ch[0] = token;
|
||||
ch[1] = '\0';
|
||||
return ch;
|
||||
}
|
||||
#else
|
||||
|
|
@ -76,18 +77,20 @@ void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
|
|||
}
|
||||
|
||||
AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) {
|
||||
return new AstAssignW(fileline, new AstVarRef(fileline, name, true),
|
||||
new AstConst(fileline, AstConst::StringToParse(),
|
||||
(value ? "'1" : "'0")));
|
||||
return new AstAssignW(
|
||||
fileline, new AstVarRef(fileline, name, true),
|
||||
new AstConst(fileline, AstConst::StringToParse(), (value ? "'1" : "'0")));
|
||||
}
|
||||
|
||||
AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
||||
// Remove any UnsizedRange's from list
|
||||
for (AstNodeRange* nodep = nrangep, *nextp; nodep; nodep = nextp) {
|
||||
for (AstNodeRange *nodep = nrangep, *nextp; nodep; nodep = nextp) {
|
||||
nextp = VN_CAST(nodep->nextp(), NodeRange);
|
||||
if (!VN_IS(nodep, Range)) {
|
||||
nodep->v3error("Unsupported or syntax error: Unsized range in cell or other declaration");
|
||||
nodep->unlinkFrBack(); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
nodep->v3error(
|
||||
"Unsupported or syntax error: Unsized range in cell or other declaration");
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
if (nrangep && nrangep->nextp()) {
|
||||
|
|
@ -98,8 +101,8 @@ AstRange* V3ParseGrammar::scrubRange(AstNodeRange* nrangep) {
|
|||
return VN_CAST(nrangep, Range);
|
||||
}
|
||||
|
||||
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
|
||||
AstNodeRange* nrangep, bool isPacked) {
|
||||
AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstNodeRange* nrangep,
|
||||
bool isPacked) {
|
||||
// Split RANGE0-RANGE1-RANGE2
|
||||
// into ARRAYDTYPE0(ARRAYDTYPE1(ARRAYDTYPE2(BASICTYPE3), RANGE), RANGE)
|
||||
AstNodeDType* arrayp = basep;
|
||||
|
|
@ -110,26 +113,26 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
|
|||
if (prevp) nrangep->unlinkFrBack();
|
||||
AstRange* rangep = VN_CAST(nrangep, Range);
|
||||
if (rangep && isPacked) {
|
||||
arrayp = new AstPackArrayDType
|
||||
(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
||||
arrayp
|
||||
= new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
||||
} else if (VN_IS(nrangep, QueueRange)) {
|
||||
arrayp = new AstQueueDType
|
||||
(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
|
||||
} else if (rangep && (VN_IS(rangep->leftp(), Unbounded)
|
||||
|| VN_IS(rangep->rightp(), Unbounded))) {
|
||||
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp, NULL);
|
||||
} else if (rangep
|
||||
&& (VN_IS(rangep->leftp(), Unbounded)
|
||||
|| VN_IS(rangep->rightp(), Unbounded))) {
|
||||
arrayp = new AstQueueDType(nrangep->fileline(), VFlagChildDType(), arrayp,
|
||||
rangep->rightp()->cloneTree(true));
|
||||
} else if (rangep) {
|
||||
arrayp = new AstUnpackArrayDType
|
||||
(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
|
||||
arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp,
|
||||
rangep);
|
||||
} else if (VN_IS(nrangep, UnsizedRange)) {
|
||||
arrayp = new AstUnsizedArrayDType
|
||||
(nrangep->fileline(), VFlagChildDType(), arrayp);
|
||||
arrayp = new AstUnsizedArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp);
|
||||
} else if (VN_IS(nrangep, AssocRange)) {
|
||||
AstAssocRange* arangep = VN_CAST(nrangep, AssocRange);
|
||||
AstNodeDType* keyp = arangep->keyDTypep(); keyp->unlinkFrBack();
|
||||
arrayp = new AstAssocArrayDType
|
||||
(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
|
||||
AstNodeDType* keyp = arangep->keyDTypep();
|
||||
keyp->unlinkFrBack();
|
||||
arrayp
|
||||
= new AstAssocArrayDType(nrangep->fileline(), VFlagChildDType(), arrayp, keyp);
|
||||
} else {
|
||||
UASSERT_OBJ(0, nrangep, "Expected range or unsized range");
|
||||
}
|
||||
|
|
@ -142,10 +145,9 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep,
|
|||
AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
||||
AstNodeRange* arrayp, AstNode* attrsp) {
|
||||
AstNodeDType* dtypep = GRAMMARP->m_varDTypep;
|
||||
UINFO(5," creVar "<<name<<" decl="<<GRAMMARP->m_varDecl
|
||||
<<" io="<<GRAMMARP->m_varIO<<" dt="<<(dtypep?"set":"")<<endl);
|
||||
if (GRAMMARP->m_varIO == VDirection::NONE
|
||||
&& GRAMMARP->m_varDecl == AstVarType::PORT) {
|
||||
UINFO(5, " creVar " << name << " decl=" << GRAMMARP->m_varDecl << " io="
|
||||
<< GRAMMARP->m_varIO << " dt=" << (dtypep ? "set" : "") << endl);
|
||||
if (GRAMMARP->m_varIO == VDirection::NONE && GRAMMARP->m_varDecl == AstVarType::PORT) {
|
||||
// Just a port list with variable name (not v2k format); AstPort already created
|
||||
if (dtypep) fileline->v3error("Unsupported: Ranges ignored in port-lists");
|
||||
return NULL;
|
||||
|
|
@ -159,7 +161,8 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
|||
} else { // May make new variables with same type, so clone
|
||||
dtypep = dtypep->cloneTree(false);
|
||||
}
|
||||
//UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<" io="<<GRAMMARP->m_varIO.ascii()<<endl);
|
||||
// UINFO(0,"CREVAR "<<fileline->ascii()<<" decl="<<GRAMMARP->m_varDecl.ascii()<<"
|
||||
// io="<<GRAMMARP->m_varIO.ascii()<<endl);
|
||||
AstVarType type = GRAMMARP->m_varDecl;
|
||||
if (type == AstVarType::UNKNOWN) {
|
||||
if (GRAMMARP->m_varIO.isAny()) {
|
||||
|
|
@ -169,7 +172,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
|||
}
|
||||
}
|
||||
if (type == AstVarType::GENVAR) {
|
||||
if (arrayp) fileline->v3error("Genvars may not be arrayed: "<<name);
|
||||
if (arrayp) fileline->v3error("Genvars may not be arrayed: " << name);
|
||||
}
|
||||
|
||||
// Split RANGE0-RANGE1-RANGE2 into
|
||||
|
|
@ -202,9 +205,13 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name,
|
|||
// We need to autosize parameters and integers separately
|
||||
//
|
||||
// Propagate from current module tracing state
|
||||
if (nodep->isGenVar()) nodep->trace(false);
|
||||
else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false);
|
||||
else nodep->trace(allTracingOn(nodep->fileline()));
|
||||
if (nodep->isGenVar()) {
|
||||
nodep->trace(false);
|
||||
} else if (nodep->isParam() && !v3Global.opt.traceParams()) {
|
||||
nodep->trace(false);
|
||||
} else {
|
||||
nodep->trace(allTracingOn(nodep->fileline()));
|
||||
}
|
||||
|
||||
// Remember the last variable created, so we can attach attributes to it in later parsing
|
||||
GRAMMARP->m_varAttrp = nodep;
|
||||
|
|
@ -222,7 +229,7 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
|
|||
for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) {
|
||||
if (quoted) {
|
||||
if (isdigit(*cp)) {
|
||||
octal_val = octal_val*8 + (*cp-'0');
|
||||
octal_val = octal_val * 8 + (*cp - '0');
|
||||
if (++octal_digits == 3) {
|
||||
octal_digits = 0;
|
||||
quoted = false;
|
||||
|
|
@ -238,29 +245,33 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
|
|||
continue;
|
||||
}
|
||||
quoted = false;
|
||||
if (*cp == 'n') newtext += '\n';
|
||||
else if (*cp == 'a') newtext += '\a'; // SystemVerilog 3.1
|
||||
else if (*cp == 'f') newtext += '\f'; // SystemVerilog 3.1
|
||||
else if (*cp == 'r') newtext += '\r';
|
||||
else if (*cp == 't') newtext += '\t';
|
||||
else if (*cp == 'v') newtext += '\v'; // SystemVerilog 3.1
|
||||
else if (*cp == 'x' && isxdigit(cp[1]) && isxdigit(cp[2])) { // SystemVerilog 3.1
|
||||
#define vl_decodexdigit(c) ((isdigit(c)?((c)-'0'):(tolower((c))-'a'+10)))
|
||||
newtext += (char)(16*vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2]));
|
||||
if (*cp == 'n') {
|
||||
newtext += '\n';
|
||||
} else if (*cp == 'a') {
|
||||
newtext += '\a'; // SystemVerilog 3.1
|
||||
} else if (*cp == 'f') {
|
||||
newtext += '\f'; // SystemVerilog 3.1
|
||||
} else if (*cp == 'r') {
|
||||
newtext += '\r';
|
||||
} else if (*cp == 't') {
|
||||
newtext += '\t';
|
||||
} else if (*cp == 'v') {
|
||||
newtext += '\v'; // SystemVerilog 3.1
|
||||
} else if (*cp == 'x' && isxdigit(cp[1])
|
||||
&& isxdigit(cp[2])) { // SystemVerilog 3.1
|
||||
#define vl_decodexdigit(c) ((isdigit(c) ? ((c) - '0') : (tolower((c)) - 'a' + 10)))
|
||||
newtext += (char)(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2]));
|
||||
cp += 2;
|
||||
}
|
||||
else if (isalnum(*cp)) {
|
||||
fileline->v3error("Unknown escape sequence: \\"<<*cp);
|
||||
} else if (isalnum(*cp)) {
|
||||
fileline->v3error("Unknown escape sequence: \\" << *cp);
|
||||
break;
|
||||
}
|
||||
else newtext += *cp;
|
||||
} else
|
||||
newtext += *cp;
|
||||
}
|
||||
}
|
||||
else if (*cp == '\\') {
|
||||
} else if (*cp == '\\') {
|
||||
quoted = true;
|
||||
octal_digits = 0;
|
||||
}
|
||||
else if (*cp != '"') {
|
||||
} else if (*cp != '"') {
|
||||
newtext += *cp;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@
|
|||
//======================================================================
|
||||
// Globals
|
||||
|
||||
V3ParseImp* V3ParseImp::s_parsep = NULL;
|
||||
V3ParseImp* V3ParseImp::s_parsep = NULL;
|
||||
|
||||
int V3ParseSym::s_anonNum = 0;
|
||||
int V3ParseSym::s_anonNum = 0;
|
||||
|
||||
extern void yyerror(const char*);
|
||||
extern void yyerrorf(const char* format, ...);
|
||||
|
|
@ -63,7 +63,10 @@ V3ParseImp::~V3ParseImp() {
|
|||
lexDestroy();
|
||||
parserClear();
|
||||
|
||||
if (debug()>=9) { UINFO(0,"~V3ParseImp\n"); symp()->dump(cout, "-vpi: "); }
|
||||
if (debug() >= 9) {
|
||||
UINFO(0, "~V3ParseImp\n");
|
||||
symp()->dump(cout, "-vpi: ");
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
|
@ -73,7 +76,7 @@ void V3ParseImp::ppline(const char* textp) {
|
|||
// Handle `line directive
|
||||
FileLine* prevFl = copyOrSameFileLine();
|
||||
int enterExit;
|
||||
fileline()->lineDirective(textp, enterExit/*ref*/);
|
||||
fileline()->lineDirective(textp, enterExit /*ref*/);
|
||||
if (enterExit == 1) { // Enter
|
||||
fileline()->parent(prevFl);
|
||||
} else if (enterExit == 2) { // Exit
|
||||
|
|
@ -83,9 +86,7 @@ void V3ParseImp::ppline(const char* textp) {
|
|||
}
|
||||
}
|
||||
|
||||
void V3ParseImp::verilatorCmtLintSave() {
|
||||
m_lintState.push_back(*parsep()->fileline());
|
||||
}
|
||||
void V3ParseImp::verilatorCmtLintSave() { m_lintState.push_back(*parsep()->fileline()); }
|
||||
|
||||
void V3ParseImp::verilatorCmtLintRestore() {
|
||||
if (m_lintState.empty()) {
|
||||
|
|
@ -117,16 +118,10 @@ void V3ParseImp::verilatorCmtBad(const char* textp) {
|
|||
if (cmtparse.substr(0, strlen("/*verilator")) == "/*verilator") {
|
||||
cmtparse.replace(0, strlen("/*verilator"), "");
|
||||
}
|
||||
while (isspace(cmtparse[0])) {
|
||||
cmtparse.replace(0, 1, "");
|
||||
}
|
||||
while (isspace(cmtparse[0])) cmtparse.replace(0, 1, "");
|
||||
string cmtname;
|
||||
for (int i = 0; isalnum(cmtparse[i]); i++) {
|
||||
cmtname += cmtparse[i];
|
||||
}
|
||||
if (!parsep()->optFuture(cmtname)) {
|
||||
yyerrorf("Unknown verilator comment: %s", textp);
|
||||
}
|
||||
for (int i = 0; isalnum(cmtparse[i]); i++) { cmtname += cmtparse[i]; }
|
||||
if (!parsep()->optFuture(cmtname)) yyerrorf("Unknown verilator comment: %s", textp);
|
||||
}
|
||||
|
||||
void V3ParseImp::errorPreprocDirective(const char* textp) {
|
||||
|
|
@ -140,8 +135,9 @@ void V3ParseImp::errorPreprocDirective(const char* textp) {
|
|||
}
|
||||
V3PreShell::candidateDefines(&speller);
|
||||
string suggest = speller.bestCandidateMsg(textp);
|
||||
fileline()->v3error("Define or directive not defined: '"<<textp<<"'\n"
|
||||
<<(suggest.empty() ? "" : fileline()->warnMore()+suggest));
|
||||
fileline()->v3error("Define or directive not defined: '"
|
||||
<< textp << "'\n"
|
||||
<< (suggest.empty() ? "" : fileline()->warnMore() + suggest));
|
||||
}
|
||||
|
||||
void V3ParseImp::tag(const char* text) {
|
||||
|
|
@ -154,19 +150,22 @@ void V3ParseImp::tag(const char* text) {
|
|||
}
|
||||
|
||||
double V3ParseImp::parseDouble(const char* textp, size_t length, bool* successp) {
|
||||
char* strgp = new char[length+1];
|
||||
char* strgp = new char[length + 1];
|
||||
char* dp = strgp;
|
||||
if (successp) *successp = true;
|
||||
for (const char* sp = textp; sp < (textp+length); ++sp) {
|
||||
for (const char* sp = textp; sp < (textp + length); ++sp) {
|
||||
if (*sp != '_') *dp++ = *sp;
|
||||
}
|
||||
*dp++ = '\0';
|
||||
char* endp = strgp;
|
||||
double d = strtod(strgp, &endp);
|
||||
size_t parsed_len = endp-strgp;
|
||||
size_t parsed_len = endp - strgp;
|
||||
if (parsed_len != strlen(strgp)) {
|
||||
if (successp) *successp = false;
|
||||
else yyerrorf("Syntax error parsing real: %s", strgp);
|
||||
if (successp) {
|
||||
*successp = false;
|
||||
} else {
|
||||
yyerrorf("Syntax error parsing real: %s", strgp);
|
||||
}
|
||||
}
|
||||
VL_DO_DANGLING(delete[] strgp, strgp);
|
||||
return d;
|
||||
|
|
@ -179,20 +178,21 @@ size_t V3ParseImp::ppInputToLex(char* buf, size_t max_size) {
|
|||
size_t got = 0;
|
||||
while (got < max_size // Haven't got enough
|
||||
&& !m_ppBuffers.empty()) { // And something buffered
|
||||
string front = m_ppBuffers.front(); m_ppBuffers.pop_front();
|
||||
string front = m_ppBuffers.front();
|
||||
m_ppBuffers.pop_front();
|
||||
size_t len = front.length();
|
||||
if (len > (max_size-got)) { // Front string too big
|
||||
string remainder = front.substr(max_size-got);
|
||||
front = front.substr(0, max_size-got);
|
||||
if (len > (max_size - got)) { // Front string too big
|
||||
string remainder = front.substr(max_size - got);
|
||||
front = front.substr(0, max_size - got);
|
||||
m_ppBuffers.push_front(remainder); // Put back remainder for next time
|
||||
len = (max_size-got);
|
||||
len = (max_size - got);
|
||||
}
|
||||
memcpy(buf+got, front.c_str(), len);
|
||||
memcpy(buf + got, front.c_str(), len);
|
||||
got += len;
|
||||
}
|
||||
if (debug()>=9) {
|
||||
if (debug() >= 9) {
|
||||
string out = string(buf, got);
|
||||
cout<<" inputToLex got="<<got<<" '"<<out<<"'"<<endl;
|
||||
cout << " inputToLex got=" << got << " '" << out << "'" << endl;
|
||||
}
|
||||
// Note returns 0 at EOF
|
||||
return got;
|
||||
|
|
@ -203,11 +203,15 @@ void V3ParseImp::preprocDumps(std::ostream& os) {
|
|||
V3PreShell::dumpDefines(os);
|
||||
} else {
|
||||
bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine();
|
||||
for (std::deque<string>::iterator it = m_ppBuffers.begin(); it!=m_ppBuffers.end(); ++it) {
|
||||
for (std::deque<string>::iterator it = m_ppBuffers.begin(); it != m_ppBuffers.end();
|
||||
++it) {
|
||||
if (noblanks) {
|
||||
bool blank = true;
|
||||
for (string::iterator its = it->begin(); its != it->end(); ++its) {
|
||||
if (!isspace(*its) && *its!='\n') { blank = false; break; }
|
||||
if (!isspace(*its) && *its != '\n') {
|
||||
blank = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blank) continue;
|
||||
}
|
||||
|
|
@ -220,7 +224,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
|||
const string& errmsg) { // "" for no error, make fake node
|
||||
string modname = V3Os::filenameNonExt(modfilename);
|
||||
|
||||
UINFO(2,__FUNCTION__<<": "<<modname<<(inLibrary?" [LIB]":"")<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << modname << (inLibrary ? " [LIB]" : "") << endl);
|
||||
m_fileline = new FileLine(fileline);
|
||||
m_fileline->newContent();
|
||||
m_inLibrary = inLibrary;
|
||||
|
|
@ -237,7 +241,8 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
|||
|
||||
if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) {
|
||||
// Create output file with all the preprocessor output we buffered up
|
||||
string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp";
|
||||
string vppfilename
|
||||
= v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "_" + modname + ".vpp";
|
||||
std::ofstream* ofp = NULL;
|
||||
std::ostream* osp;
|
||||
if (v3Global.opt.preprocOnly()) {
|
||||
|
|
@ -246,7 +251,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
|||
osp = ofp = V3File::new_ofstream(vppfilename);
|
||||
}
|
||||
if (osp->fail()) {
|
||||
fileline->v3error("Cannot write preprocessor output: "+vppfilename);
|
||||
fileline->v3error("Cannot write preprocessor output: " + vppfilename);
|
||||
return;
|
||||
} else {
|
||||
preprocDumps(*osp);
|
||||
|
|
@ -267,7 +272,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
|||
|
||||
void V3ParseImp::lexFile(const string& modname) {
|
||||
// Prepare for lexing
|
||||
UINFO(3,"Lexing "<<modname<<endl);
|
||||
UINFO(3, "Lexing " << modname << endl);
|
||||
s_parsep = this;
|
||||
fileline()->warnResetDefault(); // Reenable warnings on each file
|
||||
lexDestroy(); // Restart from clean slate.
|
||||
|
|
@ -283,7 +288,7 @@ void V3ParseImp::lexFile(const string& modname) {
|
|||
V3Parse::V3Parse(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* symp) {
|
||||
m_impp = new V3ParseImp(rootp, filterp, symp);
|
||||
}
|
||||
V3Parse::~V3Parse() {
|
||||
V3Parse::~V3Parse() { //
|
||||
VL_DO_CLEAR(delete m_impp, m_impp = NULL);
|
||||
}
|
||||
void V3Parse::parseFile(FileLine* fileline, const string& modname, bool inLibrary,
|
||||
|
|
|
|||
127
src/V3ParseImp.h
127
src/V3ParseImp.h
|
|
@ -45,49 +45,49 @@ typedef enum { iprop_NONE, iprop_CONTEXT, iprop_PURE } V3ImportProperty;
|
|||
// We can't use bison's %union as we want to pass the fileline with all tokens
|
||||
|
||||
struct V3ParseBisonYYSType {
|
||||
FileLine* fl;
|
||||
AstNode* scp; // Symbol table scope for future lookups
|
||||
int token; // Read token, aka tok
|
||||
FileLine* fl;
|
||||
AstNode* scp; // Symbol table scope for future lookups
|
||||
int token; // Read token, aka tok
|
||||
union {
|
||||
V3Number* nump;
|
||||
string* strp;
|
||||
int cint;
|
||||
double cdouble;
|
||||
bool cbool;
|
||||
V3UniqState uniqstate;
|
||||
VSignedState signstate;
|
||||
V3Number* nump;
|
||||
string* strp;
|
||||
int cint;
|
||||
double cdouble;
|
||||
bool cbool;
|
||||
V3UniqState uniqstate;
|
||||
VSignedState signstate;
|
||||
V3ImportProperty iprop;
|
||||
V3ErrorCode::en errcodeen;
|
||||
AstAttrType::en attrtypeen;
|
||||
|
||||
AstNode* nodep;
|
||||
AstNode* nodep;
|
||||
|
||||
AstBasicDType* bdtypep;
|
||||
AstBegin* beginp;
|
||||
AstCase* casep;
|
||||
AstCaseItem* caseitemp;
|
||||
AstCell* cellp;
|
||||
AstClass* classp;
|
||||
AstConst* constp;
|
||||
AstBasicDType* bdtypep;
|
||||
AstBegin* beginp;
|
||||
AstCase* casep;
|
||||
AstCaseItem* caseitemp;
|
||||
AstCell* cellp;
|
||||
AstClass* classp;
|
||||
AstConst* constp;
|
||||
AstMemberDType* memberp;
|
||||
AstNodeModule* modulep;
|
||||
AstNodeModule* modulep;
|
||||
AstNodeUOrStructDType* uorstructp;
|
||||
AstNodeDType* dtypep;
|
||||
AstNodeFTask* ftaskp;
|
||||
AstNodeDType* dtypep;
|
||||
AstNodeFTask* ftaskp;
|
||||
AstNodeFTaskRef* ftaskrefp;
|
||||
AstNodeRange* rangep;
|
||||
AstNodeRange* rangep;
|
||||
AstNodeSenItem* senitemp;
|
||||
AstNodeVarRef* varnodep;
|
||||
AstPackage* packagep;
|
||||
AstPackageRef* packagerefp;
|
||||
AstParseRef* parserefp;
|
||||
AstPatMember* patmemberp;
|
||||
AstPattern* patternp;
|
||||
AstPin* pinp;
|
||||
AstRefDType* refdtypep;
|
||||
AstSenTree* sentreep;
|
||||
AstVar* varp;
|
||||
AstVarRef* varrefp;
|
||||
AstNodeVarRef* varnodep;
|
||||
AstPackage* packagep;
|
||||
AstPackageRef* packagerefp;
|
||||
AstParseRef* parserefp;
|
||||
AstPatMember* patmemberp;
|
||||
AstPattern* patternp;
|
||||
AstPin* pinp;
|
||||
AstRefDType* refdtypep;
|
||||
AstSenTree* sentreep;
|
||||
AstVar* varp;
|
||||
AstVarRef* varrefp;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -97,33 +97,33 @@ struct V3ParseBisonYYSType {
|
|||
|
||||
class V3ParseImp {
|
||||
// MEMBERS
|
||||
AstNetlist* m_rootp; // Root of the design
|
||||
VInFilter* m_filterp; // Reading filter
|
||||
V3ParseSym* m_symp; // Symbol table
|
||||
AstNetlist* m_rootp; // Root of the design
|
||||
VInFilter* m_filterp; // Reading filter
|
||||
V3ParseSym* m_symp; // Symbol table
|
||||
|
||||
V3Lexer* m_lexerp; // Current FlexLexer
|
||||
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
|
||||
FileLine* m_fileline; // Filename/linenumber currently active
|
||||
V3Lexer* m_lexerp; // Current FlexLexer
|
||||
static V3ParseImp* s_parsep; // Current THIS, bison() isn't class based
|
||||
FileLine* m_fileline; // Filename/linenumber currently active
|
||||
|
||||
bool m_inCellDefine; // Inside a `celldefine
|
||||
bool m_inLibrary; // Currently reading a library vs. regular file
|
||||
int m_inBeginKwd; // Inside a `begin_keywords
|
||||
int m_lastVerilogState; // Last LEX state in `begin_keywords
|
||||
bool m_inCellDefine; // Inside a `celldefine
|
||||
bool m_inLibrary; // Currently reading a library vs. regular file
|
||||
int m_inBeginKwd; // Inside a `begin_keywords
|
||||
int m_lastVerilogState; // Last LEX state in `begin_keywords
|
||||
VOptionBool m_unconnectedDrive; // Last unconnected drive
|
||||
|
||||
int m_prevLexToken; // previous parsed token (for lexer)
|
||||
bool m_ahead; // aheadval is valid
|
||||
V3ParseBisonYYSType m_aheadVal; // ahead token value
|
||||
int m_prevLexToken; // previous parsed token (for lexer)
|
||||
bool m_ahead; // aheadval is valid
|
||||
V3ParseBisonYYSType m_aheadVal; // ahead token value
|
||||
V3ParseBisonYYSType m_curBisonVal; // current token for error reporting
|
||||
V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting
|
||||
V3ParseBisonYYSType m_prevBisonVal; // previous token for error reporting
|
||||
|
||||
std::deque<string*> m_stringps; // Created strings for later cleanup
|
||||
std::deque<V3Number*> m_numberps; // Created numbers for later cleanup
|
||||
std::deque<FileLine> m_lintState; // Current lint state for save/restore
|
||||
std::deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
|
||||
std::deque<string*> m_stringps; // Created strings for later cleanup
|
||||
std::deque<V3Number*> m_numberps; // Created numbers for later cleanup
|
||||
std::deque<FileLine> m_lintState; // Current lint state for save/restore
|
||||
std::deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
|
||||
|
||||
string m_tag; // Contents (if any) of current verilator tag
|
||||
AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set.
|
||||
string m_tag; // Contents (if any) of current verilator tag
|
||||
AstNode* m_tagNodep; // Points to the node to set to m_tag or NULL to not set.
|
||||
public:
|
||||
// Note these are an exception to using the filename as the debug type
|
||||
static int debugBison() {
|
||||
|
|
@ -151,12 +151,21 @@ public:
|
|||
void errorPreprocDirective(const char* textp);
|
||||
void tag(const char* text);
|
||||
void tagNodep(AstNode* nodep) { m_tagNodep = nodep; }
|
||||
AstNode* tagNodep() const { return m_tagNodep;}
|
||||
AstNode* tagNodep() const { return m_tagNodep; }
|
||||
|
||||
static double parseDouble(const char* text, size_t length, bool* successp = NULL);
|
||||
void pushBeginKeywords(int state) { m_inBeginKwd++; m_lastVerilogState = state; }
|
||||
void pushBeginKeywords(int state) {
|
||||
m_inBeginKwd++;
|
||||
m_lastVerilogState = state;
|
||||
}
|
||||
bool popBeginKeywords() {
|
||||
if (m_inBeginKwd) { m_inBeginKwd--; return true; } else return false; }
|
||||
if (m_inBeginKwd) {
|
||||
m_inBeginKwd--;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
int lastVerilogState() const { return m_lastVerilogState; }
|
||||
static const char* tokenName(int tok);
|
||||
|
||||
|
|
@ -204,7 +213,7 @@ public:
|
|||
void unconnectedDrive(const VOptionBool flag) { m_unconnectedDrive = flag; }
|
||||
|
||||
// Interactions with parser
|
||||
int bisonParse();
|
||||
int bisonParse();
|
||||
|
||||
// Interactions with lexer
|
||||
void lexNew();
|
||||
|
|
@ -222,7 +231,9 @@ public:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
V3ParseImp(AstNetlist* rootp, VInFilter* filterp, V3ParseSym* parserSymp)
|
||||
: m_rootp(rootp), m_filterp(filterp), m_symp(parserSymp) {
|
||||
: m_rootp(rootp)
|
||||
, m_filterp(filterp)
|
||||
, m_symp(parserSymp) {
|
||||
m_fileline = NULL;
|
||||
m_lexerp = NULL;
|
||||
m_inCellDefine = false;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -353,7 +353,7 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
|
|||
// become a stale invalid pointer.
|
||||
//
|
||||
VPreStream* streamp = curStreamp();
|
||||
if (debug()>=10) {
|
||||
if (debug() >= 10) {
|
||||
cout<<"- pp:inputToLex ITL s="<<max_size<<" bs="<<streamp->m_buffers.size()<<endl;
|
||||
dumpStack();
|
||||
}
|
||||
|
|
@ -394,7 +394,7 @@ size_t V3PreLex::inputToLex(char* buf, size_t max_size) {
|
|||
if (again) goto again;
|
||||
}
|
||||
}
|
||||
if (debug()>=10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf, got)<<"'"<<endl; }
|
||||
if (debug() >= 10) { cout<<"- pp::inputToLex got="<<got<<" '"<<string(buf, got)<<"'"<<endl; }
|
||||
return got;
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
154
src/V3Premit.cpp
154
src/V3Premit.cpp
|
|
@ -42,17 +42,17 @@ class PremitAssignVisitor : public AstNVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
// AstVar::user4() // bool; occurs on LHS of current assignment
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser4InUse m_inuser4;
|
||||
|
||||
// STATE
|
||||
bool m_noopt; // Disable optimization of variables in this block
|
||||
bool m_noopt; // Disable optimization of variables in this block
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
//AstNode::user4ClearTree(); // Implied by AstUser4InUse
|
||||
// AstNode::user4ClearTree(); // Implied by AstUser4InUse
|
||||
// LHS first as fewer varrefs
|
||||
iterateAndNextNull(nodep->lhsp());
|
||||
// Now find vars marked as lhs
|
||||
|
|
@ -64,7 +64,7 @@ private:
|
|||
nodep->varp()->user4(true);
|
||||
} else {
|
||||
if (nodep->varp()->user4()) {
|
||||
if (!m_noopt) UINFO(4, "Block has LHS+RHS var: "<<nodep<<endl);
|
||||
if (!m_noopt) UINFO(4, "Block has LHS+RHS var: " << nodep << endl);
|
||||
m_noopt = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit PremitAssignVisitor(AstNodeAssign* nodep) {
|
||||
UINFO(4," PremitAssignVisitor on "<<nodep<<endl);
|
||||
UINFO(4, " PremitAssignVisitor on " << nodep << endl);
|
||||
m_noopt = false;
|
||||
iterate(nodep);
|
||||
}
|
||||
|
|
@ -92,23 +92,22 @@ private:
|
|||
// AstShiftL::user2() -> bool. True if converted to conditional
|
||||
// AstShiftR::user2() -> bool. True if converted to conditional
|
||||
// *::user4() -> See PremitAssignVisitor
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current block
|
||||
AstNode* m_stmtp; // Current statement
|
||||
AstWhile* m_inWhilep; // Inside while loop, special statement additions
|
||||
AstTraceInc* m_inTracep; // Inside while loop, special statement additions
|
||||
bool m_assignLhs; // Inside assignment lhs, don't breakup extracts
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current block
|
||||
AstNode* m_stmtp; // Current statement
|
||||
AstWhile* m_inWhilep; // Inside while loop, special statement additions
|
||||
AstTraceInc* m_inTracep; // Inside while loop, special statement additions
|
||||
bool m_assignLhs; // Inside assignment lhs, don't breakup extracts
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
bool assignNoTemp(AstNodeAssign* nodep) {
|
||||
return (VN_IS(nodep->lhsp(), VarRef)
|
||||
&& !AstVar::scVarRecurse(nodep->lhsp())
|
||||
return (VN_IS(nodep->lhsp(), VarRef) && !AstVar::scVarRecurse(nodep->lhsp())
|
||||
&& VN_IS(nodep->rhsp(), Const));
|
||||
}
|
||||
void checkNode(AstNode* nodep) {
|
||||
|
|
@ -119,24 +118,22 @@ private:
|
|||
// ARRAYSEL(*here*, ...) (No wides can be in any argument but first,
|
||||
// so we don't check which arg is wide)
|
||||
// ASSIGN(x, SEL*HERE*(ARRAYSEL()...) (m_assignLhs==true handles this.)
|
||||
//UINFO(9, " Check: "<<nodep<<endl);
|
||||
//UINFO(9, " Detail stmtp="<<(m_stmtp?"Y":"N")<<" U="<<(nodep->user1()?"Y":"N")<<" IW="<<(nodep->isWide()?"Y":"N")<<endl);
|
||||
if (m_stmtp
|
||||
&& !nodep->user1()) { // Not already done
|
||||
// UINFO(9, " Check: " << nodep << endl);
|
||||
// UINFO(9, " Detail stmtp=" << (m_stmtp?"Y":"N") << " U=" << (nodep->user1()?"Y":"N")
|
||||
// << " IW=" << (nodep->isWide()?"Y":"N") << endl);
|
||||
if (m_stmtp && !nodep->user1()) { // Not already done
|
||||
if (nodep->isWide()) {
|
||||
if (m_assignLhs) {
|
||||
} else if (nodep->firstAbovep()
|
||||
&& VN_IS(nodep->firstAbovep(), NodeAssign)
|
||||
} else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), NodeAssign)
|
||||
&& assignNoTemp(VN_CAST(nodep->firstAbovep(), NodeAssign))) {
|
||||
// Not much point if it's just a direct assignment to a constant
|
||||
} else if (VN_IS(nodep->backp(), Sel)
|
||||
&& VN_CAST(nodep->backp(), Sel)->widthp() == nodep) {
|
||||
// AstSel::width must remain a constant
|
||||
} else if (nodep->firstAbovep()
|
||||
&& VN_IS(nodep->firstAbovep(), ArraySel)) {
|
||||
} else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) {
|
||||
// ArraySel's are pointer refs, ignore
|
||||
} else {
|
||||
UINFO(4,"Cre Temp: "<<nodep<<endl);
|
||||
UINFO(4, "Cre Temp: " << nodep << endl);
|
||||
createDeepTemp(nodep, false);
|
||||
}
|
||||
}
|
||||
|
|
@ -144,9 +141,9 @@ private:
|
|||
}
|
||||
|
||||
AstVar* getBlockTemp(AstNode* nodep) {
|
||||
string newvarname = (string("__Vtemp")+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname,
|
||||
nodep->dtypep());
|
||||
string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp
|
||||
= new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep());
|
||||
m_funcp->addInitsp(varp);
|
||||
return varp;
|
||||
}
|
||||
|
|
@ -171,7 +168,7 @@ private:
|
|||
}
|
||||
|
||||
void createDeepTemp(AstNode* nodep, bool noSubst) {
|
||||
if (debug()>8) nodep->dumpTree(cout, "deepin:");
|
||||
if (debug() > 8) nodep->dumpTree(cout, "deepin:");
|
||||
|
||||
AstNRelinker linker;
|
||||
nodep->unlinkFrBack(&linker);
|
||||
|
|
@ -183,16 +180,15 @@ private:
|
|||
linker.relink(newp);
|
||||
// Put assignment before the referencing statement
|
||||
AstAssign* assp = new AstAssign(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), varp, true),
|
||||
nodep);
|
||||
new AstVarRef(nodep->fileline(), varp, true), nodep);
|
||||
insertBeforeStmt(assp);
|
||||
if (debug()>8) assp->dumpTree(cout, "deepou:");
|
||||
if (debug() > 8) assp->dumpTree(cout, "deepou:");
|
||||
nodep->user1(true); // Don't add another assignment
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
|
|
@ -211,7 +207,7 @@ private:
|
|||
if (m_funcp) m_stmtp = nodep;
|
||||
}
|
||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
UINFO(4," WHILE "<<nodep<<endl);
|
||||
UINFO(4, " WHILE " << nodep << endl);
|
||||
startStatement(nodep);
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
startStatement(nodep);
|
||||
|
|
@ -229,7 +225,7 @@ private:
|
|||
bool noopt = PremitAssignVisitor(nodep).noOpt();
|
||||
if (noopt && !nodep->user1()) {
|
||||
// Need to do this even if not wide, as e.g. a select may be on a wide operator
|
||||
UINFO(4,"Deep temp for LHS/RHS\n");
|
||||
UINFO(4, "Deep temp for LHS/RHS\n");
|
||||
createDeepTemp(nodep->rhsp(), false);
|
||||
}
|
||||
}
|
||||
|
|
@ -244,7 +240,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
UINFO(4," STMT "<<nodep<<endl);
|
||||
UINFO(4, " STMT " << nodep << endl);
|
||||
startStatement(nodep);
|
||||
iterateChildren(nodep);
|
||||
m_stmtp = NULL;
|
||||
|
|
@ -259,29 +255,30 @@ private:
|
|||
void visitShift(AstNodeBiop* nodep) {
|
||||
// Shifts of > 32/64 bits in C++ will wrap-around and generate non-0s
|
||||
if (!nodep->user2SetOnce()) {
|
||||
UINFO(4," ShiftFix "<<nodep<<endl);
|
||||
UINFO(4, " ShiftFix " << nodep << endl);
|
||||
const AstConst* shiftp = VN_CAST(nodep->rhsp(), Const);
|
||||
if (shiftp && shiftp->num().mostSetBitP1() > 32) {
|
||||
shiftp->v3error("Unsupported: Shifting of by over 32-bit number isn't supported."
|
||||
<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
||||
shiftp->v3error(
|
||||
"Unsupported: Shifting of by over 32-bit number isn't supported."
|
||||
<< " (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
|
||||
}
|
||||
if (nodep->widthMin() <= 64 // Else we'll use large operators which work right
|
||||
// C operator's width must be < maximum shift which is based on Verilog width
|
||||
&& nodep->width() < (1LL<<nodep->rhsp()->widthMin())) {
|
||||
// C operator's width must be < maximum shift which is
|
||||
// based on Verilog width
|
||||
&& nodep->width() < (1LL << nodep->rhsp()->widthMin())) {
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
AstNode* constzerop;
|
||||
int m1value = nodep->widthMin()-1; // Constant of width-1; not changing dtype width
|
||||
int m1value
|
||||
= nodep->widthMin() - 1; // Constant of width-1; not changing dtype width
|
||||
if (nodep->signedFlavor()) {
|
||||
// Then over shifting gives the sign bit, not all zeros
|
||||
// Note *NOT* clean output -- just like normal shift!
|
||||
// Create equivalent of VL_SIGNONES_(node_width)
|
||||
constzerop = new AstNegate(nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
new AstConst(nodep->fileline(),
|
||||
m1value),
|
||||
nodep->width()));
|
||||
constzerop = new AstNegate(
|
||||
nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(), nodep->lhsp()->cloneTree(false),
|
||||
new AstConst(nodep->fileline(), m1value), nodep->width()));
|
||||
} else {
|
||||
constzerop = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->width(), 0);
|
||||
|
|
@ -291,43 +288,39 @@ private:
|
|||
AstNode* constwidthp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->rhsp()->widthMin(), m1value);
|
||||
constwidthp->dtypeFrom(nodep->rhsp()); // unsigned
|
||||
AstCond* newp =
|
||||
new AstCond(nodep->fileline(),
|
||||
new AstGte(nodep->fileline(),
|
||||
constwidthp,
|
||||
nodep->rhsp()->cloneTree(false)),
|
||||
nodep,
|
||||
constzerop);
|
||||
AstCond* newp = new AstCond(
|
||||
nodep->fileline(),
|
||||
new AstGte(nodep->fileline(), constwidthp, nodep->rhsp()->cloneTree(false)),
|
||||
nodep, constzerop);
|
||||
replaceHandle.relink(newp);
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep); checkNode(nodep);
|
||||
}
|
||||
virtual void visit(AstShiftL* nodep) VL_OVERRIDE {
|
||||
visitShift(nodep);
|
||||
}
|
||||
virtual void visit(AstShiftR* nodep) VL_OVERRIDE {
|
||||
visitShift(nodep);
|
||||
}
|
||||
virtual void visit(AstShiftRS* nodep) VL_OVERRIDE {
|
||||
visitShift(nodep);
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
virtual void visit(AstShiftL* nodep) VL_OVERRIDE { visitShift(nodep); }
|
||||
virtual void visit(AstShiftR* nodep) VL_OVERRIDE { visitShift(nodep); }
|
||||
virtual void visit(AstShiftRS* nodep) VL_OVERRIDE { visitShift(nodep); }
|
||||
// Operators
|
||||
virtual void visit(AstNodeTermop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep); checkNode(nodep);
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeUniop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep); checkNode(nodep);
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep); checkNode(nodep);
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep); checkNode(nodep);
|
||||
iterateChildren(nodep);
|
||||
checkNode(nodep);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
{ // Only the 'from' is part of the assignment LHS
|
||||
{ // Only the 'from' is part of the assignment LHS
|
||||
bool prevAssign = m_assignLhs;
|
||||
m_assignLhs = false;
|
||||
iterateAndNextNull(nodep->lsbp());
|
||||
|
|
@ -338,7 +331,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
{ // Only the 'from' is part of the assignment LHS
|
||||
{ // Only the 'from' is part of the assignment LHS
|
||||
bool prevAssign = m_assignLhs;
|
||||
m_assignLhs = false;
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
|
|
@ -348,7 +341,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstAssocSel* nodep) VL_OVERRIDE {
|
||||
iterateAndNextNull(nodep->fromp());
|
||||
{ // Only the 'from' is part of the assignment LHS
|
||||
{ // Only the 'from' is part of the assignment LHS
|
||||
bool prevAssign = m_assignLhs;
|
||||
m_assignLhs = false;
|
||||
iterateAndNextNull(nodep->bitp());
|
||||
|
|
@ -362,8 +355,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeCond* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->expr1p()->isWide()
|
||||
&& !VN_IS(nodep->condp(), Const)
|
||||
if (nodep->expr1p()->isWide() && !VN_IS(nodep->condp(), Const)
|
||||
&& !VN_IS(nodep->condp(), VarRef)) {
|
||||
// We're going to need the expression several times in the expanded code,
|
||||
// so might as well make it a common expression
|
||||
|
|
@ -380,12 +372,11 @@ private:
|
|||
if (v3Global.opt.autoflush()) {
|
||||
AstNode* searchp = nodep->nextp();
|
||||
while (searchp && VN_IS(searchp, Comment)) searchp = searchp->nextp();
|
||||
if (searchp
|
||||
&& VN_IS(searchp, Display)
|
||||
if (searchp && VN_IS(searchp, Display)
|
||||
&& nodep->filep()->sameGateTree(VN_CAST(searchp, Display)->filep())) {
|
||||
// There's another display next; we can just wait to flush
|
||||
} else {
|
||||
UINFO(4,"Autoflush "<<nodep<<endl);
|
||||
UINFO(4, "Autoflush " << nodep << endl);
|
||||
nodep->addNextHere(new AstFFlush(nodep->fileline(),
|
||||
AstNode::cloneTreeNull(nodep->filep(), true)));
|
||||
}
|
||||
|
|
@ -395,9 +386,8 @@ private:
|
|||
iterateChildren(nodep);
|
||||
// Any strings sent to a display must be var of string data type,
|
||||
// to avoid passing a pointer to a temporary.
|
||||
for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) {
|
||||
if (expp->dtypep()->basicp()
|
||||
&& expp->dtypep()->basicp()->isString()
|
||||
for (AstNode* expp = nodep->exprsp(); expp; expp = expp->nextp()) {
|
||||
if (expp->dtypep()->basicp() && expp->dtypep()->basicp()->isString()
|
||||
&& !VN_IS(expp, VarRef)) {
|
||||
createDeepTemp(expp, true);
|
||||
}
|
||||
|
|
@ -430,9 +420,7 @@ public:
|
|||
// Premit class functions
|
||||
|
||||
void V3Premit::premitAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
PremitVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ PremitVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("premit", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,50 +26,49 @@
|
|||
|
||||
#include <list>
|
||||
|
||||
|
||||
//######################################################################
|
||||
// ProtectLib top-level visitor
|
||||
|
||||
class ProtectVisitor : public AstNVisitor {
|
||||
private:
|
||||
AstVFile* m_vfilep; // DPI-enabled Verilog wrapper
|
||||
AstCFile* m_cfilep; // C implementation of DPI functions
|
||||
private:
|
||||
AstVFile* m_vfilep; // DPI-enabled Verilog wrapper
|
||||
AstCFile* m_cfilep; // C implementation of DPI functions
|
||||
// Verilog text blocks
|
||||
AstTextBlock* m_modPortsp; // Module port list
|
||||
AstTextBlock* m_comboPortsp; // Combo function port list
|
||||
AstTextBlock* m_seqPortsp; // Sequential function port list
|
||||
AstTextBlock* m_modPortsp; // Module port list
|
||||
AstTextBlock* m_comboPortsp; // Combo function port list
|
||||
AstTextBlock* m_seqPortsp; // Sequential function port list
|
||||
AstTextBlock* m_comboIgnorePortsp; // Combo ignore function port list
|
||||
AstTextBlock* m_comboDeclsp; // Combo signal declaration list
|
||||
AstTextBlock* m_seqDeclsp; // Sequential signal declaration list
|
||||
AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list
|
||||
AstTextBlock* m_hashValuep; // CPP hash value
|
||||
AstTextBlock* m_comboParamsp; // Combo function parameter list
|
||||
AstTextBlock* m_clkSensp; // Clock sensitivity list
|
||||
AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list
|
||||
AstTextBlock* m_seqParamsp; // Sequential parameter list
|
||||
AstTextBlock* m_nbAssignsp; // Non-blocking assignment list
|
||||
AstTextBlock* m_seqAssignsp; // Sequential assignment list
|
||||
AstTextBlock* m_comboAssignsp; // Combo assignment list
|
||||
AstTextBlock* m_comboDeclsp; // Combo signal declaration list
|
||||
AstTextBlock* m_seqDeclsp; // Sequential signal declaration list
|
||||
AstTextBlock* m_tmpDeclsp; // Temporary signal declaration list
|
||||
AstTextBlock* m_hashValuep; // CPP hash value
|
||||
AstTextBlock* m_comboParamsp; // Combo function parameter list
|
||||
AstTextBlock* m_clkSensp; // Clock sensitivity list
|
||||
AstTextBlock* m_comboIgnoreParamsp; // Combo ignore parameter list
|
||||
AstTextBlock* m_seqParamsp; // Sequential parameter list
|
||||
AstTextBlock* m_nbAssignsp; // Non-blocking assignment list
|
||||
AstTextBlock* m_seqAssignsp; // Sequential assignment list
|
||||
AstTextBlock* m_comboAssignsp; // Combo assignment list
|
||||
// C text blocks
|
||||
AstTextBlock* m_cHashValuep; // CPP hash value
|
||||
AstTextBlock* m_cComboParamsp; // Combo function parameter list
|
||||
AstTextBlock* m_cComboInsp; // Combo input copy list
|
||||
AstTextBlock* m_cComboOutsp; // Combo output copy list
|
||||
AstTextBlock* m_cSeqParamsp; // Sequential parameter list
|
||||
AstTextBlock* m_cSeqClksp; // Sequential clock copy list
|
||||
AstTextBlock* m_cSeqOutsp; // Sequential output copy list
|
||||
AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list
|
||||
AstTextBlock* m_cHashValuep; // CPP hash value
|
||||
AstTextBlock* m_cComboParamsp; // Combo function parameter list
|
||||
AstTextBlock* m_cComboInsp; // Combo input copy list
|
||||
AstTextBlock* m_cComboOutsp; // Combo output copy list
|
||||
AstTextBlock* m_cSeqParamsp; // Sequential parameter list
|
||||
AstTextBlock* m_cSeqClksp; // Sequential clock copy list
|
||||
AstTextBlock* m_cSeqOutsp; // Sequential output copy list
|
||||
AstTextBlock* m_cIgnoreParamsp; // Combo ignore parameter list
|
||||
string m_libName;
|
||||
string m_topName;
|
||||
bool m_foundTop; // Have seen the top module
|
||||
bool m_foundTop; // Have seen the top module
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
m_vfilep = new AstVFile(nodep->fileline(),
|
||||
v3Global.opt.makeDir()+"/"+m_libName+".sv");
|
||||
m_vfilep
|
||||
= new AstVFile(nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".sv");
|
||||
nodep->addFilesp(m_vfilep);
|
||||
m_cfilep = new AstCFile(nodep->fileline(),
|
||||
v3Global.opt.makeDir()+"/"+m_libName+".cpp");
|
||||
m_cfilep
|
||||
= new AstCFile(nodep->fileline(), v3Global.opt.makeDir() + "/" + m_libName + ".cpp");
|
||||
nodep->addFilesp(m_cfilep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -87,8 +86,8 @@ class ProtectVisitor : public AstNVisitor {
|
|||
iterateChildren(nodep);
|
||||
|
||||
V3Hash hash = V3Hashed::uncachedHash(m_cfilep);
|
||||
m_hashValuep->addText(fl, cvtToStr(hash.fullValue())+";\n");
|
||||
m_cHashValuep->addText(fl, cvtToStr(hash.fullValue())+"U;\n");
|
||||
m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n");
|
||||
m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n");
|
||||
m_foundTop = true;
|
||||
}
|
||||
|
||||
|
|
@ -127,47 +126,55 @@ class ProtectVisitor : public AstNVisitor {
|
|||
// Comments
|
||||
AstTextBlock* txtp = new AstTextBlock(fl);
|
||||
addComment(txtp, fl, "Wrapper module for DPI protected library");
|
||||
addComment(txtp, fl, "This module requires lib"+m_libName+
|
||||
".a or lib"+m_libName+".so to work");
|
||||
addComment(txtp, fl, "See instructions in your simulator for how"
|
||||
addComment(txtp, fl,
|
||||
"This module requires lib" + m_libName + ".a or lib" + m_libName
|
||||
+ ".so to work");
|
||||
addComment(txtp, fl,
|
||||
"See instructions in your simulator for how"
|
||||
" to use DPI libraries\n");
|
||||
|
||||
// Module declaration
|
||||
m_modPortsp = new AstTextBlock(fl, "module "+m_libName+" (\n", false, true);
|
||||
m_modPortsp = new AstTextBlock(fl, "module " + m_libName + " (\n", false, true);
|
||||
txtp->addNodep(m_modPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
|
||||
// DPI declarations
|
||||
hashComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void "+
|
||||
m_libName+"_protectlib_check_hash(int protectlib_hash__V);\n\n");
|
||||
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_check_hash(int protectlib_hash__V);\n\n");
|
||||
initialComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function chandle "+
|
||||
m_libName+"_protectlib_create(string scope__V);\n\n");
|
||||
txtp->addText(fl, "import \"DPI-C\" function chandle " + m_libName
|
||||
+ "_protectlib_create(string scope__V);\n\n");
|
||||
comboComment(txtp, fl);
|
||||
m_comboPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+
|
||||
m_libName+"_protectlib_combo_update "
|
||||
"(\n", false, true);
|
||||
m_comboPortsp = new AstTextBlock(fl,
|
||||
"import \"DPI-C\" function longint " + m_libName
|
||||
+ "_protectlib_combo_update "
|
||||
"(\n",
|
||||
false, true);
|
||||
m_comboPortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodep(m_comboPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
seqComment(txtp, fl);
|
||||
m_seqPortsp = new AstTextBlock(fl, "import \"DPI-C\" function longint "+
|
||||
m_libName+"_protectlib_seq_update"
|
||||
"(\n", false, true);
|
||||
m_seqPortsp = new AstTextBlock(fl,
|
||||
"import \"DPI-C\" function longint " + m_libName
|
||||
+ "_protectlib_seq_update"
|
||||
"(\n",
|
||||
false, true);
|
||||
m_seqPortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodep(m_seqPortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
comboIgnoreComment(txtp, fl);
|
||||
m_comboIgnorePortsp = new AstTextBlock(fl, "import \"DPI-C\" function void "+
|
||||
m_libName+"_protectlib_combo_ignore"
|
||||
"(\n", false, true);
|
||||
m_comboIgnorePortsp = new AstTextBlock(fl,
|
||||
"import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_combo_ignore"
|
||||
"(\n",
|
||||
false, true);
|
||||
m_comboIgnorePortsp->addText(fl, "chandle handle__V\n");
|
||||
txtp->addNodep(m_comboIgnorePortsp);
|
||||
txtp->addText(fl, ");\n\n");
|
||||
finalComment(txtp, fl);
|
||||
txtp->addText(fl, "import \"DPI-C\" function void "+
|
||||
m_libName+"_protectlib_final(chandle handle__V);\n\n");
|
||||
txtp->addText(fl, "import \"DPI-C\" function void " + m_libName
|
||||
+ "_protectlib_final(chandle handle__V);\n\n");
|
||||
|
||||
// Local variables
|
||||
txtp->addText(fl, "chandle handle__V;\n\n");
|
||||
|
|
@ -189,16 +196,18 @@ class ProtectVisitor : public AstNVisitor {
|
|||
|
||||
// Initial
|
||||
txtp->addText(fl, "initial begin\n");
|
||||
txtp->addText(fl, m_libName+"_protectlib_check_hash(protectlib_hash__V);\n");
|
||||
txtp->addText(fl, "handle__V = "+m_libName+"_protectlib_create"
|
||||
"($sformatf(\"%m\"));\n");
|
||||
txtp->addText(fl, m_libName + "_protectlib_check_hash(protectlib_hash__V);\n");
|
||||
txtp->addText(fl, "handle__V = " + m_libName
|
||||
+ "_protectlib_create"
|
||||
"($sformatf(\"%m\"));\n");
|
||||
txtp->addText(fl, "end\n\n");
|
||||
|
||||
// Combinatorial process
|
||||
addComment(txtp, fl, "Combinatorialy evaluate changes to inputs");
|
||||
m_comboParamsp = new AstTextBlock(fl, "always @(*) begin\n"
|
||||
"last_combo_seqnum__V = "+
|
||||
m_libName+"_protectlib_combo_update(\n",
|
||||
m_comboParamsp = new AstTextBlock(fl,
|
||||
"always @(*) begin\n"
|
||||
"last_combo_seqnum__V = "
|
||||
+ m_libName + "_protectlib_combo_update(\n",
|
||||
false, true);
|
||||
m_comboParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodep(m_comboParamsp);
|
||||
|
|
@ -210,14 +219,13 @@ class ProtectVisitor : public AstNVisitor {
|
|||
m_clkSensp = new AstTextBlock(fl, "always @(", false, true);
|
||||
txtp->addNodep(m_clkSensp);
|
||||
txtp->addText(fl, ") begin\n");
|
||||
m_comboIgnoreParamsp = new AstTextBlock(fl, m_libName+"_protectlib_combo_ignore(\n",
|
||||
false, true);
|
||||
m_comboIgnoreParamsp
|
||||
= new AstTextBlock(fl, m_libName + "_protectlib_combo_ignore(\n", false, true);
|
||||
m_comboIgnoreParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodep(m_comboIgnoreParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
m_seqParamsp = new AstTextBlock(fl, "last_seq_seqnum__V <= "+m_libName+
|
||||
"_protectlib_seq_update(\n",
|
||||
false, true);
|
||||
m_seqParamsp = new AstTextBlock(
|
||||
fl, "last_seq_seqnum__V <= " + m_libName + "_protectlib_seq_update(\n", false, true);
|
||||
m_seqParamsp->addText(fl, "handle__V\n");
|
||||
txtp->addNodep(m_seqParamsp);
|
||||
txtp->addText(fl, ");\n");
|
||||
|
|
@ -229,7 +237,7 @@ class ProtectVisitor : public AstNVisitor {
|
|||
addComment(txtp, fl, "Select between combinatorial and sequential results");
|
||||
txtp->addText(fl, "always @(*) begin\n");
|
||||
m_seqAssignsp = new AstTextBlock(fl, "if (last_seq_seqnum__V > "
|
||||
"last_combo_seqnum__V) begin\n");
|
||||
"last_combo_seqnum__V) begin\n");
|
||||
txtp->addNodep(m_seqAssignsp);
|
||||
m_comboAssignsp = new AstTextBlock(fl, "end else begin\n");
|
||||
txtp->addNodep(m_comboAssignsp);
|
||||
|
|
@ -237,15 +245,17 @@ class ProtectVisitor : public AstNVisitor {
|
|||
txtp->addText(fl, "end\n\n");
|
||||
|
||||
// Final
|
||||
txtp->addText(fl, "final "+m_libName+"_protectlib_final(handle__V);\n\n");
|
||||
txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n");
|
||||
|
||||
txtp->addText(fl, "endmodule\n");
|
||||
m_vfilep->tblockp(txtp);
|
||||
}
|
||||
|
||||
void castPtr(FileLine* fl, AstTextBlock* txtp) {
|
||||
txtp->addText(fl, m_topName+"_container* handlep__V = "
|
||||
"static_cast<"+m_topName+"_container*>(vhandlep__V);\n");
|
||||
txtp->addText(fl, m_topName
|
||||
+ "_container* handlep__V = "
|
||||
"static_cast<"
|
||||
+ m_topName + "_container*>(vhandlep__V);\n");
|
||||
}
|
||||
|
||||
void createCppFile(FileLine* fl) {
|
||||
|
|
@ -254,18 +264,18 @@ class ProtectVisitor : public AstNVisitor {
|
|||
addComment(txtp, fl, "Wrapper functions for DPI protected library\n");
|
||||
|
||||
// Includes
|
||||
txtp->addText(fl, "#include \""+m_topName+".h\"\n");
|
||||
txtp->addText(fl, "#include \"" + m_topName + ".h\"\n");
|
||||
txtp->addText(fl, "#include \"verilated_dpi.h\"\n\n");
|
||||
txtp->addText(fl, "#include <cstdio>\n");
|
||||
txtp->addText(fl, "#include <cstdlib>\n\n");
|
||||
|
||||
// Verilated module plus sequence number
|
||||
addComment(txtp, fl, "Container class to house verilated object and sequence number");
|
||||
txtp->addText(fl, "class "+m_topName+"_container: public "+m_topName+" {\n");
|
||||
txtp->addText(fl, "class " + m_topName + "_container: public " + m_topName + " {\n");
|
||||
txtp->addText(fl, "public:\n");
|
||||
txtp->addText(fl, "long long m_seqnum;\n");
|
||||
txtp->addText(fl, m_topName+"_container(const char* scopep__V):\n");
|
||||
txtp->addText(fl, m_topName+"(scopep__V) {}\n");
|
||||
txtp->addText(fl, m_topName + "_container(const char* scopep__V):\n");
|
||||
txtp->addText(fl, m_topName + "(scopep__V) {}\n");
|
||||
txtp->addText(fl, "};\n\n");
|
||||
|
||||
// Extern C
|
||||
|
|
@ -273,31 +283,32 @@ class ProtectVisitor : public AstNVisitor {
|
|||
|
||||
// Hash check
|
||||
hashComment(txtp, fl);
|
||||
txtp->addText(fl, "void "+m_libName+"_protectlib_check_hash"
|
||||
"(int protectlib_hash__V) {\n");
|
||||
txtp->addText(fl, "void " + m_libName
|
||||
+ "_protectlib_check_hash"
|
||||
"(int protectlib_hash__V) {\n");
|
||||
m_cHashValuep = new AstTextBlock(fl, "int expected_hash__V = ");
|
||||
txtp->addNodep(m_cHashValuep);
|
||||
txtp->addText(fl, "if (protectlib_hash__V != expected_hash__V) {\n");
|
||||
txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use "+m_libName+" library, "
|
||||
"Verliog (%u) and library (%u) hash values do not "
|
||||
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
|
||||
txtp->addText(fl, "fprintf(stderr, \"%%Error: cannot use " + m_libName
|
||||
+ " library, "
|
||||
"Verliog (%u) and library (%u) hash values do not "
|
||||
"agree\\n\", protectlib_hash__V, expected_hash__V);\n");
|
||||
txtp->addText(fl, "exit(EXIT_FAILURE);\n");
|
||||
txtp->addText(fl, "}\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
// Initial
|
||||
initialComment(txtp, fl);
|
||||
txtp->addText(fl, "void* "+m_libName+"_protectlib_create"
|
||||
" (const char* scopep__V) {\n");
|
||||
txtp->addText(fl, m_topName+"_container* handlep__V = "
|
||||
"new "+m_topName+"_container(scopep__V);\n");
|
||||
txtp->addText(fl, "void* " + m_libName + "_protectlib_create(const char* scopep__V) {\n");
|
||||
txtp->addText(fl, m_topName + "_container* handlep__V = new " + m_topName
|
||||
+ "_container(scopep__V);\n");
|
||||
txtp->addText(fl, "return handlep__V;\n");
|
||||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
// Updates
|
||||
comboComment(txtp, fl);
|
||||
m_cComboParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_combo_update(\n",
|
||||
false, true);
|
||||
m_cComboParamsp = new AstTextBlock(
|
||||
fl, "long long " + m_libName + "_protectlib_combo_update(\n", false, true);
|
||||
m_cComboParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodep(m_cComboParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
|
|
@ -310,8 +321,8 @@ class ProtectVisitor : public AstNVisitor {
|
|||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
seqComment(txtp, fl);
|
||||
m_cSeqParamsp = new AstTextBlock(fl, "long long "+m_libName+"_protectlib_seq_update(\n",
|
||||
false, true);
|
||||
m_cSeqParamsp = new AstTextBlock(
|
||||
fl, "long long " + m_libName + "_protectlib_seq_update(\n", false, true);
|
||||
m_cSeqParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodep(m_cSeqParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
|
|
@ -324,8 +335,8 @@ class ProtectVisitor : public AstNVisitor {
|
|||
txtp->addText(fl, "}\n\n");
|
||||
|
||||
comboIgnoreComment(txtp, fl);
|
||||
m_cIgnoreParamsp = new AstTextBlock(fl, "void "+m_libName+"_protectlib_combo_ignore(\n",
|
||||
false, true);
|
||||
m_cIgnoreParamsp = new AstTextBlock(
|
||||
fl, "void " + m_libName + "_protectlib_combo_ignore(\n", false, true);
|
||||
m_cIgnoreParamsp->addText(fl, "void* vhandlep__V\n");
|
||||
txtp->addNodep(m_cIgnoreParamsp);
|
||||
txtp->addText(fl, ")\n");
|
||||
|
|
@ -333,7 +344,7 @@ class ProtectVisitor : public AstNVisitor {
|
|||
|
||||
// Final
|
||||
finalComment(txtp, fl);
|
||||
txtp->addText(fl, "void "+m_libName+"_protectlib_final(void* vhandlep__V) {\n");
|
||||
txtp->addText(fl, "void " + m_libName + "_protectlib_final(void* vhandlep__V) {\n");
|
||||
castPtr(fl, txtp);
|
||||
txtp->addText(fl, "handlep__V->final();\n");
|
||||
txtp->addText(fl, "delete handlep__V;\n");
|
||||
|
|
@ -346,11 +357,11 @@ class ProtectVisitor : public AstNVisitor {
|
|||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (!nodep->isIO()) return;
|
||||
if (VN_IS(nodep->dtypep(), UnpackArrayDType)) {
|
||||
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "<<nodep->prettyNameQ());
|
||||
nodep->v3error("Unsupported: unpacked arrays with protect-lib on "
|
||||
<< nodep->prettyNameQ());
|
||||
}
|
||||
if (nodep->direction() == VDirection::INPUT) {
|
||||
if (nodep->isUsedClock()
|
||||
|| nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
||||
if (nodep->isUsedClock() || nodep->attrClocker() == VVarAttrClocker::CLOCKER_YES) {
|
||||
handleClock(nodep);
|
||||
} else {
|
||||
handleDataInput(nodep);
|
||||
|
|
@ -358,8 +369,8 @@ class ProtectVisitor : public AstNVisitor {
|
|||
} else if (nodep->direction() == VDirection::OUTPUT) {
|
||||
handleOutput(nodep);
|
||||
} else {
|
||||
nodep->v3error("Unsupported: protect-lib port direction: "<<
|
||||
nodep->direction().ascii());
|
||||
nodep->v3error(
|
||||
"Unsupported: protect-lib port direction: " << nodep->direction().ascii());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -369,18 +380,18 @@ class ProtectVisitor : public AstNVisitor {
|
|||
string frstmt;
|
||||
bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt);
|
||||
if (useSetWSvlv) {
|
||||
return frstmt+" handlep__V->"+varp->name()+", "+varp->name()+");\n";
|
||||
return frstmt + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n";
|
||||
}
|
||||
return "handlep__V->"+varp->name()+" = "+frstmt+";\n";
|
||||
return "handlep__V->" + varp->name() + " = " + frstmt + ";\n";
|
||||
}
|
||||
|
||||
void handleClock(AstVar* varp) {
|
||||
FileLine* fl = varp->fileline();
|
||||
handleInput(varp);
|
||||
m_seqPortsp->addNodep(varp->cloneTree(false));
|
||||
m_seqParamsp->addText(fl, varp->name()+"\n");
|
||||
m_clkSensp->addText(fl, "edge("+varp->name()+")");
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_seqParamsp->addText(fl, varp->name() + "\n");
|
||||
m_clkSensp->addText(fl, "edge(" + varp->name() + ")");
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cSeqClksp->addText(fl, cInputConnection(varp));
|
||||
}
|
||||
|
||||
|
|
@ -388,61 +399,76 @@ class ProtectVisitor : public AstNVisitor {
|
|||
FileLine* fl = varp->fileline();
|
||||
handleInput(varp);
|
||||
m_comboPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->name()+"\n");
|
||||
m_comboParamsp->addText(fl, varp->name() + "\n");
|
||||
m_comboIgnorePortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboIgnoreParamsp->addText(fl, varp->name()+"\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_comboIgnoreParamsp->addText(fl, varp->name() + "\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cComboInsp->addText(fl, cInputConnection(varp));
|
||||
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_cIgnoreParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
}
|
||||
|
||||
void handleInput(AstVar* varp) {
|
||||
m_modPortsp->addNodep(varp->cloneTree(false));
|
||||
}
|
||||
void handleInput(AstVar* varp) { m_modPortsp->addNodep(varp->cloneTree(false)); }
|
||||
|
||||
void handleOutput(AstVar* varp) {
|
||||
FileLine* fl = varp->fileline();
|
||||
m_modPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboPortsp->addNodep(varp->cloneTree(false));
|
||||
m_comboParamsp->addText(fl, varp->name()+"_combo__V\n");
|
||||
m_comboParamsp->addText(fl, varp->name() + "_combo__V\n");
|
||||
m_seqPortsp->addNodep(varp->cloneTree(false));
|
||||
m_seqParamsp->addText(fl, varp->name()+"_tmp__V\n");
|
||||
m_seqParamsp->addText(fl, varp->name() + "_tmp__V\n");
|
||||
|
||||
AstNodeDType* comboDtypep = varp->dtypep()->cloneTree(false);
|
||||
m_comboDeclsp->addNodep(comboDtypep);
|
||||
m_comboDeclsp->addText(fl, " "+varp->name()+"_combo__V;\n");
|
||||
m_comboDeclsp->addText(fl, " " + varp->name() + "_combo__V;\n");
|
||||
|
||||
AstNodeDType* seqDtypep = varp->dtypep()->cloneTree(false);
|
||||
m_seqDeclsp->addNodep(seqDtypep);
|
||||
m_seqDeclsp->addText(fl, " "+varp->name()+"_seq__V;\n");
|
||||
m_seqDeclsp->addText(fl, " " + varp->name() + "_seq__V;\n");
|
||||
|
||||
AstNodeDType* tmpDtypep = varp->dtypep()->cloneTree(false);
|
||||
m_tmpDeclsp->addNodep(tmpDtypep);
|
||||
m_tmpDeclsp->addText(fl, " "+varp->name()+"_tmp__V;\n");
|
||||
m_tmpDeclsp->addText(fl, " " + varp->name() + "_tmp__V;\n");
|
||||
|
||||
m_nbAssignsp->addText(fl, varp->name()+"_seq__V <= "+varp->name()+"_tmp__V;\n");
|
||||
m_seqAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_seq__V;\n");
|
||||
m_comboAssignsp->addText(fl, varp->name()+" = "+varp->name()+"_combo__V;\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_nbAssignsp->addText(fl, varp->name() + "_seq__V <= " + varp->name() + "_tmp__V;\n");
|
||||
m_seqAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_seq__V;\n");
|
||||
m_comboAssignsp->addText(fl, varp->name() + " = " + varp->name() + "_combo__V;\n");
|
||||
m_cComboParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cComboOutsp->addText(fl,
|
||||
V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->"));
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false)+"\n");
|
||||
m_cSeqParamsp->addText(fl, varp->dpiArgType(true, false) + "\n");
|
||||
m_cSeqOutsp->addText(fl, V3Task::assignInternalToDpi(varp, true, "", "", "handlep__V->"));
|
||||
}
|
||||
|
||||
public:
|
||||
explicit ProtectVisitor(AstNode* nodep):
|
||||
m_vfilep(NULL), m_cfilep(NULL), m_modPortsp(NULL),
|
||||
m_comboPortsp(NULL), m_seqPortsp(NULL), m_comboIgnorePortsp(NULL), m_comboDeclsp(NULL),
|
||||
m_seqDeclsp(NULL), m_tmpDeclsp(NULL), m_hashValuep(NULL),
|
||||
m_comboParamsp(NULL),
|
||||
m_clkSensp(NULL),
|
||||
m_comboIgnoreParamsp(NULL), m_seqParamsp(NULL), m_nbAssignsp(NULL), m_seqAssignsp(NULL),
|
||||
m_comboAssignsp(NULL), m_cHashValuep(NULL), m_cComboParamsp(NULL), m_cComboInsp(NULL),
|
||||
m_cComboOutsp(NULL), m_cSeqParamsp(NULL), m_cSeqClksp(NULL), m_cSeqOutsp(NULL),
|
||||
m_cIgnoreParamsp(NULL), m_libName(v3Global.opt.protectLib()),
|
||||
m_topName(v3Global.opt.prefix()), m_foundTop(false)
|
||||
{
|
||||
public:
|
||||
explicit ProtectVisitor(AstNode* nodep)
|
||||
: m_vfilep(NULL)
|
||||
, m_cfilep(NULL)
|
||||
, m_modPortsp(NULL)
|
||||
, m_comboPortsp(NULL)
|
||||
, m_seqPortsp(NULL)
|
||||
, m_comboIgnorePortsp(NULL)
|
||||
, m_comboDeclsp(NULL)
|
||||
, m_seqDeclsp(NULL)
|
||||
, m_tmpDeclsp(NULL)
|
||||
, m_hashValuep(NULL)
|
||||
, m_comboParamsp(NULL)
|
||||
, m_clkSensp(NULL)
|
||||
, m_comboIgnoreParamsp(NULL)
|
||||
, m_seqParamsp(NULL)
|
||||
, m_nbAssignsp(NULL)
|
||||
, m_seqAssignsp(NULL)
|
||||
, m_comboAssignsp(NULL)
|
||||
, m_cHashValuep(NULL)
|
||||
, m_cComboParamsp(NULL)
|
||||
, m_cComboInsp(NULL)
|
||||
, m_cComboOutsp(NULL)
|
||||
, m_cSeqParamsp(NULL)
|
||||
, m_cSeqClksp(NULL)
|
||||
, m_cSeqOutsp(NULL)
|
||||
, m_cIgnoreParamsp(NULL)
|
||||
, m_libName(v3Global.opt.protectLib())
|
||||
, m_topName(v3Global.opt.prefix())
|
||||
, m_foundTop(false) {
|
||||
iterate(nodep);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
135
src/V3Scope.cpp
135
src/V3Scope.cpp
|
|
@ -43,8 +43,8 @@ private:
|
|||
// NODE STATE
|
||||
// AstVar::user1p -> AstVarScope replacement for this variable
|
||||
// AstTask::user2p -> AstTask*. Replacement task
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// TYPES
|
||||
typedef vl_unordered_map<AstNodeModule*, AstScope*> PackageScopeMap;
|
||||
|
|
@ -53,26 +53,25 @@ private:
|
|||
typedef std::set<std::pair<AstVarRef*, AstScope*> > VarRefScopeSet;
|
||||
|
||||
// STATE, inside processing a single module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope we are building
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstScope* m_scopep; // Current scope we are building
|
||||
// STATE, for passing down one level of hierarchy (may need save/restore)
|
||||
AstCell* m_aboveCellp; // Cell that instantiates this module
|
||||
AstScope* m_aboveScopep; // Scope that instantiates this scope
|
||||
AstCell* m_aboveCellp; // Cell that instantiates this module
|
||||
AstScope* m_aboveScopep; // Scope that instantiates this scope
|
||||
|
||||
PackageScopeMap m_packageScopes; // Scopes for each package
|
||||
VarScopeMap m_varScopes; // Varscopes created for each scope and var
|
||||
VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when done
|
||||
PackageScopeMap m_packageScopes; // Scopes for each package
|
||||
VarScopeMap m_varScopes; // Varscopes created for each scope and var
|
||||
VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when done
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void cleanupVarRefs() {
|
||||
for (VarRefScopeSet::iterator it = m_varRefScopes.begin();
|
||||
it!=m_varRefScopes.end(); ++it) {
|
||||
for (VarRefScopeSet::iterator it = m_varRefScopes.begin(); it != m_varRefScopes.end();
|
||||
++it) {
|
||||
AstVarRef* nodep = it->first;
|
||||
AstScope* scopep = it->second;
|
||||
if (nodep->packagep()
|
||||
&& !nodep->varp()->isClassMember()) {
|
||||
if (nodep->packagep() && !nodep->varp()->isClassMember()) {
|
||||
PackageScopeMap::iterator it2 = m_packageScopes.find(nodep->packagep());
|
||||
UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope");
|
||||
scopep = it2->second;
|
||||
|
|
@ -87,7 +86,10 @@ private:
|
|||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* modp = nodep->topModulep();
|
||||
if (!modp) { nodep->v3error("No top level module found"); return; }
|
||||
if (!modp) {
|
||||
nodep->v3error("No top level module found");
|
||||
return;
|
||||
}
|
||||
// Operate starting at the top of the hierarchy
|
||||
m_aboveCellp = NULL;
|
||||
m_aboveScopep = NULL;
|
||||
|
|
@ -97,22 +99,25 @@ private:
|
|||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
// Create required blocks and add to module
|
||||
string scopename;
|
||||
if (!m_aboveScopep) scopename = "TOP";
|
||||
else scopename = m_aboveScopep->name()+"."+m_aboveCellp->name();
|
||||
if (!m_aboveScopep) {
|
||||
scopename = "TOP";
|
||||
} else {
|
||||
scopename = m_aboveScopep->name() + "." + m_aboveCellp->name();
|
||||
}
|
||||
|
||||
UINFO(4," MOD AT "<<scopename<<" "<<nodep<<endl);
|
||||
UINFO(4, " MOD AT " << scopename << " " << nodep << endl);
|
||||
AstNode::user1ClearTree();
|
||||
|
||||
m_scopep = new AstScope((m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp)
|
||||
: static_cast<AstNode*>(nodep))
|
||||
->fileline(),
|
||||
nodep, scopename, m_aboveScopep, m_aboveCellp);
|
||||
m_scopep = new AstScope(
|
||||
(m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp) : static_cast<AstNode*>(nodep))
|
||||
->fileline(),
|
||||
nodep, scopename, m_aboveScopep, m_aboveCellp);
|
||||
if (VN_IS(nodep, Package)) {
|
||||
m_packageScopes.insert(make_pair(VN_CAST(nodep, Package), m_scopep));
|
||||
}
|
||||
|
||||
// Now for each child cell, iterate the module this cell points to
|
||||
for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) {
|
||||
for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) {
|
||||
if (AstCell* cellp = VN_CAST(cellnextp, Cell)) {
|
||||
AstScope* oldScopep = m_scopep;
|
||||
AstCell* oldAbCellp = m_aboveCellp;
|
||||
|
|
@ -132,7 +137,7 @@ private:
|
|||
}
|
||||
|
||||
// Create scope for the current usage of this module
|
||||
UINFO(4," back AT "<<scopename<<" "<<nodep<<endl);
|
||||
UINFO(4, " back AT " << scopename << " " << nodep << endl);
|
||||
AstNode::user1ClearTree();
|
||||
m_modp = nodep;
|
||||
if (m_modp->isTop()) {
|
||||
|
|
@ -168,8 +173,8 @@ private:
|
|||
|
||||
AstNode* abovep = (m_aboveCellp ? static_cast<AstNode*>(m_aboveCellp)
|
||||
: static_cast<AstNode*>(nodep));
|
||||
m_scopep = new AstScope(abovep->fileline(),
|
||||
m_modp, scopename, m_aboveScopep, m_aboveCellp);
|
||||
m_scopep
|
||||
= new AstScope(abovep->fileline(), m_modp, scopename, m_aboveScopep, m_aboveCellp);
|
||||
// Create scope for the current usage of this cell
|
||||
AstNode::user1ClearTree();
|
||||
nodep->addMembersp(m_scopep);
|
||||
|
|
@ -181,7 +186,7 @@ private:
|
|||
m_aboveCellp = oldAbCellp;
|
||||
m_aboveScopep = oldAbScopep;
|
||||
}
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCellInline* nodep) VL_OVERRIDE { //
|
||||
nodep->scopep(m_scopep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
|
|
@ -189,7 +194,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstInitial* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -197,7 +202,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstFinal* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -205,7 +210,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -213,7 +218,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
|
||||
// Copy under the scope but don't recurse
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -221,7 +226,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -229,7 +234,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -237,7 +242,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -245,7 +250,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," Move "<<nodep<<endl);
|
||||
UINFO(4, " Move " << nodep << endl);
|
||||
AstNode* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -253,7 +258,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," CFUNC "<<nodep<<endl);
|
||||
UINFO(4, " CFUNC " << nodep << endl);
|
||||
AstCFunc* clonep = nodep->cloneTree(false);
|
||||
nodep->user2p(clonep);
|
||||
m_scopep->addActivep(clonep);
|
||||
|
|
@ -263,7 +268,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
// Add to list of blocks under this scope
|
||||
UINFO(4," FTASK "<<nodep<<endl);
|
||||
UINFO(4, " FTASK " << nodep << endl);
|
||||
AstNodeFTask* clonep;
|
||||
if (nodep->classMethod()) {
|
||||
// Only one scope will be created, so avoid pointless cloning
|
||||
|
|
@ -281,7 +286,7 @@ private:
|
|||
// Make new scope variable
|
||||
if (!nodep->user1p()) {
|
||||
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
|
||||
UINFO(6," New scope "<<varscp<<endl);
|
||||
UINFO(6, " New scope " << varscp << endl);
|
||||
if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
|
||||
nodep->user1p(varscp);
|
||||
if (v3Global.opt.isClocker(varscp->prettyName())) {
|
||||
|
|
@ -307,10 +312,10 @@ private:
|
|||
// So push to a list and post-correct
|
||||
m_varRefScopes.insert(make_pair(nodep, m_scopep));
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
string prefix = string("__DOT__")+m_scopep->name();
|
||||
string prefix = string("__DOT__") + m_scopep->name();
|
||||
// TOP and above will be the user's name().
|
||||
// Note 'TOP.' is stripped by scopePrettyName
|
||||
// To keep correct visual order, must add before other Text's
|
||||
|
|
@ -375,36 +380,16 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE {
|
||||
movedDeleteOrIterate(nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstAssignVarScope* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
virtual void visit(AstCFunc* nodep) VL_OVERRIDE { movedDeleteOrIterate(nodep); }
|
||||
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
// The crossrefs are dealt with in V3LinkDot
|
||||
|
|
@ -412,17 +397,17 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeFTaskRef* nodep) VL_OVERRIDE {
|
||||
// The crossrefs are dealt with in V3LinkDot
|
||||
UINFO(9," Old pkg-taskref "<<nodep<<endl);
|
||||
UINFO(9, " Old pkg-taskref " << nodep << endl);
|
||||
if (nodep->packagep()) {
|
||||
// Point to the clone
|
||||
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked");
|
||||
AstNodeFTask* newp = VN_CAST(nodep->taskp()->user2p(), NodeFTask);
|
||||
UASSERT_OBJ(newp, nodep, "No clone for package function");
|
||||
nodep->taskp(newp);
|
||||
UINFO(9," New pkg-taskref "<<nodep<<endl);
|
||||
UINFO(9, " New pkg-taskref " << nodep << endl);
|
||||
} else if (!VN_IS(nodep, MethodCall)) {
|
||||
nodep->taskp(NULL);
|
||||
UINFO(9," New pkg-taskref "<<nodep<<endl);
|
||||
UINFO(9, " New pkg-taskref " << nodep << endl);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -448,10 +433,10 @@ public:
|
|||
// Scope class functions
|
||||
|
||||
void V3Scope::scopeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
ScopeVisitor visitor (nodep);
|
||||
ScopeCleanupVisitor cleanVisitor (nodep);
|
||||
ScopeVisitor visitor(nodep);
|
||||
ScopeCleanupVisitor cleanVisitor(nodep);
|
||||
} // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("scope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,8 +116,9 @@ private:
|
|||
// Don't grab SenTrees under Actives, only those that are global (under Scope directly)
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE { m_trees.add(nodep); }
|
||||
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE { //
|
||||
m_trees.add(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
||||
|
|
|
|||
303
src/V3Simulate.h
303
src/V3Simulate.h
|
|
@ -89,21 +89,21 @@ private:
|
|||
|
||||
// STATE
|
||||
// Major mode
|
||||
bool m_checkOnly; ///< Checking only (no simulation) mode
|
||||
bool m_scoped; ///< Running with AstVarScopes instead of AstVars
|
||||
bool m_params; ///< Doing parameter propagation
|
||||
bool m_checkOnly; ///< Checking only (no simulation) mode
|
||||
bool m_scoped; ///< Running with AstVarScopes instead of AstVars
|
||||
bool m_params; ///< Doing parameter propagation
|
||||
// Checking:
|
||||
string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
|
||||
AstNode* m_whyNotNodep; ///< First node not optimizable
|
||||
bool m_anyAssignDly; ///< True if found a delayed assignment
|
||||
bool m_anyAssignComb; ///< True if found a non-delayed assignment
|
||||
bool m_inDlyAssign; ///< Under delayed assignment
|
||||
int m_instrCount; ///< Number of nodes
|
||||
int m_dataCount; ///< Bytes of data
|
||||
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
||||
string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
|
||||
AstNode* m_whyNotNodep; ///< First node not optimizable
|
||||
bool m_anyAssignDly; ///< True if found a delayed assignment
|
||||
bool m_anyAssignComb; ///< True if found a non-delayed assignment
|
||||
bool m_inDlyAssign; ///< Under delayed assignment
|
||||
int m_instrCount; ///< Number of nodes
|
||||
int m_dataCount; ///< Bytes of data
|
||||
AstJumpGo* m_jumpp; ///< Jump label we're branching from
|
||||
// Simulating:
|
||||
ConstPile m_constFreeps; ///< List of all AstConst* free and not in use
|
||||
ConstPile m_constAllps; ///< List of all AstConst* free and in use
|
||||
ConstPile m_constFreeps; ///< List of all AstConst* free and not in use
|
||||
ConstPile m_constAllps; ///< List of all AstConst* free and in use
|
||||
std::deque<SimStackNode*> m_callStack; ///< Call stack for verbose error messages
|
||||
|
||||
// Cleanup
|
||||
|
|
@ -116,35 +116,35 @@ private:
|
|||
|
||||
// Potentially very slow, intended for debugging
|
||||
string prettyNumber(const V3Number* nump, AstNodeDType* dtypep) {
|
||||
if (AstRefDType* refdtypep = VN_CAST(dtypep, RefDType)) {
|
||||
if (AstRefDType* refdtypep = VN_CAST(dtypep, RefDType)) { //
|
||||
dtypep = refdtypep->skipRefp();
|
||||
}
|
||||
if (AstStructDType* stp = VN_CAST(dtypep, StructDType)) {
|
||||
if (stp->packed()) {
|
||||
std::ostringstream out;
|
||||
out<<"'{";
|
||||
for (AstMemberDType* itemp = stp->membersp();
|
||||
itemp; itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
||||
out << "'{";
|
||||
for (AstMemberDType* itemp = stp->membersp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), MemberDType)) {
|
||||
int width = itemp->width();
|
||||
int lsb = itemp->lsb();
|
||||
int msb = lsb + width - 1;
|
||||
V3Number fieldNum(nump, width);
|
||||
fieldNum.opSel(*nump, msb, lsb);
|
||||
out<<itemp->name()<<": ";
|
||||
out << itemp->name() << ": ";
|
||||
if (AstNodeDType* childTypep = itemp->subDTypep()) {
|
||||
out<<prettyNumber(&fieldNum, childTypep);
|
||||
out << prettyNumber(&fieldNum, childTypep);
|
||||
} else {
|
||||
out<<fieldNum;
|
||||
out << fieldNum;
|
||||
}
|
||||
if (itemp->nextp()) out<<", ";
|
||||
if (itemp->nextp()) out << ", ";
|
||||
}
|
||||
out<<"}";
|
||||
out << "}";
|
||||
return out.str();
|
||||
}
|
||||
} else if (AstPackArrayDType* arrayp = VN_CAST(dtypep, PackArrayDType)) {
|
||||
if (AstNodeDType* childTypep = arrayp->subDTypep()) {
|
||||
std::ostringstream out;
|
||||
out<<"[";
|
||||
out << "[";
|
||||
int arrayElements = arrayp->elementsConst();
|
||||
for (int element = 0; element < arrayElements; ++element) {
|
||||
int width = childTypep->width();
|
||||
|
|
@ -153,10 +153,10 @@ private:
|
|||
V3Number fieldNum(nump, width);
|
||||
fieldNum.opSel(*nump, msb, lsb);
|
||||
int arrayElem = arrayp->lsb() + element;
|
||||
out<<arrayElem<<" = "<<prettyNumber(&fieldNum, childTypep);
|
||||
if (element < arrayElements - 1) out<<", ";
|
||||
out << arrayElem << " = " << prettyNumber(&fieldNum, childTypep);
|
||||
if (element < arrayElements - 1) out << ", ";
|
||||
}
|
||||
out<<"]";
|
||||
out << "]";
|
||||
return out.str();
|
||||
}
|
||||
}
|
||||
|
|
@ -168,32 +168,31 @@ public:
|
|||
/// Call other-this function on all new *non-constant* var references
|
||||
virtual void varRefCb(AstVarRef* nodep) {}
|
||||
|
||||
void clearOptimizable(AstNode* nodep/*null ok*/, const string& why) {
|
||||
void clearOptimizable(AstNode* nodep /*null ok*/, const string& why) {
|
||||
// Something bad found. optimizable() will return false,
|
||||
// and fetchConst should not be called or it may assert.
|
||||
if (!m_whyNotNodep) {
|
||||
m_whyNotNodep = nodep;
|
||||
if (debug() >= 5) {
|
||||
UINFO(0, "Clear optimizable: "<<why);
|
||||
if (nodep) cout<<": "<<nodep;
|
||||
cout<<endl;
|
||||
UINFO(0, "Clear optimizable: " << why);
|
||||
if (nodep) cout << ": " << nodep;
|
||||
cout << endl;
|
||||
}
|
||||
m_whyNotOptimizable = why;
|
||||
std::ostringstream stack;
|
||||
for (std::deque<SimStackNode*>::iterator it = m_callStack.begin();
|
||||
it != m_callStack.end(); ++it) {
|
||||
AstFuncRef* funcp = (*it)->m_funcp;
|
||||
stack<<"\n "<<funcp->fileline()
|
||||
<<"... Called from "
|
||||
<<funcp->prettyName()<<"() with parameters:";
|
||||
stack << "\n " << funcp->fileline() << "... Called from "
|
||||
<< funcp->prettyName() << "() with parameters:";
|
||||
V3TaskConnects* tconnects = (*it)->m_tconnects;
|
||||
for (V3TaskConnects::iterator conIt = tconnects->begin();
|
||||
conIt != tconnects->end(); ++conIt) {
|
||||
AstVar* portp = conIt->first;
|
||||
AstNode* pinp = conIt->second->exprp();
|
||||
AstNodeDType* dtypep = pinp->dtypep();
|
||||
stack<<"\n "<<portp->prettyName(
|
||||
)<<" = "<<prettyNumber(&fetchConst(pinp)->num(), dtypep);
|
||||
stack << "\n " << portp->prettyName() << " = "
|
||||
<< prettyNumber(&fetchConst(pinp)->num(), dtypep);
|
||||
}
|
||||
}
|
||||
m_whyNotOptimizable += stack.str();
|
||||
|
|
@ -216,11 +215,12 @@ private:
|
|||
AstConst* constp;
|
||||
AstNodeDType* dtypep = nodep->dtypep();
|
||||
if (!m_constFreeps[dtypep].empty()) {
|
||||
//UINFO(7, "Num Reuse "<<nodep->width()<<endl);
|
||||
constp = m_constFreeps[dtypep].back(); m_constFreeps[dtypep].pop_back();
|
||||
// UINFO(7, "Num Reuse " << nodep->width() << endl);
|
||||
constp = m_constFreeps[dtypep].back();
|
||||
m_constFreeps[dtypep].pop_back();
|
||||
constp->num().nodep(nodep);
|
||||
} else {
|
||||
//UINFO(7, "Num New "<<nodep->width()<<endl);
|
||||
// UINFO(7, "Num New " << nodep->width() << endl);
|
||||
constp = new AstConst(nodep->fileline(), AstConst::DtypedValue(), nodep->dtypep(), 0);
|
||||
m_constAllps[constp->dtypep()].push_back(constp);
|
||||
}
|
||||
|
|
@ -228,6 +228,7 @@ private:
|
|||
constp->num().isString(nodep->isString());
|
||||
return constp;
|
||||
}
|
||||
|
||||
public:
|
||||
void newValue(AstNode* nodep, const AstNode* valuep) {
|
||||
if (const AstConst* constp = VN_CAST_CONST(valuep, Const)) {
|
||||
|
|
@ -245,6 +246,7 @@ public:
|
|||
setOutValue(nodep, newTrackedClone(const_cast<AstNode*>(valuep)));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AstNode* newTrackedClone(AstNode* nodep) {
|
||||
AstNode* newp = nodep->cloneTree(false);
|
||||
|
|
@ -271,30 +273,26 @@ private:
|
|||
return fetchOutConst(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AstNode* fetchValueNull(AstNode* nodep) {
|
||||
return nodep->user3p();
|
||||
}
|
||||
AstNode* fetchValueNull(AstNode* nodep) { return nodep->user3p(); }
|
||||
|
||||
private:
|
||||
AstNode* fetchOutValueNull(AstNode* nodep) {
|
||||
return nodep->user2p();
|
||||
}
|
||||
AstConst* fetchConstNull(AstNode* nodep) {
|
||||
return VN_CAST(fetchValueNull(nodep), Const);
|
||||
}
|
||||
AstNode* fetchOutValueNull(AstNode* nodep) { return nodep->user2p(); }
|
||||
AstConst* fetchConstNull(AstNode* nodep) { return VN_CAST(fetchValueNull(nodep), Const); }
|
||||
AstConst* fetchOutConstNull(AstNode* nodep) {
|
||||
return VN_CAST(fetchOutValueNull(nodep), Const);
|
||||
}
|
||||
AstNode* fetchValue(AstNode* nodep) {
|
||||
AstNode* valuep = fetchValueNull(nodep);
|
||||
UASSERT_OBJ(valuep, nodep, "No value found for node.");
|
||||
//UINFO(9, " fetch val "<<*valuep<<" on "<<nodep<<endl);
|
||||
// UINFO(9, " fetch val " << *valuep << " on " << nodep << endl);
|
||||
return valuep;
|
||||
}
|
||||
AstConst* fetchConst(AstNode* nodep) {
|
||||
AstConst* constp = fetchConstNull(nodep);
|
||||
UASSERT_OBJ(constp, nodep, "No value found for node.");
|
||||
//UINFO(9, " fetch num "<<*constp<<" on "<<nodep<<endl);
|
||||
// UINFO(9, " fetch num " << *constp << " on " << nodep << endl);
|
||||
return constp;
|
||||
}
|
||||
AstConst* fetchOutConst(AstNode* nodep) {
|
||||
|
|
@ -302,6 +300,7 @@ private:
|
|||
UASSERT_OBJ(constp, nodep, "No value found for node.");
|
||||
return constp;
|
||||
}
|
||||
|
||||
public:
|
||||
V3Number* fetchNumberNull(AstNode* nodep) {
|
||||
AstConst* constp = fetchConstNull(nodep);
|
||||
|
|
@ -313,15 +312,16 @@ public:
|
|||
if (constp) return &constp->num();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
private:
|
||||
void setValue(AstNode* nodep, const AstNode* valuep) {
|
||||
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
|
||||
UINFO(9, " set val "<<valuep->name()<<" on "<<nodep<<endl);
|
||||
UINFO(9, " set val " << valuep->name() << " on " << nodep << endl);
|
||||
nodep->user3p((void*)valuep);
|
||||
}
|
||||
void setOutValue(AstNode* nodep, const AstNode* valuep) {
|
||||
UASSERT_OBJ(valuep, nodep, "Simulate setting null value");
|
||||
UINFO(9, " set oval "<<valuep->name()<<" on "<<nodep<<endl);
|
||||
UINFO(9, " set oval " << valuep->name() << " on " << nodep << endl);
|
||||
nodep->user2p((void*)valuep);
|
||||
}
|
||||
|
||||
|
|
@ -331,7 +331,7 @@ private:
|
|||
m_dataCount += nodep->width();
|
||||
}
|
||||
if (!nodep->isPredictOptimizable()) {
|
||||
//UINFO(9, " !predictopt "<<nodep<<endl);
|
||||
// UINFO(9, " !predictopt " << nodep << endl);
|
||||
clearOptimizable(nodep, "Isn't predictable");
|
||||
}
|
||||
}
|
||||
|
|
@ -342,17 +342,21 @@ private:
|
|||
if (optimizable()) {
|
||||
// Hmm, what is this then?
|
||||
// In production code, we'll just not optimize. It should be fixed though.
|
||||
clearOptimizable(nodep, "Unknown node type, perhaps missing visitor in SimulateVisitor");
|
||||
clearOptimizable(nodep,
|
||||
"Unknown node type, perhaps missing visitor in SimulateVisitor");
|
||||
#ifdef VL_DEBUG
|
||||
UINFO(0, "Unknown node type in SimulateVisitor: "<<nodep->prettyTypeName()<<endl);
|
||||
UINFO(0, "Unknown node type in SimulateVisitor: " << nodep->prettyTypeName() << endl);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* varOrScope(AstVarRef* nodep) {
|
||||
AstNode* vscp;
|
||||
if (m_scoped) vscp = nodep->varScopep();
|
||||
else vscp = nodep->varp();
|
||||
if (m_scoped) {
|
||||
vscp = nodep->varScopep();
|
||||
} else {
|
||||
vscp = nodep->varp();
|
||||
}
|
||||
UASSERT_OBJ(vscp, nodep, "Not linked");
|
||||
return vscp;
|
||||
}
|
||||
|
|
@ -420,10 +424,9 @@ private:
|
|||
vscp->user1(vscp->user1() | VU_RV);
|
||||
bool isConst = nodep->varp()->isParam() && nodep->varp()->valuep();
|
||||
AstNode* valuep = isConst ? fetchValueNull(nodep->varp()->valuep()) : NULL;
|
||||
if (isConst && valuep) { // Propagate PARAM constants for constant function analysis
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newValue(vscp, valuep);
|
||||
}
|
||||
if (isConst
|
||||
&& valuep) { // Propagate PARAM constants for constant function analysis
|
||||
if (!m_checkOnly && optimizable()) newValue(vscp, valuep);
|
||||
} else {
|
||||
if (m_checkOnly) varRefCb(nodep);
|
||||
}
|
||||
|
|
@ -437,9 +440,11 @@ private:
|
|||
AstNode* valuep = fetchValueNull(vscp);
|
||||
if (!valuep) {
|
||||
if (m_params) {
|
||||
clearOptimizable(nodep, "Language violation: reference to non-function-local variable");
|
||||
clearOptimizable(
|
||||
nodep, "Language violation: reference to non-function-local variable");
|
||||
} else {
|
||||
nodep->v3fatalSrc("Variable value should have been set before any visitor called.");
|
||||
nodep->v3fatalSrc(
|
||||
"Variable value should have been set before any visitor called.");
|
||||
}
|
||||
valuep = allocConst(nodep); // Any value; just so recover from error
|
||||
}
|
||||
|
|
@ -449,12 +454,20 @@ private:
|
|||
}
|
||||
virtual void visit(AstVarXRef* nodep) VL_OVERRIDE {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (m_scoped) { badNodeType(nodep); return; }
|
||||
else { clearOptimizable(nodep, "Language violation: Dotted hierarchical references not allowed in constant functions"); }
|
||||
if (m_scoped) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
} else {
|
||||
clearOptimizable(nodep, "Language violation: Dotted hierarchical references not "
|
||||
"allowed in constant functions");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
}
|
||||
if (nodep->dpiImport()) {
|
||||
clearOptimizable(nodep, "DPI import functions aren't simulatable");
|
||||
}
|
||||
|
|
@ -463,7 +476,7 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
if (jumpingOver(nodep)) return;
|
||||
UINFO(5, " IF "<<nodep<<endl);
|
||||
UINFO(5, " IF " << nodep << endl);
|
||||
checkNodeInfo(nodep);
|
||||
if (m_checkOnly) {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -480,15 +493,11 @@ private:
|
|||
}
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newValue(nodep, nodep);
|
||||
}
|
||||
if (!m_checkOnly && optimizable()) newValue(nodep, nodep);
|
||||
}
|
||||
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newValue(nodep, nodep);
|
||||
}
|
||||
if (!m_checkOnly && optimizable()) newValue(nodep, nodep);
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep) VL_OVERRIDE {
|
||||
checkNodeInfo(nodep);
|
||||
|
|
@ -497,9 +506,7 @@ private:
|
|||
AstNode* valuep = nodep->itemp()->valuep();
|
||||
if (valuep) {
|
||||
iterateAndNextNull(valuep);
|
||||
if (optimizable()) {
|
||||
newValue(nodep, fetchValue(valuep));
|
||||
}
|
||||
if (optimizable()) newValue(nodep, fetchValue(valuep));
|
||||
} else {
|
||||
clearOptimizable(nodep, "No value found for enum item");
|
||||
}
|
||||
|
|
@ -510,8 +517,7 @@ private:
|
|||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
nodep->numberOperate(newConst(nodep)->num(),
|
||||
fetchConst(nodep->lhsp())->num());
|
||||
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep) VL_OVERRIDE {
|
||||
|
|
@ -519,8 +525,7 @@ private:
|
|||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
nodep->numberOperate(newConst(nodep)->num(),
|
||||
fetchConst(nodep->lhsp())->num(),
|
||||
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
|
||||
fetchConst(nodep->rhsp())->num());
|
||||
}
|
||||
}
|
||||
|
|
@ -529,8 +534,7 @@ private:
|
|||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
nodep->numberOperate(newConst(nodep)->num(),
|
||||
fetchConst(nodep->lhsp())->num(),
|
||||
nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(),
|
||||
fetchConst(nodep->rhsp())->num(),
|
||||
fetchConst(nodep->thsp())->num());
|
||||
}
|
||||
|
|
@ -652,7 +656,7 @@ private:
|
|||
}
|
||||
uint32_t index = fetchConst(selp->bitp())->toUInt();
|
||||
AstNode* valuep = newTrackedClone(fetchValue(nodep->rhsp()));
|
||||
UINFO(9, " set val["<<index<<"] = "<<valuep<<endl);
|
||||
UINFO(9, " set val[" << index << "] = " << valuep << endl);
|
||||
// Values are in the "real" tree under the InitArray so can eventually extract it,
|
||||
// Not in the usual setValue (pointed to by user2/3p)
|
||||
initp->addIndexValuep(index, valuep);
|
||||
|
|
@ -664,7 +668,7 @@ private:
|
|||
AstVarRef* varrefp = NULL;
|
||||
V3Number lsb(nodep);
|
||||
iterateAndNextNull(nodep->rhsp()); // Value to assign
|
||||
handleAssignSelRecurse(nodep, selp, varrefp/*ref*/, lsb/*ref*/, 0);
|
||||
handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0);
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
UASSERT_OBJ(varrefp, nodep,
|
||||
"Indicated optimizable, but no variable found on RHS of select");
|
||||
|
|
@ -683,15 +687,12 @@ private:
|
|||
outconstp->num().setAllBitsX();
|
||||
}
|
||||
}
|
||||
outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(),
|
||||
lsb,
|
||||
selp->widthConst());
|
||||
outconstp->num().opSelInto(fetchConst(nodep->rhsp())->num(), lsb, selp->widthConst());
|
||||
assignOutValue(nodep, vscp, outconstp);
|
||||
}
|
||||
}
|
||||
void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp,
|
||||
AstVarRef*& outVarrefpRef, V3Number& lsbRef,
|
||||
int depth) {
|
||||
void handleAssignSelRecurse(AstNodeAssign* nodep, AstSel* selp, AstVarRef*& outVarrefpRef,
|
||||
V3Number& lsbRef, int depth) {
|
||||
// Recurse down to find final variable being set (outVarrefp), with
|
||||
// lsb to be eventually set on lsbRef
|
||||
checkNodeInfo(selp);
|
||||
|
|
@ -702,7 +703,7 @@ private:
|
|||
return; // And presumably still optimizable()
|
||||
} else if (AstSel* subselp = VN_CAST(selp->lhsp(), Sel)) {
|
||||
V3Number sublsb(nodep);
|
||||
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb/*ref*/, depth+1);
|
||||
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb /*ref*/, depth + 1);
|
||||
if (optimizable()) {
|
||||
lsbRef = sublsb;
|
||||
lsbRef.opAdd(sublsb, fetchConst(selp->lsbp())->num());
|
||||
|
|
@ -725,20 +726,22 @@ private:
|
|||
}
|
||||
|
||||
if (AstSel* selp = VN_CAST(nodep->lhsp(), Sel)) {
|
||||
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
||||
if (!m_params) {
|
||||
clearOptimizable(nodep, "LHS has select");
|
||||
return;
|
||||
}
|
||||
handleAssignSel(nodep, selp);
|
||||
}
|
||||
else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) {
|
||||
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
||||
} else if (AstArraySel* selp = VN_CAST(nodep->lhsp(), ArraySel)) {
|
||||
if (!m_params) {
|
||||
clearOptimizable(nodep, "LHS has select");
|
||||
return;
|
||||
}
|
||||
handleAssignArray(nodep, selp);
|
||||
}
|
||||
else if (!VN_IS(nodep->lhsp(), VarRef)) {
|
||||
} else if (!VN_IS(nodep->lhsp(), VarRef)) {
|
||||
clearOptimizable(nodep, "LHS isn't simple variable");
|
||||
}
|
||||
else if (m_checkOnly) {
|
||||
} else if (m_checkOnly) {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
else if (optimizable()) {
|
||||
} else if (optimizable()) {
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
if (optimizable()) {
|
||||
AstNode* vscp = varOrScope(VN_CAST(nodep->lhsp(), VarRef));
|
||||
|
|
@ -756,7 +759,7 @@ private:
|
|||
AstNode* itemp = initp->getIndexDefaultedValuep(offset);
|
||||
if (!itemp) {
|
||||
clearOptimizable(nodep, "Array initialization has too few elements, need element "
|
||||
+cvtToStr(offset));
|
||||
+ cvtToStr(offset));
|
||||
} else {
|
||||
setValue(nodep, itemp);
|
||||
}
|
||||
|
|
@ -770,15 +773,15 @@ private:
|
|||
}
|
||||
virtual void visit(AstNodeCase* nodep) VL_OVERRIDE {
|
||||
if (jumpingOver(nodep)) return;
|
||||
UINFO(5, " CASE "<<nodep<<endl);
|
||||
UINFO(5, " CASE " << nodep << endl);
|
||||
checkNodeInfo(nodep);
|
||||
if (m_checkOnly) {
|
||||
iterateChildren(nodep);
|
||||
} else if (optimizable()) {
|
||||
iterateAndNextNull(nodep->exprp());
|
||||
bool hit = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp=VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (!itemp->isDefault()) {
|
||||
for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) {
|
||||
if (hit) break;
|
||||
|
|
@ -795,8 +798,8 @@ private:
|
|||
}
|
||||
}
|
||||
// Else default match
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (hit) break;
|
||||
if (!hit && itemp->isDefault()) {
|
||||
iterateAndNextNull(itemp->bodysp());
|
||||
|
|
@ -819,7 +822,7 @@ private:
|
|||
if (jumpingOver(nodep)) return;
|
||||
checkNodeInfo(nodep);
|
||||
if (!m_checkOnly) {
|
||||
UINFO(5, " JUMP GO "<<nodep<<endl);
|
||||
UINFO(5, " JUMP GO " << nodep << endl);
|
||||
m_jumpp = nodep;
|
||||
}
|
||||
}
|
||||
|
|
@ -828,7 +831,7 @@ private:
|
|||
checkNodeInfo(nodep);
|
||||
iterateChildren(nodep);
|
||||
if (m_jumpp && m_jumpp->labelp() == nodep) {
|
||||
UINFO(5, " JUMP DONE "<<nodep<<endl);
|
||||
UINFO(5, " JUMP DONE " << nodep << endl);
|
||||
m_jumpp = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -836,15 +839,20 @@ private:
|
|||
if (jumpingOver(nodep)) return;
|
||||
if (m_params) { // This message seems better than an obscure $stop
|
||||
// The spec says $stop is just ignored, it seems evil to ignore assertions
|
||||
clearOptimizable(nodep, "$stop executed during function constification; maybe indicates assertion firing");
|
||||
clearOptimizable(
|
||||
nodep,
|
||||
"$stop executed during function constification; maybe indicates assertion firing");
|
||||
}
|
||||
checkNodeInfo(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeFor* nodep) VL_OVERRIDE {
|
||||
// Doing lots of Whiles is slow, so only for parameters
|
||||
UINFO(5, " FOR "<<nodep<<endl);
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
UINFO(5, " FOR " << nodep << endl);
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
}
|
||||
checkNodeInfo(nodep);
|
||||
if (m_checkOnly) {
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -852,18 +860,18 @@ private:
|
|||
int loops = 0;
|
||||
iterateAndNextNull(nodep->initsp());
|
||||
while (true) {
|
||||
UINFO(5, " FOR-ITER "<<nodep<<endl);
|
||||
UINFO(5, " FOR-ITER " << nodep << endl);
|
||||
iterateAndNextNull(nodep->condp());
|
||||
if (!optimizable()) break;
|
||||
if (!fetchConst(nodep->condp())->num().isNeqZero()) {
|
||||
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
|
||||
break;
|
||||
}
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
iterateAndNextNull(nodep->incsp());
|
||||
if (loops++ > unrollCount()*16) {
|
||||
if (loops++ > unrollCount() * 16) {
|
||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an"
|
||||
"infinite loop, or set --unroll-count above "
|
||||
+ cvtToStr(unrollCount()));
|
||||
"infinite loop, or set --unroll-count above "
|
||||
+ cvtToStr(unrollCount()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -873,21 +881,24 @@ private:
|
|||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||
// Doing lots of Whiles is slow, so only for parameters
|
||||
if (jumpingOver(nodep)) return;
|
||||
UINFO(5, " WHILE "<<nodep<<endl);
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
UINFO(5, " WHILE " << nodep << endl);
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
}
|
||||
checkNodeInfo(nodep);
|
||||
if (m_checkOnly) {
|
||||
iterateChildren(nodep);
|
||||
} else if (optimizable()) {
|
||||
int loops = 0;
|
||||
while (true) {
|
||||
UINFO(5, " WHILE-ITER "<<nodep<<endl);
|
||||
UINFO(5, " WHILE-ITER " << nodep << endl);
|
||||
iterateAndNextNull(nodep->precondsp());
|
||||
if (jumpingOver(nodep)) break;
|
||||
iterateAndNextNull(nodep->condp());
|
||||
if (jumpingOver(nodep)) break;
|
||||
if (!optimizable()) break;
|
||||
if (!fetchConst(nodep->condp())->num().isNeqZero()) {
|
||||
if (!fetchConst(nodep->condp())->num().isNeqZero()) { //
|
||||
break;
|
||||
}
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
|
|
@ -896,9 +907,11 @@ private:
|
|||
if (jumpingOver(nodep)) break;
|
||||
|
||||
// Prep for next loop
|
||||
if (loops++ > unrollCount()*16) {
|
||||
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite"
|
||||
" loop, or set --unroll-count above "+cvtToStr(unrollCount()));
|
||||
if (loops++ > unrollCount() * 16) {
|
||||
clearOptimizable(nodep,
|
||||
"Loop unrolling took too long; probably this is an infinite"
|
||||
" loop, or set --unroll-count above "
|
||||
+ cvtToStr(unrollCount()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -908,12 +921,17 @@ private:
|
|||
virtual void visit(AstFuncRef* nodep) VL_OVERRIDE {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (!optimizable()) return; // Accelerate
|
||||
UINFO(5, " FUNCREF "<<nodep<<endl);
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
UINFO(5, " FUNCREF " << nodep << endl);
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
}
|
||||
AstNodeFTask* funcp = VN_CAST(nodep->taskp(), NodeFTask);
|
||||
UASSERT_OBJ(funcp, nodep, "Not linked");
|
||||
if (m_params) { V3Width::widthParamsEdit(funcp); } VL_DANGLING(funcp); // Make sure we've sized the function
|
||||
funcp = VN_CAST(nodep->taskp(), NodeFTask); UASSERT_OBJ(funcp, nodep, "Not linked");
|
||||
if (m_params) V3Width::widthParamsEdit(funcp);
|
||||
VL_DANGLING(funcp); // Make sure we've sized the function
|
||||
funcp = VN_CAST(nodep->taskp(), NodeFTask);
|
||||
UASSERT_OBJ(funcp, nodep, "Not linked");
|
||||
// Apply function call values to function
|
||||
V3TaskConnects tconnects = V3Task::taskConnects(nodep, nodep->taskp()->stmtsp());
|
||||
// Must do this in two steps, eval all params, then apply them
|
||||
|
|
@ -923,7 +941,9 @@ private:
|
|||
AstNode* pinp = it->second->exprp();
|
||||
if (pinp) { // Else too few arguments in function call - ignore it
|
||||
if (portp->isWritable()) {
|
||||
clearOptimizable(portp, "Language violation: Outputs/refs not allowed in constant functions");
|
||||
clearOptimizable(
|
||||
portp,
|
||||
"Language violation: Outputs/refs not allowed in constant functions");
|
||||
return;
|
||||
}
|
||||
// Evaluate pin value
|
||||
|
|
@ -935,9 +955,7 @@ private:
|
|||
AstNode* pinp = it->second->exprp();
|
||||
if (pinp) { // Else too few arguments in function call - ignore it
|
||||
// Apply value to the function
|
||||
if (!m_checkOnly && optimizable()) {
|
||||
newValue(portp, fetchValue(pinp));
|
||||
}
|
||||
if (!m_checkOnly && optimizable()) newValue(portp, fetchValue(pinp));
|
||||
}
|
||||
}
|
||||
SimStackNode stackNode(nodep, &tconnects);
|
||||
|
|
@ -954,7 +972,10 @@ private:
|
|||
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
if (jumpingOver(nodep)) return;
|
||||
if (!m_params) { badNodeType(nodep); return; }
|
||||
if (!m_params) {
|
||||
badNodeType(nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstScopeName* nodep) VL_OVERRIDE {
|
||||
|
|
@ -986,7 +1007,8 @@ private:
|
|||
nextArgp = nextArgp->nextp();
|
||||
AstConst* constp = fetchConstNull(argp);
|
||||
if (!constp) {
|
||||
clearOptimizable(nodep, "Argument for $display like statement is not constant");
|
||||
clearOptimizable(
|
||||
nodep, "Argument for $display like statement is not constant");
|
||||
break;
|
||||
}
|
||||
string pformat = string("%") + pos[0];
|
||||
|
|
@ -1051,6 +1073,7 @@ private:
|
|||
iterate(nodep);
|
||||
UASSERT_OBJ(!m_jumpp, m_jumpp, "JumpGo branched to label that wasn't found");
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
SimulateVisitor() {
|
||||
|
|
@ -1076,26 +1099,24 @@ public:
|
|||
m_constFreeps = m_constAllps;
|
||||
}
|
||||
void mainTableCheck(AstNode* nodep) {
|
||||
setMode(true/*scoped*/, true/*checking*/, false/*params*/);
|
||||
setMode(true /*scoped*/, true /*checking*/, false /*params*/);
|
||||
mainGuts(nodep);
|
||||
}
|
||||
void mainTableEmulate(AstNode* nodep) {
|
||||
setMode(true/*scoped*/, false/*checking*/, false/*params*/);
|
||||
setMode(true /*scoped*/, false /*checking*/, false /*params*/);
|
||||
mainGuts(nodep);
|
||||
}
|
||||
void mainCheckTree(AstNode* nodep) {
|
||||
setMode(false/*scoped*/, true/*checking*/, false/*params*/);
|
||||
setMode(false /*scoped*/, true /*checking*/, false /*params*/);
|
||||
mainGuts(nodep);
|
||||
}
|
||||
void mainParamEmulate(AstNode* nodep) {
|
||||
setMode(false/*scoped*/, false/*checking*/, true/*params*/);
|
||||
setMode(false /*scoped*/, false /*checking*/, true /*params*/);
|
||||
mainGuts(nodep);
|
||||
}
|
||||
virtual ~SimulateVisitor() {
|
||||
for (ConstPile::iterator it = m_constAllps.begin();
|
||||
it != m_constAllps.end(); ++it) {
|
||||
for (ConstDeque::iterator it2 = it->second.begin();
|
||||
it2 != it->second.end(); ++it2) {
|
||||
for (ConstPile::iterator it = m_constAllps.begin(); it != m_constAllps.end(); ++it) {
|
||||
for (ConstDeque::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) {
|
||||
delete (*it2);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
143
src/V3Slice.cpp
143
src/V3Slice.cpp
|
|
@ -52,11 +52,11 @@ class SliceVisitor : public AstNVisitor {
|
|||
// AstNodeAssign::user1() -> bool. True if find is complete
|
||||
// AstNodeUniop::user1() -> bool. True if find is complete
|
||||
// AstArraySel::user1p() -> AstVarRef. The VarRef that the final ArraySel points to
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNode* m_assignp; // Assignment we are under
|
||||
bool m_assignError; // True if the current assign already has an error
|
||||
AstNode* m_assignp; // Assignment we are under
|
||||
bool m_assignError; // True if the current assign already has an error
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -66,54 +66,59 @@ class SliceVisitor : public AstNVisitor {
|
|||
AstUnpackArrayDType* arrayp = VN_CAST(nodep->dtypep()->skipRefp(), UnpackArrayDType);
|
||||
if (!arrayp) { // V3Width should have complained, but...
|
||||
if (!m_assignError) {
|
||||
nodep->v3error(nodep->prettyTypeName()
|
||||
<<" is not an unpacked array, but is in an unpacked array context");
|
||||
nodep->v3error(
|
||||
nodep->prettyTypeName()
|
||||
<< " is not an unpacked array, but is in an unpacked array context");
|
||||
}
|
||||
m_assignError = true;
|
||||
return nodep->cloneTree(false); // Likely will cause downstream errors
|
||||
}
|
||||
if (arrayp->rangep()->elementsConst() != elements) {
|
||||
if (!m_assignError) nodep->v3error("Slices of arrays in assignments have different unpacked dimensions, "
|
||||
<<elements<<" versus "
|
||||
<<arrayp->rangep()->elementsConst());
|
||||
if (!m_assignError) {
|
||||
nodep->v3error(
|
||||
"Slices of arrays in assignments have different unpacked dimensions, "
|
||||
<< elements << " versus " << arrayp->rangep()->elementsConst());
|
||||
}
|
||||
m_assignError = true;
|
||||
elements = 1; offset = 0;
|
||||
elements = 1;
|
||||
offset = 0;
|
||||
}
|
||||
AstNode* newp;
|
||||
if (AstInitArray* initp = VN_CAST(nodep, InitArray)) {
|
||||
UINFO(9," cloneInitArray("<<elements<<","<<offset<<") "<<nodep<<endl);
|
||||
UINFO(9, " cloneInitArray(" << elements << "," << offset << ") " << nodep << endl);
|
||||
int leOffset = !arrayp->rangep()->littleEndian()
|
||||
? arrayp->rangep()->elementsConst()-1-offset : offset;
|
||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
||||
: offset;
|
||||
AstNode* itemp = initp->getIndexDefaultedValuep(leOffset);
|
||||
if (!itemp) {
|
||||
nodep->v3error("Array initialization has too few elements, need element "<<offset);
|
||||
nodep->v3error("Array initialization has too few elements, need element "
|
||||
<< offset);
|
||||
itemp = initp->initsp();
|
||||
}
|
||||
newp = itemp->cloneTree(false);
|
||||
}
|
||||
else if (AstNodeCond* snodep = VN_CAST(nodep, NodeCond)) {
|
||||
UINFO(9," cloneCond("<<elements<<","<<offset<<") "<<nodep<<endl);
|
||||
} else if (AstNodeCond* snodep = VN_CAST(nodep, NodeCond)) {
|
||||
UINFO(9, " cloneCond(" << elements << "," << offset << ") " << nodep << endl);
|
||||
return snodep->cloneType(snodep->condp()->cloneTree(false),
|
||||
cloneAndSel(snodep->expr1p(), elements, offset),
|
||||
cloneAndSel(snodep->expr2p(), elements, offset));
|
||||
}
|
||||
else if (AstSliceSel* snodep = VN_CAST(nodep, SliceSel)) {
|
||||
UINFO(9," cloneSliceSel("<<elements<<","<<offset<<") "<<nodep<<endl);
|
||||
} else if (AstSliceSel* snodep = VN_CAST(nodep, SliceSel)) {
|
||||
UINFO(9, " cloneSliceSel(" << elements << "," << offset << ") " << nodep << endl);
|
||||
int leOffset = (snodep->declRange().lo()
|
||||
+ (!snodep->declRange().littleEndian()
|
||||
? snodep->declRange().elements()-1-offset : offset));
|
||||
? snodep->declRange().elements() - 1 - offset
|
||||
: offset));
|
||||
newp = new AstArraySel(nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset);
|
||||
}
|
||||
else if (VN_IS(nodep, ArraySel)
|
||||
|| VN_IS(nodep, NodeVarRef)
|
||||
|| VN_IS(nodep, NodeSel)) {
|
||||
UINFO(9," cloneSel("<<elements<<","<<offset<<") "<<nodep<<endl);
|
||||
} else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel)) {
|
||||
UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl);
|
||||
int leOffset = !arrayp->rangep()->littleEndian()
|
||||
? arrayp->rangep()->elementsConst()-1-offset : offset;
|
||||
? arrayp->rangep()->elementsConst() - 1 - offset
|
||||
: offset;
|
||||
newp = new AstArraySel(nodep->fileline(), nodep->cloneTree(false), leOffset);
|
||||
}
|
||||
else {
|
||||
if (!m_assignError) nodep->v3error(nodep->prettyTypeName()<<" unexpected in assignment to unpacked array");
|
||||
} else {
|
||||
if (!m_assignError) {
|
||||
nodep->v3error(nodep->prettyTypeName()
|
||||
<< " unexpected in assignment to unpacked array");
|
||||
}
|
||||
m_assignError = true;
|
||||
newp = nodep->cloneTree(false); // Likely will cause downstream errors
|
||||
}
|
||||
|
|
@ -122,11 +127,13 @@ class SliceVisitor : public AstNVisitor {
|
|||
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
// Called recursively on newly created assignments
|
||||
if (!nodep->user1()
|
||||
&& !VN_IS(nodep, AssignAlias)) {
|
||||
if (!nodep->user1() && !VN_IS(nodep, AssignAlias)) {
|
||||
nodep->user1(true);
|
||||
m_assignError = false;
|
||||
if (debug()>=9) { cout<<endl; nodep->dumpTree(cout, " Deslice-In: "); }
|
||||
if (debug() >= 9) {
|
||||
cout << endl;
|
||||
nodep->dumpTree(cout, " Deslice-In: ");
|
||||
}
|
||||
AstNodeDType* dtp = nodep->lhsp()->dtypep()->skipRefp();
|
||||
if (AstUnpackArrayDType* arrayp = VN_CAST(dtp, UnpackArrayDType)) {
|
||||
// Left and right could have different msb/lsbs/endianness, but #elements is common
|
||||
|
|
@ -136,13 +143,17 @@ class SliceVisitor : public AstNVisitor {
|
|||
int elements = arrayp->rangep()->elementsConst();
|
||||
for (int offset = 0; offset < elements; ++offset) {
|
||||
AstNode* newp = nodep->cloneType // AstNodeAssign
|
||||
(cloneAndSel(nodep->lhsp(), elements, offset),
|
||||
cloneAndSel(nodep->rhsp(), elements, offset));
|
||||
if (debug()>=9) { newp->dumpTree(cout, "-new "); }
|
||||
(cloneAndSel(nodep->lhsp(), elements, offset),
|
||||
cloneAndSel(nodep->rhsp(), elements, offset));
|
||||
if (debug() >= 9) { newp->dumpTree(cout, "-new "); }
|
||||
newlistp = AstNode::addNextNull(newlistp, newp);
|
||||
}
|
||||
if (debug()>=9) { cout<<endl; nodep->dumpTree(cout, " Deslice-Dn: "); }
|
||||
nodep->replaceWith(newlistp); VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (debug() >= 9) {
|
||||
cout << endl;
|
||||
nodep->dumpTree(cout, " Deslice-Dn: ");
|
||||
}
|
||||
nodep->replaceWith(newlistp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
// Normal edit iterator will now iterate on all of the expansion assignments
|
||||
// This will potentially call this function again to resolve next level of slicing
|
||||
return;
|
||||
|
|
@ -154,8 +165,7 @@ class SliceVisitor : public AstNVisitor {
|
|||
}
|
||||
|
||||
virtual void visit(AstInitArray* nodep) VL_OVERRIDE {
|
||||
UASSERT_OBJ(!m_assignp, nodep,
|
||||
"Array initialization should have been removed earlier");
|
||||
UASSERT_OBJ(!m_assignp, nodep, "Array initialization should have been removed earlier");
|
||||
}
|
||||
|
||||
void expandBiOp(AstNodeBiop* nodep) {
|
||||
|
|
@ -163,30 +173,31 @@ class SliceVisitor : public AstNVisitor {
|
|||
nodep->user1(true);
|
||||
// If it's an unpacked array, blow it up into comparing each element
|
||||
AstNodeDType* fromDtp = nodep->lhsp()->dtypep()->skipRefp();
|
||||
UINFO(9, " Bi-Eq/Neq expansion "<<nodep<<endl);
|
||||
UINFO(9, " Bi-Eq/Neq expansion " << nodep << endl);
|
||||
if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
|
||||
AstNodeBiop* logp = NULL;
|
||||
if (!VN_IS(nodep->lhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
nodep->lhsp()->v3error("Slice operator "<<nodep->lhsp()->prettyTypeName()
|
||||
<<" on non-slicable (e.g. non-vector) left-hand-side operand");
|
||||
}
|
||||
else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
nodep->rhsp()->v3error("Slice operator "<<nodep->rhsp()->prettyTypeName()
|
||||
<<" on non-slicable (e.g. non-vector) right-hand-side operand");
|
||||
}
|
||||
else {
|
||||
nodep->lhsp()->v3error(
|
||||
"Slice operator "
|
||||
<< nodep->lhsp()->prettyTypeName()
|
||||
<< " on non-slicable (e.g. non-vector) left-hand-side operand");
|
||||
} else if (!VN_IS(nodep->rhsp()->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
nodep->rhsp()->v3error(
|
||||
"Slice operator "
|
||||
<< nodep->rhsp()->prettyTypeName()
|
||||
<< " on non-slicable (e.g. non-vector) right-hand-side operand");
|
||||
} else {
|
||||
for (int index = 0; index < adtypep->rangep()->elementsConst(); ++index) {
|
||||
// EQ(a,b) -> LOGAND(EQ(ARRAYSEL(a,0), ARRAYSEL(b,0)), ...[1])
|
||||
AstNodeBiop* clonep
|
||||
= VN_CAST(nodep->cloneType
|
||||
(new AstArraySel(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
index),
|
||||
new AstArraySel(nodep->fileline(),
|
||||
nodep->rhsp()->cloneTree(false),
|
||||
index)),
|
||||
= VN_CAST(nodep->cloneType(
|
||||
new AstArraySel(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false), index),
|
||||
new AstArraySel(nodep->fileline(),
|
||||
nodep->rhsp()->cloneTree(false), index)),
|
||||
NodeBiop);
|
||||
if (!logp) logp = clonep;
|
||||
if (!logp)
|
||||
logp = clonep;
|
||||
else {
|
||||
switch (nodep->type()) {
|
||||
case AstType::atEq: // FALLTHRU
|
||||
|
|
@ -212,18 +223,10 @@ class SliceVisitor : public AstNVisitor {
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstEq* nodep) VL_OVERRIDE {
|
||||
expandBiOp(nodep);
|
||||
}
|
||||
virtual void visit(AstNeq* nodep) VL_OVERRIDE {
|
||||
expandBiOp(nodep);
|
||||
}
|
||||
virtual void visit(AstEqCase* nodep) VL_OVERRIDE {
|
||||
expandBiOp(nodep);
|
||||
}
|
||||
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE {
|
||||
expandBiOp(nodep);
|
||||
}
|
||||
virtual void visit(AstEq* nodep) VL_OVERRIDE { expandBiOp(nodep); }
|
||||
virtual void visit(AstNeq* nodep) VL_OVERRIDE { expandBiOp(nodep); }
|
||||
virtual void visit(AstEqCase* nodep) VL_OVERRIDE { expandBiOp(nodep); }
|
||||
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { expandBiOp(nodep); }
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
||||
|
|
@ -241,9 +244,7 @@ public:
|
|||
// Link class functions
|
||||
|
||||
void V3Slice::sliceAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
SliceVisitor visitor(nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ SliceVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("slice", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
245
src/V3Split.cpp
245
src/V3Split.cpp
|
|
@ -97,18 +97,19 @@
|
|||
// Support classes
|
||||
|
||||
class SplitNodeVertex : public V3GraphVertex {
|
||||
AstNode* m_nodep;
|
||||
AstNode* m_nodep;
|
||||
|
||||
protected:
|
||||
SplitNodeVertex(V3Graph* graphp, AstNode* nodep)
|
||||
: V3GraphVertex(graphp), m_nodep(nodep) {}
|
||||
: V3GraphVertex(graphp)
|
||||
, m_nodep(nodep) {}
|
||||
virtual ~SplitNodeVertex() {}
|
||||
// ACCESSORS
|
||||
// Do not make accessor for nodep(), It may change due to
|
||||
// reordering a lower block, but we don't repair it
|
||||
virtual string name() const {
|
||||
return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName();
|
||||
}
|
||||
virtual string name() const { return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); }
|
||||
virtual FileLine* fileline() const { return nodep()->fileline(); }
|
||||
|
||||
public:
|
||||
virtual AstNode* nodep() const { return m_nodep; }
|
||||
};
|
||||
|
|
@ -143,7 +144,7 @@ public:
|
|||
SplitVarPostVertex(V3Graph* graphp, AstNode* nodep)
|
||||
: SplitNodeVertex(graphp, nodep) {}
|
||||
virtual ~SplitVarPostVertex() {}
|
||||
virtual string name() const { return string("POST ")+SplitNodeVertex::name(); }
|
||||
virtual string name() const { return string("POST ") + SplitNodeVertex::name(); }
|
||||
virtual string dotColor() const { return "CadetBlue"; }
|
||||
};
|
||||
|
||||
|
|
@ -155,11 +156,12 @@ class SplitEdge : public V3GraphEdge {
|
|||
static uint32_t s_stepNum; // Global step number
|
||||
protected:
|
||||
enum { WEIGHT_NORMAL = 10 };
|
||||
SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
|
||||
int weight, bool cutable=CUTABLE)
|
||||
SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight,
|
||||
bool cutable = CUTABLE)
|
||||
: V3GraphEdge(graphp, fromp, top, weight, cutable)
|
||||
, m_ignoreInStep(0) {}
|
||||
virtual ~SplitEdge() {}
|
||||
|
||||
public:
|
||||
// Iterator for graph functions
|
||||
static void incrementStep() { ++s_stepNum; }
|
||||
|
|
@ -181,7 +183,7 @@ public:
|
|||
return ignoreThisStep() ? "dotted" : V3GraphEdge::dotStyle();
|
||||
}
|
||||
};
|
||||
uint32_t SplitEdge::s_stepNum = 0;
|
||||
uint32_t SplitEdge::s_stepNum = 0;
|
||||
|
||||
class SplitPostEdge : public SplitEdge {
|
||||
public:
|
||||
|
|
@ -240,28 +242,26 @@ private:
|
|||
// AstVarScope::user2p -> Var SplitNodeVertex* for delayed assignment var, 0=not set yet
|
||||
// Ast*::user3p -> Statement SplitLogicVertex* (temporary only)
|
||||
// Ast*::user4 -> Current ordering number (reorderBlock usage)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
AstUser4InUse m_inuser4;
|
||||
|
||||
protected:
|
||||
// TYPES
|
||||
typedef std::vector<SplitLogicVertex*> VStack;
|
||||
|
||||
// STATE
|
||||
string m_noReorderWhy; // Reason we can't reorder
|
||||
VStack m_stmtStackps; // Current statements being tracked
|
||||
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
bool m_inDly; // Inside ASSIGNDLY
|
||||
VDouble0 m_statSplits; // Statistic tracking
|
||||
string m_noReorderWhy; // Reason we can't reorder
|
||||
VStack m_stmtStackps; // Current statements being tracked
|
||||
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
bool m_inDly; // Inside ASSIGNDLY
|
||||
VDouble0 m_statSplits; // Statistic tracking
|
||||
|
||||
// CONSTRUCTORS
|
||||
public:
|
||||
SplitReorderBaseVisitor() {
|
||||
scoreboardClear();
|
||||
}
|
||||
SplitReorderBaseVisitor() { scoreboardClear(); }
|
||||
virtual ~SplitReorderBaseVisitor() {
|
||||
V3Stats::addStat("Optimizations, Split always", m_statSplits);
|
||||
}
|
||||
|
|
@ -271,7 +271,7 @@ protected:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
void scoreboardClear() {
|
||||
//VV***** We reset user1p() and user2p on each block!!!
|
||||
// VV***** We reset user1p() and user2p on each block!!!
|
||||
m_inDly = false;
|
||||
m_graph.clear();
|
||||
m_stmtStackps.clear();
|
||||
|
|
@ -298,14 +298,14 @@ private:
|
|||
}
|
||||
}
|
||||
void scoreboardPushStmt(AstNode* nodep) {
|
||||
//UINFO(9," push "<<nodep<<endl);
|
||||
// UINFO(9, " push " << nodep << endl);
|
||||
SplitLogicVertex* vertexp = new SplitLogicVertex(&m_graph, nodep);
|
||||
m_stmtStackps.push_back(vertexp);
|
||||
UASSERT_OBJ(!nodep->user3p(), nodep, "user3p should not be used; cleared in processBlock");
|
||||
nodep->user3p(vertexp);
|
||||
}
|
||||
void scoreboardPopStmt() {
|
||||
//UINFO(9," pop"<<endl);
|
||||
// UINFO(9, " pop" << endl);
|
||||
if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow");
|
||||
m_stmtStackps.pop_back();
|
||||
}
|
||||
|
|
@ -313,7 +313,7 @@ private:
|
|||
protected:
|
||||
void scanBlock(AstNode* nodep) {
|
||||
// Iterate across current block, making the scoreboard
|
||||
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
|
||||
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
|
||||
scoreboardPushStmt(nextp);
|
||||
iterate(nextp);
|
||||
scoreboardPopStmt();
|
||||
|
|
@ -321,17 +321,15 @@ protected:
|
|||
}
|
||||
|
||||
void pruneDepsOnInputs() {
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
if (!vertexp->outBeginp()
|
||||
&& dynamic_cast<SplitVarStdVertex*>(vertexp)) {
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (!vertexp->outBeginp() && dynamic_cast<SplitVarStdVertex*>(vertexp)) {
|
||||
if (debug() >= 9) {
|
||||
SplitVarStdVertex* stdp = static_cast<SplitVarStdVertex*>(vertexp);
|
||||
UINFO(0, "Will prune deps on var "<<stdp->nodep()<<endl);
|
||||
UINFO(0, "Will prune deps on var " << stdp->nodep() << endl);
|
||||
stdp->nodep()->dumpTree(cout, "- ");
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp();
|
||||
edgep; edgep=edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
|
|
@ -350,7 +348,7 @@ protected:
|
|||
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
m_inDly = true;
|
||||
UINFO(4," ASSIGNDLY "<<nodep<<endl);
|
||||
UINFO(4, " ASSIGNDLY " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
m_inDly = false;
|
||||
}
|
||||
|
|
@ -386,7 +384,7 @@ protected:
|
|||
|
||||
// SPEEDUP: We add duplicate edges, that should be fixed
|
||||
if (m_inDly && nodep->lvalue()) {
|
||||
UINFO(4," VARREFDLY: "<<nodep<<endl);
|
||||
UINFO(4, " VARREFDLY: " << nodep << endl);
|
||||
// Delayed variable is different from non-delayed variable
|
||||
if (!vscp->user2p()) {
|
||||
SplitVarPostVertex* vpostp = new SplitVarPostVertex(&m_graph, vscp);
|
||||
|
|
@ -396,21 +394,21 @@ protected:
|
|||
SplitVarPostVertex* vpostp
|
||||
= reinterpret_cast<SplitVarPostVertex*>(vscp->user2p());
|
||||
// Add edges
|
||||
for (VStack::iterator it = m_stmtStackps.begin();
|
||||
it != m_stmtStackps.end(); ++it) {
|
||||
for (VStack::iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end();
|
||||
++it) {
|
||||
new SplitLVEdge(&m_graph, vpostp, *it);
|
||||
}
|
||||
} else { // Nondelayed assignment
|
||||
if (nodep->lvalue()) {
|
||||
// Non-delay; need to maintain existing ordering
|
||||
// with all consumers of the signal
|
||||
UINFO(4," VARREFLV: "<<nodep<<endl);
|
||||
UINFO(4, " VARREFLV: " << nodep << endl);
|
||||
for (VStack::iterator it = m_stmtStackps.begin();
|
||||
it != m_stmtStackps.end(); ++it) {
|
||||
new SplitLVEdge(&m_graph, vstdp, *it);
|
||||
}
|
||||
} else {
|
||||
UINFO(4," VARREF: "<<nodep<<endl);
|
||||
UINFO(4, " VARREF: " << nodep << endl);
|
||||
makeRvalueEdges(vstdp);
|
||||
}
|
||||
}
|
||||
|
|
@ -423,7 +421,7 @@ protected:
|
|||
// This is overly pessimistic; we could treat jumps as barriers, and
|
||||
// reorder everything between jumps/labels, however jumps are rare
|
||||
// in always, so the performance gain probably isn't worth the work.
|
||||
UINFO(9," NoReordering "<<nodep<<endl);
|
||||
UINFO(9, " NoReordering " << nodep << endl);
|
||||
m_noReorderWhy = "JumpGo";
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -433,7 +431,7 @@ protected:
|
|||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
// **** SPECIAL default type that sets PLI_ORDERING
|
||||
if (!m_stmtStackps.empty() && !nodep->isPure()) {
|
||||
UINFO(9," NotSplittable "<<nodep<<endl);
|
||||
UINFO(9, " NotSplittable " << nodep << endl);
|
||||
scoreboardPli(nodep);
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -446,9 +444,7 @@ private:
|
|||
class ReorderVisitor : public SplitReorderBaseVisitor {
|
||||
// CONSTRUCTORS
|
||||
public:
|
||||
explicit ReorderVisitor(AstNetlist* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit ReorderVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ReorderVisitor() {}
|
||||
|
||||
// METHODS
|
||||
|
|
@ -461,18 +457,18 @@ protected:
|
|||
|
||||
void cleanupBlockGraph(AstNode* nodep) {
|
||||
// Transform the graph into what we need
|
||||
UINFO(5, "ReorderBlock "<<nodep<<endl);
|
||||
UINFO(5, "ReorderBlock " << nodep << endl);
|
||||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue);
|
||||
|
||||
if (debug()>=9) {
|
||||
if (debug() >= 9) {
|
||||
m_graph.dumpDotFilePrefixed("reorderg_nodup", false);
|
||||
//m_graph.dump(); cout<<endl;
|
||||
// m_graph.dump(); cout<<endl;
|
||||
}
|
||||
|
||||
// Mark all the logic for this step
|
||||
// Vertex::m_user begin: true indicates logic for this step
|
||||
m_graph.userClearVertices();
|
||||
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
|
||||
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
|
||||
SplitLogicVertex* vvertexp = reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
|
||||
vvertexp->user(true);
|
||||
}
|
||||
|
|
@ -484,16 +480,17 @@ protected:
|
|||
|
||||
// For reordering this single block only, mark all logic
|
||||
// vertexes not involved with this step as unimportant
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
if (SplitLogicVertex* vvertexp = dynamic_cast<SplitLogicVertex*>(vertexp)) {
|
||||
if (!vvertexp->user()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep=edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp();
|
||||
edgep; edgep=edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep;
|
||||
edgep = edgep->outNextp()) {
|
||||
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
|
|
@ -507,7 +504,7 @@ protected:
|
|||
|
||||
// Add hard orderings between all nodes of same color, in the order they appeared
|
||||
vl_unordered_map<uint32_t, SplitLogicVertex*> lastOfColor;
|
||||
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
|
||||
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
|
||||
SplitLogicVertex* vvertexp = reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
|
||||
uint32_t color = vvertexp->color();
|
||||
UASSERT_OBJ(color, nextp, "No node color assigned");
|
||||
|
|
@ -520,20 +517,20 @@ protected:
|
|||
// And a real ordering to get the statements into something reasonable
|
||||
// We don't care if there's cutable violations here...
|
||||
// Non-cutable violations should be impossible; as those edges are program-order
|
||||
if (debug()>=9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false);
|
||||
if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false);
|
||||
m_graph.acyclic(&SplitEdge::followCyclic);
|
||||
m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive
|
||||
if (debug()>=9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false);
|
||||
if (debug() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false);
|
||||
}
|
||||
|
||||
void reorderBlock(AstNode* nodep) {
|
||||
// Reorder statements in the completed graph
|
||||
|
||||
// Map the rank numbers into nodes they associate with
|
||||
typedef std::multimap<uint32_t,AstNode*> RankNodeMap;
|
||||
typedef std::multimap<uint32_t, AstNode*> RankNodeMap;
|
||||
RankNodeMap rankMap;
|
||||
int currOrder = 0; // Existing sequence number of assignment
|
||||
for (AstNode* nextp=nodep; nextp; nextp=nextp->nextp()) {
|
||||
for (AstNode* nextp = nodep; nextp; nextp = nextp->nextp()) {
|
||||
SplitLogicVertex* vvertexp = reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
|
||||
rankMap.insert(make_pair(vvertexp->rank(), nextp));
|
||||
nextp->user4(++currOrder); // Record current ordering
|
||||
|
|
@ -542,23 +539,28 @@ protected:
|
|||
// Is the current ordering OK?
|
||||
bool leaveAlone = true;
|
||||
int newOrder = 0; // New sequence number of assignment
|
||||
for (RankNodeMap::const_iterator it = rankMap.begin();
|
||||
it != rankMap.end(); ++it) {
|
||||
for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
|
||||
AstNode* nextp = it->second;
|
||||
if (++newOrder != nextp->user4()) leaveAlone = false;
|
||||
}
|
||||
if (leaveAlone) {
|
||||
UINFO(6," No changes\n");
|
||||
UINFO(6, " No changes\n");
|
||||
} else {
|
||||
AstNRelinker replaceHandle; // Where to add the list
|
||||
AstNode* newListp = NULL;
|
||||
for (RankNodeMap::const_iterator it = rankMap.begin(); it != rankMap.end(); ++it) {
|
||||
AstNode* nextp = it->second;
|
||||
UINFO(6, " New order: "<<nextp<<endl);
|
||||
if (nextp == nodep) nodep->unlinkFrBack(&replaceHandle);
|
||||
else nextp->unlinkFrBack();
|
||||
if (newListp) newListp = newListp->addNext(nextp);
|
||||
else newListp = nextp;
|
||||
UINFO(6, " New order: " << nextp << endl);
|
||||
if (nextp == nodep) {
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
} else {
|
||||
nextp->unlinkFrBack();
|
||||
}
|
||||
if (newListp) {
|
||||
newListp = newListp->addNext(nextp);
|
||||
} else {
|
||||
newListp = nextp;
|
||||
}
|
||||
}
|
||||
replaceHandle.relink(newListp);
|
||||
}
|
||||
|
|
@ -579,19 +581,19 @@ protected:
|
|||
// Just one, so can't reorder. Just look for more blocks/statements.
|
||||
iterate(nodep);
|
||||
} else {
|
||||
UINFO(9," processBlock "<<nodep<<endl);
|
||||
UINFO(9, " processBlock " << nodep << endl);
|
||||
// Process block and followers
|
||||
scanBlock(nodep);
|
||||
if (m_noReorderWhy != "") { // Jump or something nasty
|
||||
UINFO(9," NoReorderBlock because "<<m_noReorderWhy<<endl);
|
||||
UINFO(9, " NoReorderBlock because " << m_noReorderWhy << endl);
|
||||
} else {
|
||||
// Reorder statements in this block
|
||||
cleanupBlockGraph(nodep);
|
||||
reorderBlock(nodep);
|
||||
// Delete old vertexes and edges only applying to this block
|
||||
// First, walk back to first in list
|
||||
while (firstp->backp()->nextp()==firstp) firstp = firstp->backp();
|
||||
for (AstNode* nextp=firstp; nextp; nextp=nextp->nextp()) {
|
||||
while (firstp->backp()->nextp() == firstp) firstp = firstp->backp();
|
||||
for (AstNode* nextp = firstp; nextp; nextp = nextp->nextp()) {
|
||||
SplitLogicVertex* vvertexp
|
||||
= reinterpret_cast<SplitLogicVertex*>(nextp->user3p());
|
||||
vvertexp->unlinkDelete(&m_graph);
|
||||
|
|
@ -603,19 +605,20 @@ protected:
|
|||
}
|
||||
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout, " alwIn:: ");
|
||||
UINFO(4, " ALW " << nodep << endl);
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " alwIn:: ");
|
||||
scoreboardClear();
|
||||
processBlock(nodep->bodysp());
|
||||
if (debug()>=9) nodep->dumpTree(cout, " alwOut: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " alwOut: ");
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
UINFO(4," IF "<<nodep<<endl);
|
||||
UINFO(4, " IF " << nodep << endl);
|
||||
iterateAndNextNull(nodep->condp());
|
||||
processBlock(nodep->ifsp());
|
||||
processBlock(nodep->elsesp());
|
||||
}
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(ReorderVisitor);
|
||||
};
|
||||
|
|
@ -638,9 +641,7 @@ class IfColorVisitor : public AstNVisitor {
|
|||
public:
|
||||
// Visit through *nodep and map each AstNodeIf within to the set of
|
||||
// colors it will participate in. Also find the whole set of colors.
|
||||
explicit IfColorVisitor(AstAlways* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
explicit IfColorVisitor(AstAlways* nodep) { iterate(nodep); }
|
||||
virtual ~IfColorVisitor() {}
|
||||
|
||||
// METHODS
|
||||
|
|
@ -660,8 +661,7 @@ private:
|
|||
UINFO(8, " SVL " << vertexp << " has color " << color << "\n");
|
||||
|
||||
// Record that all containing ifs have this color.
|
||||
for (IfStack::const_iterator it = m_ifStack.begin();
|
||||
it != m_ifStack.end(); ++it) {
|
||||
for (IfStack::const_iterator it = m_ifStack.begin(); it != m_ifStack.end(); ++it) {
|
||||
m_ifColors[*it].insert(color);
|
||||
}
|
||||
}
|
||||
|
|
@ -700,9 +700,7 @@ public:
|
|||
// EmitSplitVisitor visits through always block *nodep
|
||||
// and generates its split blocks, writing the split blocks
|
||||
// into *newBlocksp.
|
||||
EmitSplitVisitor(AstAlways* nodep,
|
||||
const IfColorVisitor* ifColorp,
|
||||
AlwaysVec* newBlocksp)
|
||||
EmitSplitVisitor(AstAlways* nodep, const IfColorVisitor* ifColorp, AlwaysVec* newBlocksp)
|
||||
: m_origAlwaysp(nodep)
|
||||
, m_ifColorp(ifColorp)
|
||||
, m_newBlocksp(newBlocksp) {
|
||||
|
|
@ -715,13 +713,11 @@ public:
|
|||
void go() {
|
||||
// Create a new always for each color
|
||||
const ColorSet& colors = m_ifColorp->colors();
|
||||
for (ColorSet::const_iterator color = colors.begin();
|
||||
color != colors.end(); ++color) {
|
||||
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
|
||||
// We don't need to clone m_origAlwaysp->sensesp() here;
|
||||
// V3Activate already moved it to a parent node.
|
||||
AstAlways* alwaysp =
|
||||
new AstAlways(m_origAlwaysp->fileline(), VAlwaysKwd::ALWAYS,
|
||||
NULL, NULL);
|
||||
AstAlways* alwaysp
|
||||
= new AstAlways(m_origAlwaysp->fileline(), VAlwaysKwd::ALWAYS, NULL, NULL);
|
||||
// Put a placeholder node into stmtp to track our position.
|
||||
// We'll strip these out after the blocks are fully cloned.
|
||||
AstSplitPlaceholder* placeholderp = makePlaceholderp();
|
||||
|
|
@ -769,16 +765,12 @@ protected:
|
|||
typedef vl_unordered_map<uint32_t, AstNodeIf*> CloneMap;
|
||||
CloneMap clones;
|
||||
|
||||
for (ColorSet::const_iterator color = colors.begin();
|
||||
color != colors.end(); ++color) {
|
||||
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
|
||||
// Clone this if into its set of split blocks
|
||||
AstSplitPlaceholder* if_placeholderp = makePlaceholderp();
|
||||
AstSplitPlaceholder* else_placeholderp = makePlaceholderp();
|
||||
AstIf* clonep =
|
||||
new AstIf(nodep->fileline(),
|
||||
nodep->condp()->cloneTree(true),
|
||||
if_placeholderp,
|
||||
else_placeholderp);
|
||||
AstIf* clonep = new AstIf(nodep->fileline(), nodep->condp()->cloneTree(true),
|
||||
if_placeholderp, else_placeholderp);
|
||||
AstIf* origp = VN_CAST(nodep, If);
|
||||
if (origp) {
|
||||
// Preserve pragmas from unique if's
|
||||
|
|
@ -794,15 +786,13 @@ protected:
|
|||
|
||||
iterateAndNextNull(nodep->ifsp());
|
||||
|
||||
for (ColorSet::const_iterator color = colors.begin();
|
||||
color != colors.end(); ++color) {
|
||||
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
|
||||
m_addAfter[*color] = clones[*color]->elsesp();
|
||||
}
|
||||
|
||||
iterateAndNextNull(nodep->elsesp());
|
||||
|
||||
for (ColorSet::const_iterator color = colors.begin();
|
||||
color != colors.end(); ++color) {
|
||||
for (ColorSet::const_iterator color = colors.begin(); color != colors.end(); ++color) {
|
||||
m_addAfter[*color] = clones[*color];
|
||||
}
|
||||
}
|
||||
|
|
@ -817,17 +807,14 @@ class RemovePlaceholdersVisitor : public AstNVisitor {
|
|||
public:
|
||||
explicit RemovePlaceholdersVisitor(AstNode* nodep) {
|
||||
iterate(nodep);
|
||||
for (NodeSet::const_iterator it = m_removeSet.begin();
|
||||
it != m_removeSet.end(); ++it) {
|
||||
for (NodeSet::const_iterator it = m_removeSet.begin(); it != m_removeSet.end(); ++it) {
|
||||
AstNode* np = *it;
|
||||
np->unlinkFrBack(); // Without next
|
||||
VL_DO_DANGLING(np->deleteTree(), np);
|
||||
}
|
||||
}
|
||||
virtual ~RemovePlaceholdersVisitor() {}
|
||||
virtual void visit(AstSplitPlaceholder* nodep) VL_OVERRIDE {
|
||||
m_removeSet.insert(nodep);
|
||||
}
|
||||
virtual void visit(AstSplitPlaceholder* nodep) VL_OVERRIDE { m_removeSet.insert(nodep); }
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
||||
private:
|
||||
|
|
@ -854,11 +841,11 @@ public:
|
|||
// Splice newly-split blocks into the tree. Remove placeholders
|
||||
// from newly-split blocks. Delete the original always blocks
|
||||
// that we're replacing.
|
||||
for (ReplaceMap::iterator it = m_replaceBlocks.begin();
|
||||
it != m_replaceBlocks.end(); ++it) {
|
||||
for (ReplaceMap::iterator it = m_replaceBlocks.begin(); it != m_replaceBlocks.end();
|
||||
++it) {
|
||||
AstAlways* origp = it->first;
|
||||
for (AlwaysVec::iterator addme = it->second.begin();
|
||||
addme != it->second.end(); ++addme) {
|
||||
for (AlwaysVec::iterator addme = it->second.begin(); addme != it->second.end();
|
||||
++addme) {
|
||||
origp->addNextHere(*addme);
|
||||
RemovePlaceholdersVisitor removePlaceholders(*addme);
|
||||
}
|
||||
|
|
@ -876,9 +863,7 @@ protected:
|
|||
// not rvalues in the if/else bodies.
|
||||
for (VStack::const_iterator it = m_stmtStackps.begin(); it != m_stmtStackps.end(); ++it) {
|
||||
AstNodeIf* ifNodep = VN_CAST((*it)->nodep(), NodeIf);
|
||||
if (ifNodep && (m_curIfConditional != ifNodep)) {
|
||||
continue;
|
||||
}
|
||||
if (ifNodep && (m_curIfConditional != ifNodep)) continue;
|
||||
new SplitRVEdge(&m_graph, *it, vstdp);
|
||||
}
|
||||
}
|
||||
|
|
@ -899,8 +884,8 @@ protected:
|
|||
// For any 'if' node whose deps have all been pruned
|
||||
// (meaning, its conditional expression only looks at primary
|
||||
// inputs) prune all edges that depend on the 'if'.
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp();
|
||||
vertexp; vertexp=vertexp->verticesNextp()) {
|
||||
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp;
|
||||
vertexp = vertexp->verticesNextp()) {
|
||||
SplitLogicVertex* logicp = dynamic_cast<SplitLogicVertex*>(vertexp);
|
||||
if (!logicp) continue;
|
||||
|
||||
|
|
@ -908,8 +893,7 @@ protected:
|
|||
if (!ifNodep) continue;
|
||||
|
||||
bool pruneMe = true;
|
||||
for (V3GraphEdge* edgep = logicp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = logicp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
if (!oedgep->ignoreThisStep()) {
|
||||
// This if conditional depends on something we can't
|
||||
|
|
@ -921,8 +905,8 @@ protected:
|
|||
if (debug() >= 9) {
|
||||
V3GraphVertex* vxp = oedgep->top();
|
||||
SplitNodeVertex* nvxp = dynamic_cast<SplitNodeVertex*>(vxp);
|
||||
UINFO(0, "Cannot prune if-node due to edge "<<oedgep<<
|
||||
" pointing to node "<<nvxp->nodep()<<endl);
|
||||
UINFO(0, "Cannot prune if-node due to edge "
|
||||
<< oedgep << " pointing to node " << nvxp->nodep() << endl);
|
||||
nvxp->nodep()->dumpTree(cout, "- ");
|
||||
}
|
||||
|
||||
|
|
@ -933,21 +917,20 @@ protected:
|
|||
if (!pruneMe) continue;
|
||||
|
||||
// This if can be split; prune dependencies on it.
|
||||
for (V3GraphEdge* edgep = logicp->inBeginp();
|
||||
edgep; edgep = edgep->inNextp()) {
|
||||
for (V3GraphEdge* edgep = logicp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
SplitEdge* oedgep = dynamic_cast<SplitEdge*>(edgep);
|
||||
oedgep->setIgnoreThisStep();
|
||||
}
|
||||
}
|
||||
|
||||
if (debug()>=9) m_graph.dumpDotFilePrefixed("splitg_nodup", false);
|
||||
if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_nodup", false);
|
||||
|
||||
// Weak coloring to determine what needs to remain grouped
|
||||
// in a single always. This follows all edges excluding:
|
||||
// - those we pruned above
|
||||
// - PostEdges, which are done later
|
||||
m_graph.weaklyConnected(&SplitEdge::followScoreboard);
|
||||
if (debug()>=9) m_graph.dumpDotFilePrefixed("splitg_colored", false);
|
||||
if (debug() >= 9) m_graph.dumpDotFilePrefixed("splitg_colored", false);
|
||||
}
|
||||
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
|
|
@ -957,13 +940,13 @@ protected:
|
|||
|
||||
if (m_noReorderWhy != "") {
|
||||
// We saw a jump or something else rare that we don't handle.
|
||||
UINFO(9," NoSplitBlock because "<<m_noReorderWhy<<endl);
|
||||
UINFO(9, " NoSplitBlock because " << m_noReorderWhy << endl);
|
||||
return;
|
||||
}
|
||||
|
||||
// Look across the entire tree of if/else blocks in the always,
|
||||
// and color regions that must be kept together.
|
||||
UINFO(5, "SplitVisitor @ "<<nodep<<endl);
|
||||
UINFO(5, "SplitVisitor @ " << nodep << endl);
|
||||
colorAlwaysGraph();
|
||||
|
||||
// Map each AstNodeIf to the set of colors (split always blocks)
|
||||
|
|
@ -978,19 +961,19 @@ protected:
|
|||
|
||||
// Visit through the original always block one more time,
|
||||
// and emit the split always blocks into m_replaceBlocks:
|
||||
EmitSplitVisitor emitSplit(nodep, &ifColor,
|
||||
&(m_replaceBlocks[nodep]));
|
||||
EmitSplitVisitor emitSplit(nodep, &ifColor, &(m_replaceBlocks[nodep]));
|
||||
emitSplit.go();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep) VL_OVERRIDE {
|
||||
UINFO(4," IF "<<nodep<<endl);
|
||||
UINFO(4, " IF " << nodep << endl);
|
||||
m_curIfConditional = nodep;
|
||||
iterateAndNextNull(nodep->condp());
|
||||
m_curIfConditional = NULL;
|
||||
scanBlock(nodep->ifsp());
|
||||
scanBlock(nodep->elsesp());
|
||||
}
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(SplitVisitor);
|
||||
};
|
||||
|
|
@ -999,16 +982,12 @@ private:
|
|||
// Split class functions
|
||||
|
||||
void V3Split::splitReorderAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
ReorderVisitor visitor(nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ReorderVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("reorder", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
void V3Split::splitAlwaysAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
SplitVisitor visitor(nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ SplitVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("split", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,7 @@ private:
|
|||
|
||||
// METHODS
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->lvalue() && !m_splitVscp
|
||||
&& nodep->varp()->attrIsolateAssign()) {
|
||||
if (nodep->lvalue() && !m_splitVscp && nodep->varp()->attrIsolateAssign()) {
|
||||
m_splitVscp = nodep->varScopep();
|
||||
}
|
||||
}
|
||||
|
|
@ -76,16 +75,16 @@ public:
|
|||
class SplitAsCleanVisitor : public SplitAsBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVarScope* m_splitVscp; // Variable we want to split
|
||||
bool m_modeMatch; // Remove matching Vscp, else non-matching
|
||||
bool m_keepStmt; // Current Statement must be preserved
|
||||
bool m_matches; // Statement below has matching lvalue reference
|
||||
AstVarScope* m_splitVscp; // Variable we want to split
|
||||
bool m_modeMatch; // Remove matching Vscp, else non-matching
|
||||
bool m_keepStmt; // Current Statement must be preserved
|
||||
bool m_matches; // Statement below has matching lvalue reference
|
||||
|
||||
// METHODS
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (nodep->lvalue()) {
|
||||
if (nodep->varScopep()==m_splitVscp) {
|
||||
UINFO(6," CL VAR "<<nodep<<endl);
|
||||
if (nodep->varScopep() == m_splitVscp) {
|
||||
UINFO(6, " CL VAR " << nodep << endl);
|
||||
m_matches = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +94,7 @@ private:
|
|||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
UINFO(6," CL STMT "<<nodep<<endl);
|
||||
UINFO(6, " CL STMT " << nodep << endl);
|
||||
bool oldKeep = m_keepStmt;
|
||||
{
|
||||
m_matches = false;
|
||||
|
|
@ -103,18 +102,18 @@ private:
|
|||
|
||||
iterateChildren(nodep);
|
||||
|
||||
if (m_keepStmt
|
||||
|| (m_modeMatch ? m_matches : !m_matches)) {
|
||||
UINFO(6," Keep STMT "<<nodep<<endl);
|
||||
if (m_keepStmt || (m_modeMatch ? m_matches : !m_matches)) {
|
||||
UINFO(6, " Keep STMT " << nodep << endl);
|
||||
m_keepStmt = true;
|
||||
} else {
|
||||
UINFO(6," Delete STMT "<<nodep<<endl);
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep);
|
||||
UINFO(6, " Delete STMT " << nodep << endl);
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep);
|
||||
}
|
||||
}
|
||||
// If something below matches, the upper statement remains too.
|
||||
m_keepStmt = oldKeep || m_keepStmt;
|
||||
UINFO(9," upKeep="<<m_keepStmt<<" STMT "<<nodep<<endl);
|
||||
UINFO(9, " upKeep=" << m_keepStmt << " STMT " << nodep << endl);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
|
||||
|
|
@ -123,7 +122,7 @@ public:
|
|||
SplitAsCleanVisitor(AstAlways* nodep, AstVarScope* vscp, bool modeMatch) {
|
||||
m_splitVscp = vscp;
|
||||
m_modeMatch = modeMatch;
|
||||
m_keepStmt = false;
|
||||
m_keepStmt = false;
|
||||
m_matches = false;
|
||||
iterate(nodep);
|
||||
}
|
||||
|
|
@ -137,7 +136,7 @@ class SplitAsVisitor : public SplitAsBaseVisitor {
|
|||
private:
|
||||
// NODE STATE
|
||||
// AstAlways::user() -> bool. True if already processed
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
VDouble0 m_statSplits; // Statistic tracking
|
||||
|
|
@ -145,20 +144,20 @@ private:
|
|||
|
||||
// METHODS
|
||||
void splitAlways(AstAlways* nodep) {
|
||||
UINFO(3,"Split "<<nodep<<endl);
|
||||
UINFO(3," For "<<m_splitVscp<<endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout, "-in : ");
|
||||
UINFO(3, "Split " << nodep << endl);
|
||||
UINFO(3, " For " << m_splitVscp << endl);
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "-in : ");
|
||||
// Duplicate it and link in
|
||||
AstAlways* newp = nodep->cloneTree(false);
|
||||
newp->user1(true); // So we don't clone it again
|
||||
nodep->addNextHere(newp);
|
||||
{ // Delete stuff we don't want in old
|
||||
SplitAsCleanVisitor visitor (nodep, m_splitVscp, false);
|
||||
if (debug()>=9) nodep->dumpTree(cout, "-out0: ");
|
||||
{ // Delete stuff we don't want in old
|
||||
SplitAsCleanVisitor visitor(nodep, m_splitVscp, false);
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "-out0: ");
|
||||
}
|
||||
{ // Delete stuff we don't want in new
|
||||
SplitAsCleanVisitor visitor (newp, m_splitVscp, true);
|
||||
if (debug()>=9) newp->dumpTree(cout, "-out1: ");
|
||||
{ // Delete stuff we don't want in new
|
||||
SplitAsCleanVisitor visitor(newp, m_splitVscp, true);
|
||||
if (debug() >= 9) newp->dumpTree(cout, "-out1: ");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,13 +167,12 @@ private:
|
|||
AstVarScope* lastSplitVscp = NULL;
|
||||
while (!nodep->user1()) {
|
||||
// Find any splittable variables
|
||||
SplitAsFindVisitor visitor (nodep);
|
||||
SplitAsFindVisitor visitor(nodep);
|
||||
m_splitVscp = visitor.splitVscp();
|
||||
if (m_splitVscp && m_splitVscp == lastSplitVscp) {
|
||||
// We did this last time! Something's stuck!
|
||||
nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: "
|
||||
<<m_splitVscp->prettyNameQ())
|
||||
m_splitVscp = NULL;
|
||||
<< m_splitVscp->prettyNameQ());
|
||||
}
|
||||
lastSplitVscp = m_splitVscp;
|
||||
// Now isolate the always
|
||||
|
|
@ -207,9 +205,7 @@ public:
|
|||
// SplitAs class functions
|
||||
|
||||
void V3SplitAs::splitAsAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
SplitAsVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ SplitAsVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("splitas", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ struct SplitVarImpl {
|
|||
return new AstAssign(fileline, lhsp, rhsp);
|
||||
} else {
|
||||
return new AstAssignW(fileline, lhsp, rhsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const char* const notSplitMsg;
|
||||
|
|
@ -523,10 +523,10 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
iterate(argp);
|
||||
if (reason) {
|
||||
for (VarSet::iterator it = m_foundTargetVar.begin(),
|
||||
it_end = m_foundTargetVar.end();
|
||||
it_end = m_foundTargetVar.end();
|
||||
it != it_end; ++it) {
|
||||
argp->v3warn(SPLITVAR, (*it)->prettyNameQ()
|
||||
<< notSplitMsg << reason << ".\n");
|
||||
<< notSplitMsg << reason << ".\n");
|
||||
m_refs.remove(*it);
|
||||
}
|
||||
}
|
||||
|
|
@ -574,7 +574,7 @@ class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
m_refsForPackedSplit[m_modp].add(nodep);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) VL_OVERRIDE {
|
||||
if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep);
|
||||
if (VN_IS(nodep->fromp(), VarRef)) m_refsForPackedSplit[m_modp].add(nodep);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
|
||||
|
|
@ -815,8 +815,10 @@ public:
|
|||
if (dim.second < 1 || !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType))
|
||||
reason = "it is not an unpacked array";
|
||||
if (!reason) reason = cannotSplitVarCommonReason(nodep);
|
||||
if (reason) UINFO(5, "Check " << nodep->prettyNameQ()
|
||||
<< " cannot split because" << reason << ".\n");
|
||||
if (reason) {
|
||||
UINFO(5,
|
||||
"Check " << nodep->prettyNameQ() << " cannot split because" << reason << ".\n");
|
||||
}
|
||||
return reason;
|
||||
}
|
||||
};
|
||||
|
|
@ -900,7 +902,7 @@ class PackedVarRef {
|
|||
std::vector<PackedVarRefEntry> vect;
|
||||
vect.reserve(nodes.size());
|
||||
for (vl_unordered_map<AstNode*, size_t>::const_iterator it = nodes.begin(),
|
||||
it_end = nodes.end();
|
||||
it_end = nodes.end();
|
||||
it != it_end; ++it) {
|
||||
vect.push_back(refs[it->second]);
|
||||
}
|
||||
|
|
@ -1047,11 +1049,13 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(),
|
||||
consts[1]->toUInt()),
|
||||
vrefp->lvalue());
|
||||
UINFO(5, varp->prettyName() << " [" << consts[0]->toSInt() << ":+"
|
||||
<< consts[1]->toSInt() << "] lsb:" << refit->second.basicp()->lsb() << "\n");
|
||||
UINFO(5, varp->prettyName()
|
||||
<< " [" << consts[0]->toSInt() << ":+" << consts[1]->toSInt()
|
||||
<< "] lsb:" << refit->second.basicp()->lsb() << "\n");
|
||||
} else {
|
||||
nodep->v3warn(SPLITVAR, vrefp->prettyNameQ() << notSplitMsg
|
||||
<< "its bit range cannot be determined statically.");
|
||||
nodep->v3warn(SPLITVAR, vrefp->prettyNameQ()
|
||||
<< notSplitMsg
|
||||
<< "its bit range cannot be determined statically.");
|
||||
if (!consts[0]) {
|
||||
UINFO(4, "LSB " << nodep->lsbp() << " is expected to be constant, but not\n");
|
||||
}
|
||||
|
|
@ -1076,7 +1080,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
const int msb = std::min(ref.msb(), var.msb());
|
||||
const int bitwidth = msb + 1 - lsb;
|
||||
UINFO(4, var.varp()->prettyNameQ() << "[" << msb << ":" << lsb << "] used for "
|
||||
<< ref.nodep()->prettyNameQ() << '\n');
|
||||
<< ref.nodep()->prettyNameQ() << '\n');
|
||||
// LSB of varp is always 0. "lsb - var.lsb()" means this. see also SplitNewVar
|
||||
AstSel* selp = new AstSel(ref.nodep()->fileline(), refp, lsb - var.lsb(), bitwidth);
|
||||
return selp;
|
||||
|
|
@ -1091,9 +1095,9 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
}
|
||||
const bool in = portp->isReadOnly();
|
||||
for (size_t i = 0; i < vars.size(); ++i) {
|
||||
AstNode* rhsp = new AstSel(portp->fileline(),
|
||||
new AstVarRef(portp->fileline(), portp, !in),
|
||||
vars[i].lsb(), vars[i].bitwidth());
|
||||
AstNode* rhsp
|
||||
= new AstSel(portp->fileline(), new AstVarRef(portp->fileline(), portp, !in),
|
||||
vars[i].lsb(), vars[i].bitwidth());
|
||||
AstNode* lhsp = new AstVarRef(portp->fileline(), vars[i].varp(), in);
|
||||
if (!in) std::swap(lhsp, rhsp);
|
||||
AstNodeAssign* assignp = newAssign(portp->fileline(), lhsp, rhsp, portp);
|
||||
|
|
@ -1117,8 +1121,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
= (left == right)
|
||||
? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__"
|
||||
: varp->name() + "__BRA__" + AstNode::encodeNumber(left)
|
||||
+ AstNode::encodeName(":") + AstNode::encodeNumber(right)
|
||||
+ "__KET__";
|
||||
+ AstNode::encodeName(":") + AstNode::encodeNumber(right) + "__KET__";
|
||||
|
||||
AstBasicDType* dtypep;
|
||||
switch (basicp->keyword()) {
|
||||
|
|
@ -1226,9 +1229,8 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl {
|
|||
new AstVarRef(varp->fileline(), vars[i].varp(), false),
|
||||
rhsp);
|
||||
}
|
||||
varp->addNextHere(newAssign(varp->fileline(),
|
||||
new AstVarRef(varp->fileline(), varp, true),
|
||||
rhsp, varp));
|
||||
varp->addNextHere(newAssign(
|
||||
varp->fileline(), new AstVarRef(varp->fileline(), varp, true), rhsp, varp));
|
||||
} else { // the original variable is not used anymore.
|
||||
VL_DO_DANGLING(varp->unlinkFrBack()->deleteTree(), varp);
|
||||
}
|
||||
|
|
@ -1274,8 +1276,9 @@ public:
|
|||
} else {
|
||||
reason = "its type is unknown";
|
||||
}
|
||||
if (reason) UINFO(5, "Check " << nodep->prettyNameQ()
|
||||
<< " cannot split because" << reason << endl);
|
||||
if (reason)
|
||||
UINFO(5,
|
||||
"Check " << nodep->prettyNameQ() << " cannot split because" << reason << endl);
|
||||
return reason;
|
||||
}
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
|
|||
162
src/V3Subst.cpp
162
src/V3Subst.cpp
|
|
@ -49,10 +49,10 @@ public:
|
|||
class SubstVarWord {
|
||||
protected:
|
||||
// MEMBERS
|
||||
AstNodeAssign* m_assignp; // Last assignment to each word of this var
|
||||
int m_step; // Step number of last assignment
|
||||
bool m_use; // True if each word was consumed
|
||||
bool m_complex; // True if each word is complex
|
||||
AstNodeAssign* m_assignp; // Last assignment to each word of this var
|
||||
int m_step; // Step number of last assignment
|
||||
bool m_use; // True if each word was consumed
|
||||
bool m_complex; // True if each word is complex
|
||||
friend class SubstVarEntry;
|
||||
// METHODS
|
||||
void clear() {
|
||||
|
|
@ -68,10 +68,10 @@ protected:
|
|||
|
||||
class SubstVarEntry {
|
||||
// MEMBERS
|
||||
AstVar* m_varp; // Variable this tracks
|
||||
bool m_wordAssign; // True if any word assignments
|
||||
bool m_wordUse; // True if any individual word usage
|
||||
SubstVarWord m_whole; // Data for whole vector used at once
|
||||
AstVar* m_varp; // Variable this tracks
|
||||
bool m_wordAssign; // True if any word assignments
|
||||
bool m_wordUse; // True if any individual word usage
|
||||
SubstVarWord m_whole; // Data for whole vector used at once
|
||||
std::vector<SubstVarWord> m_words; // Data for every word, if multi word variable
|
||||
int debug() { return SubstBaseVisitor::debug(); }
|
||||
|
||||
|
|
@ -83,20 +83,21 @@ public:
|
|||
m_wordUse = false;
|
||||
m_words.resize(varp->widthWords());
|
||||
m_whole.clear();
|
||||
for (int i=0; i<varp->widthWords(); i++) {
|
||||
m_words[i].clear();
|
||||
}
|
||||
for (int i = 0; i < varp->widthWords(); i++) m_words[i].clear();
|
||||
}
|
||||
~SubstVarEntry() {}
|
||||
|
||||
private:
|
||||
// METHODS
|
||||
bool wordNumOk(int word) const {
|
||||
return word < m_varp->widthWords();
|
||||
}
|
||||
bool wordNumOk(int word) const { return word < m_varp->widthWords(); }
|
||||
AstNodeAssign* getWordAssignp(int word) const {
|
||||
if (!wordNumOk(word)) return NULL;
|
||||
else return m_words[word].m_assignp;
|
||||
if (!wordNumOk(word)) {
|
||||
return NULL;
|
||||
} else {
|
||||
return m_words[word].m_assignp;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
void assignWhole(int step, AstNodeAssign* assp) {
|
||||
if (m_whole.m_assignp) m_whole.m_complex = true;
|
||||
|
|
@ -104,8 +105,9 @@ public:
|
|||
m_whole.m_step = step;
|
||||
}
|
||||
void assignWord(int step, int word, AstNodeAssign* assp) {
|
||||
if (!wordNumOk(word) || getWordAssignp(word)
|
||||
|| m_words[word].m_complex) m_whole.m_complex = true;
|
||||
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) {
|
||||
m_whole.m_complex = true;
|
||||
}
|
||||
m_wordAssign = true;
|
||||
if (wordNumOk(word)) {
|
||||
m_words[word].m_assignp = assp;
|
||||
|
|
@ -113,13 +115,12 @@ public:
|
|||
}
|
||||
}
|
||||
void assignWordComplex(int word) {
|
||||
if (!wordNumOk(word) || getWordAssignp(word)
|
||||
|| m_words[word].m_complex) m_whole.m_complex = true;
|
||||
if (!wordNumOk(word) || getWordAssignp(word) || m_words[word].m_complex) {
|
||||
m_whole.m_complex = true;
|
||||
}
|
||||
m_words[word].m_complex = true;
|
||||
}
|
||||
void assignComplex() {
|
||||
m_whole.m_complex = true;
|
||||
}
|
||||
void assignComplex() { m_whole.m_complex = true; }
|
||||
void consumeWhole() { //==consumeComplex as we don't know the difference
|
||||
m_whole.m_use = true;
|
||||
}
|
||||
|
|
@ -129,8 +130,7 @@ public:
|
|||
}
|
||||
// ACCESSORS
|
||||
AstNode* substWhole(AstNode* errp) {
|
||||
if (!m_varp->isWide()
|
||||
&& !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
|
||||
if (!m_varp->isWide() && !m_whole.m_complex && m_whole.m_assignp && !m_wordAssign) {
|
||||
AstNodeAssign* assp = m_whole.m_assignp;
|
||||
UASSERT_OBJ(assp, errp, "Reading whole that was never assigned");
|
||||
return (assp->rhsp());
|
||||
|
|
@ -138,7 +138,8 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
AstNode* substWord(AstNode* errp, int word) { // Return what to substitute given word number for
|
||||
// Return what to substitute given word number for
|
||||
AstNode* substWord(AstNode* errp, int word) {
|
||||
if (!m_whole.m_complex && !m_whole.m_assignp && !m_words[word].m_complex) {
|
||||
AstNodeAssign* assp = getWordAssignp(word);
|
||||
UASSERT_OBJ(assp, errp, "Reading a word that was never assigned, or bad word #");
|
||||
|
|
@ -147,14 +148,16 @@ public:
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
int getWholeStep() const {
|
||||
return m_whole.m_step;
|
||||
}
|
||||
int getWholeStep() const { return m_whole.m_step; }
|
||||
int getWordStep(int word) const {
|
||||
if (!wordNumOk(word)) return 0; else return m_words[word].m_step;
|
||||
if (!wordNumOk(word)) {
|
||||
return 0;
|
||||
} else {
|
||||
return m_words[word].m_step;
|
||||
}
|
||||
}
|
||||
void deleteAssign(AstNodeAssign* nodep) {
|
||||
UINFO(5, "Delete "<<nodep<<endl);
|
||||
UINFO(5, "Delete " << nodep << endl);
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
}
|
||||
void deleteUnusedAssign() {
|
||||
|
|
@ -162,9 +165,9 @@ public:
|
|||
if (!m_whole.m_use && !m_wordUse && m_whole.m_assignp) {
|
||||
VL_DO_CLEAR(deleteAssign(m_whole.m_assignp), m_whole.m_assignp = NULL);
|
||||
}
|
||||
for (unsigned i=0; i<m_words.size(); i++) {
|
||||
if (!m_whole.m_use && !m_words[i].m_use
|
||||
&& m_words[i].m_assignp && !m_words[i].m_complex) {
|
||||
for (unsigned i = 0; i < m_words.size(); i++) {
|
||||
if (!m_whole.m_use && !m_words[i].m_use && m_words[i].m_assignp
|
||||
&& !m_words[i].m_complex) {
|
||||
VL_DO_CLEAR(deleteAssign(m_words[i].m_assignp), m_words[i].m_assignp = NULL);
|
||||
}
|
||||
}
|
||||
|
|
@ -181,8 +184,8 @@ private:
|
|||
// See SubstVisitor
|
||||
//
|
||||
// STATE
|
||||
int m_origStep; // Step number where subst was recorded
|
||||
bool m_ok; // No misassignments found
|
||||
int m_origStep; // Step number where subst was recorded
|
||||
bool m_ok; // No misassignments found
|
||||
|
||||
// METHODS
|
||||
SubstVarEntry* findEntryp(AstVarRef* nodep) {
|
||||
|
|
@ -197,7 +200,9 @@ private:
|
|||
} else {
|
||||
// A simple variable; needs checking.
|
||||
if (m_origStep < nodep->varp()->user2()) {
|
||||
if (m_ok) UINFO(9," RHS variable changed since subst recorded: "<<nodep<<endl);
|
||||
if (m_ok) {
|
||||
UINFO(9, " RHS variable changed since subst recorded: " << nodep << endl);
|
||||
}
|
||||
m_ok = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +213,7 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
SubstUseVisitor(AstNode* nodep, int origStep) {
|
||||
UINFO(9, " SubstUseVisitor "<<origStep<<" "<<nodep<<endl);
|
||||
UINFO(9, " SubstUseVisitor " << origStep << " " << nodep << endl);
|
||||
m_ok = true;
|
||||
m_origStep = origStep;
|
||||
iterate(nodep);
|
||||
|
|
@ -227,17 +232,19 @@ private:
|
|||
// Passed to SubstUseVisitor
|
||||
// AstVar::user1p -> SubstVar* for usage var, 0=not set yet
|
||||
// AstVar::user2 -> int step number for last assignment, 0=not set yet
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
std::vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
|
||||
int m_ops; // Number of operators on assign rhs
|
||||
int m_assignStep; // Assignment number to determine var lifetime
|
||||
VDouble0 m_statSubsts; // Statistic tracking
|
||||
std::vector<SubstVarEntry*> m_entryps; // Nodes to delete when we are finished
|
||||
int m_ops; // Number of operators on assign rhs
|
||||
int m_assignStep; // Assignment number to determine var lifetime
|
||||
VDouble0 m_statSubsts; // Statistic tracking
|
||||
|
||||
enum { SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
|
||||
SUBST_MAX_OPS_NA = 9999 }; // Not allowed to substitute
|
||||
enum {
|
||||
SUBST_MAX_OPS_SUBST = 30, // Maximum number of ops to substitute in
|
||||
SUBST_MAX_OPS_NA = 9999
|
||||
}; // Not allowed to substitute
|
||||
|
||||
// METHODS
|
||||
SubstVarEntry* getEntryp(AstVarRef* nodep) {
|
||||
|
|
@ -251,57 +258,51 @@ private:
|
|||
return entryp;
|
||||
}
|
||||
}
|
||||
inline bool isSubstVar(AstVar* nodep) {
|
||||
return nodep->isStatementTemp() && !nodep->noSubst();
|
||||
}
|
||||
inline bool isSubstVar(AstVar* nodep) { return nodep->isStatementTemp() && !nodep->noSubst(); }
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeAssign* nodep) VL_OVERRIDE {
|
||||
m_ops = 0;
|
||||
m_assignStep++;
|
||||
iterateAndNextNull(nodep->rhsp());
|
||||
bool hit=false;
|
||||
bool hit = false;
|
||||
if (AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef)) {
|
||||
if (isSubstVar(varrefp->varp())) {
|
||||
SubstVarEntry* entryp = getEntryp(varrefp);
|
||||
hit = true;
|
||||
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
||||
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
|
||||
UINFO(8, " ASSIGNtooDeep " << varrefp << endl);
|
||||
entryp->assignComplex();
|
||||
} else {
|
||||
UINFO(8," ASSIGNwhole "<<varrefp<<endl);
|
||||
UINFO(8, " ASSIGNwhole " << varrefp << endl);
|
||||
entryp->assignWhole(m_assignStep, nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) {
|
||||
} else if (AstWordSel* wordp = VN_CAST(nodep->lhsp(), WordSel)) {
|
||||
if (AstVarRef* varrefp = VN_CAST(wordp->lhsp(), VarRef)) {
|
||||
if (VN_IS(wordp->rhsp(), Const)
|
||||
&& isSubstVar(varrefp->varp())) {
|
||||
if (VN_IS(wordp->rhsp(), Const) && isSubstVar(varrefp->varp())) {
|
||||
int word = VN_CAST(wordp->rhsp(), Const)->toUInt();
|
||||
SubstVarEntry* entryp = getEntryp(varrefp);
|
||||
hit = true;
|
||||
if (m_ops > SUBST_MAX_OPS_SUBST) {
|
||||
UINFO(8," ASSIGNtooDeep "<<varrefp<<endl);
|
||||
UINFO(8, " ASSIGNtooDeep " << varrefp << endl);
|
||||
entryp->assignWordComplex(word);
|
||||
} else {
|
||||
UINFO(8," ASSIGNword"<<word<<" "<<varrefp<<endl);
|
||||
UINFO(8, " ASSIGNword" << word << " " << varrefp << endl);
|
||||
entryp->assignWord(m_assignStep, word, nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hit) {
|
||||
iterate(nodep->lhsp());
|
||||
}
|
||||
if (!hit) iterate(nodep->lhsp());
|
||||
}
|
||||
void replaceSubstEtc(AstNode* nodep, AstNode* substp) {
|
||||
if (debug()>5) nodep->dumpTree(cout, " substw_old: ");
|
||||
if (debug() > 5) nodep->dumpTree(cout, " substw_old: ");
|
||||
AstNode* newp = substp->cloneTree(true);
|
||||
if (!nodep->isQuad() && newp->isQuad()) {
|
||||
newp = new AstCCast(newp->fileline(), newp, nodep);
|
||||
}
|
||||
if (debug()>5) newp->dumpTree(cout, " w_new: ");
|
||||
if (debug() > 5) newp->dumpTree(cout, " w_new: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
++m_statSubsts;
|
||||
|
|
@ -310,17 +311,15 @@ private:
|
|||
iterate(nodep->rhsp());
|
||||
AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef);
|
||||
AstConst* constp = VN_CAST(nodep->rhsp(), Const);
|
||||
if (varrefp && isSubstVar(varrefp->varp())
|
||||
&& !varrefp->lvalue()
|
||||
&& constp) {
|
||||
if (varrefp && isSubstVar(varrefp->varp()) && !varrefp->lvalue() && constp) {
|
||||
// Nicely formed lvalues handled in NodeAssign
|
||||
// Other lvalues handled as unknown mess in AstVarRef
|
||||
int word = constp->toUInt();
|
||||
UINFO(8," USEword"<<word<<" "<<varrefp<<endl);
|
||||
UINFO(8, " USEword" << word << " " << varrefp << endl);
|
||||
SubstVarEntry* entryp = getEntryp(varrefp);
|
||||
if (AstNode* substp = entryp->substWord(nodep, word)) {
|
||||
// Check that the RHS hasn't changed value since we recorded it.
|
||||
SubstUseVisitor visitor (substp, entryp->getWordStep(word));
|
||||
SubstUseVisitor visitor(substp, entryp->getWordStep(word));
|
||||
if (visitor.ok()) {
|
||||
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
|
||||
} else {
|
||||
|
|
@ -338,25 +337,25 @@ private:
|
|||
if (nodep->lvalue()) {
|
||||
m_assignStep++;
|
||||
nodep->varp()->user2(m_assignStep);
|
||||
UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
|
||||
UINFO(9, " ASSIGNstep u2=" << nodep->varp()->user2() << " " << nodep << endl);
|
||||
}
|
||||
if (isSubstVar(nodep->varp())) {
|
||||
SubstVarEntry* entryp = getEntryp(nodep);
|
||||
if (nodep->lvalue()) {
|
||||
UINFO(8," ASSIGNcpx "<<nodep<<endl);
|
||||
UINFO(8, " ASSIGNcpx " << nodep << endl);
|
||||
entryp->assignComplex();
|
||||
} else if (AstNode* substp = entryp->substWhole(nodep)) {
|
||||
// Check that the RHS hasn't changed value since we recorded it.
|
||||
SubstUseVisitor visitor (substp, entryp->getWholeStep());
|
||||
SubstUseVisitor visitor(substp, entryp->getWholeStep());
|
||||
if (visitor.ok()) {
|
||||
UINFO(8," USEwhole "<<nodep<<endl);
|
||||
UINFO(8, " USEwhole " << nodep << endl);
|
||||
VL_DO_DANGLING(replaceSubstEtc(nodep, substp), nodep);
|
||||
} else {
|
||||
UINFO(8," USEwholeButChg "<<nodep<<endl);
|
||||
UINFO(8, " USEwholeButChg " << nodep << endl);
|
||||
entryp->consumeWhole();
|
||||
}
|
||||
} else { // Consumed w/o substitute
|
||||
UINFO(8," USEwtf "<<nodep<<endl);
|
||||
UINFO(8, " USEwtf " << nodep << endl);
|
||||
entryp->consumeWhole();
|
||||
}
|
||||
}
|
||||
|
|
@ -365,11 +364,10 @@ private:
|
|||
virtual void visit(AstConst*) VL_OVERRIDE {}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE {
|
||||
m_ops++;
|
||||
if (!nodep->isSubstOptimizable()) {
|
||||
m_ops = SUBST_MAX_OPS_NA;
|
||||
}
|
||||
if (!nodep->isSubstOptimizable()) m_ops = SUBST_MAX_OPS_NA;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit SubstVisitor(AstNode* nodep) {
|
||||
|
|
@ -381,8 +379,8 @@ public:
|
|||
}
|
||||
virtual ~SubstVisitor() {
|
||||
V3Stats::addStat("Optimizations, Substituted temps", m_statSubsts);
|
||||
for (std::vector<SubstVarEntry*>::iterator it = m_entryps.begin();
|
||||
it != m_entryps.end(); ++it) {
|
||||
for (std::vector<SubstVarEntry*>::iterator it = m_entryps.begin(); it != m_entryps.end();
|
||||
++it) {
|
||||
(*it)->deleteUnusedAssign();
|
||||
delete (*it);
|
||||
}
|
||||
|
|
@ -393,9 +391,7 @@ public:
|
|||
// Subst class functions
|
||||
|
||||
void V3Subst::substituteAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
SubstVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ SubstVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("subst", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
204
src/V3TSP.cpp
204
src/V3TSP.cpp
|
|
@ -47,32 +47,33 @@
|
|||
// Support classes
|
||||
|
||||
namespace V3TSP {
|
||||
static unsigned edgeIdNext = 0;
|
||||
static unsigned edgeIdNext = 0;
|
||||
|
||||
static void selfTestStates();
|
||||
static void selfTestString();
|
||||
static void selfTestStates();
|
||||
static void selfTestString();
|
||||
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
} // namespace V3TSP
|
||||
|
||||
// Vertex that tracks a per-vertex key
|
||||
template <typename T_Key>
|
||||
class TspVertexTmpl : public V3GraphVertex {
|
||||
template <typename T_Key> class TspVertexTmpl : public V3GraphVertex {
|
||||
private:
|
||||
T_Key m_key;
|
||||
|
||||
public:
|
||||
TspVertexTmpl(V3Graph* graphp, const T_Key& k)
|
||||
: V3GraphVertex(graphp), m_key(k) {}
|
||||
: V3GraphVertex(graphp)
|
||||
, m_key(k) {}
|
||||
virtual ~TspVertexTmpl() {}
|
||||
const T_Key& key() const { return m_key; }
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(TspVertexTmpl);
|
||||
};
|
||||
|
||||
// TspGraphTmpl represents a complete graph, templatized to work with
|
||||
// different T_Key types.
|
||||
template <typename T_Key>
|
||||
class TspGraphTmpl : public V3Graph {
|
||||
template <typename T_Key> class TspGraphTmpl : public V3Graph {
|
||||
public:
|
||||
// TYPES
|
||||
typedef TspVertexTmpl<T_Key> Vertex;
|
||||
|
|
@ -82,14 +83,15 @@ public:
|
|||
VMap m_vertices; // T_Key to Vertex lookup map
|
||||
|
||||
// CONSTRUCTORS
|
||||
TspGraphTmpl() : V3Graph() {}
|
||||
TspGraphTmpl()
|
||||
: V3Graph() {}
|
||||
virtual ~TspGraphTmpl() {}
|
||||
|
||||
// METHODS
|
||||
void addVertex(const T_Key &key) {
|
||||
void addVertex(const T_Key& key) {
|
||||
typename VMap::iterator itr = m_vertices.find(key);
|
||||
UASSERT(itr == m_vertices.end(), "Vertex already exists with same key");
|
||||
Vertex *v = new Vertex(this, key);
|
||||
Vertex* v = new Vertex(this, key);
|
||||
m_vertices[key] = v;
|
||||
}
|
||||
|
||||
|
|
@ -118,9 +120,7 @@ public:
|
|||
|
||||
std::list<Vertex*> keysToVertexList(const std::vector<T_Key>& odds) {
|
||||
std::list<Vertex*> vertices;
|
||||
for(unsigned i = 0; i < odds.size(); ++i) {
|
||||
vertices.push_back(findVertex(odds.at(i)));
|
||||
}
|
||||
for (unsigned i = 0; i < odds.size(); ++i) { vertices.push_back(findVertex(odds.at(i))); }
|
||||
return vertices;
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ public:
|
|||
// CONSTRUCTORS
|
||||
EdgeCmp() {}
|
||||
// METHODS
|
||||
bool operator() (const V3GraphEdge* ap, const V3GraphEdge* bp) {
|
||||
bool operator()(const V3GraphEdge* ap, const V3GraphEdge* bp) {
|
||||
int aCost = ap->weight();
|
||||
int bCost = bp->weight();
|
||||
// Sort first on cost, lowest cost edges first:
|
||||
|
|
@ -141,13 +141,12 @@ public:
|
|||
// Costs are equal. Compare edgeId's which should be unique.
|
||||
return ap->user() < bp->user();
|
||||
}
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(EdgeCmp);
|
||||
};
|
||||
|
||||
static Vertex* castVertexp(V3GraphVertex* vxp) {
|
||||
return dynamic_cast<Vertex*>(vxp);
|
||||
}
|
||||
static Vertex* castVertexp(V3GraphVertex* vxp) { return dynamic_cast<Vertex*>(vxp); }
|
||||
|
||||
// From *this, populate *mstp with the minimum spanning tree.
|
||||
// *mstp must be initially empty.
|
||||
|
|
@ -164,8 +163,7 @@ public:
|
|||
PendingEdgeSet pendingEdges(cmp);
|
||||
|
||||
vluint32_t vertCount = 0;
|
||||
for (V3GraphVertex* vxp = verticesBeginp();
|
||||
vxp; vxp = vxp->verticesNextp()) {
|
||||
for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
mstp->addVertex(castVertexp(vxp)->key());
|
||||
vertCount++;
|
||||
}
|
||||
|
|
@ -174,8 +172,7 @@ public:
|
|||
// all incident edges from this vertex go into a pending edge set.
|
||||
Vertex* start_vertexp = castVertexp(verticesBeginp());
|
||||
visited_set.insert(start_vertexp);
|
||||
for (V3GraphEdge* edgep = start_vertexp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = start_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
pendingEdges.insert(edgep);
|
||||
}
|
||||
|
||||
|
|
@ -198,9 +195,8 @@ public:
|
|||
Vertex* neighborp = castVertexp(bestEdgep->top());
|
||||
if (visited_set.find(neighborp) == visited_set.end()) {
|
||||
int bestCost = bestEdgep->weight();
|
||||
UINFO(6, "bestCost = "<<bestCost
|
||||
<<" from "<<from_vertexp->key()
|
||||
<<" to "<<neighborp->key()<<endl);
|
||||
UINFO(6, "bestCost = " << bestCost << " from " << from_vertexp->key() << " to "
|
||||
<< neighborp->key() << endl);
|
||||
|
||||
// Create the edge in our output MST graph
|
||||
mstp->addEdge(from_vertexp->key(), neighborp->key(), bestCost);
|
||||
|
|
@ -210,13 +206,13 @@ public:
|
|||
visited_set.insert(neighborp);
|
||||
|
||||
// Update the pending edges with new edges
|
||||
for (V3GraphEdge* edgep = neighborp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = neighborp->outBeginp(); edgep;
|
||||
edgep = edgep->outNextp()) {
|
||||
pendingEdges.insert(edgep);
|
||||
}
|
||||
} else {
|
||||
UINFO(6, "Discarding edge to already-visited neighbor "
|
||||
<<neighborp->key()<<endl);
|
||||
UINFO(6,
|
||||
"Discarding edge to already-visited neighbor " << neighborp->key() << endl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -226,8 +222,7 @@ public:
|
|||
|
||||
// Populate *outp with a minimal perfect matching of *this.
|
||||
// *outp must be initially empty.
|
||||
void perfectMatching(const std::vector<T_Key>& oddKeys,
|
||||
TspGraphTmpl* outp) {
|
||||
void perfectMatching(const std::vector<T_Key>& oddKeys, TspGraphTmpl* outp) {
|
||||
UASSERT(outp->empty(), "Output graph must start empty");
|
||||
|
||||
std::list<Vertex*> odds = keysToVertexList(oddKeys);
|
||||
|
|
@ -261,8 +256,7 @@ public:
|
|||
PendingEdgeSet pendingEdges(cmp);
|
||||
|
||||
for (VertexListIt it = odds.begin(); it != odds.end(); ++it) {
|
||||
for (V3GraphEdge* edgep = (*it)->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = (*it)->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
pendingEdges.insert(edgep);
|
||||
}
|
||||
}
|
||||
|
|
@ -270,8 +264,8 @@ public:
|
|||
// Iterate over all edges, in order from low to high cost.
|
||||
// For any edge whose ends are both odd-order vertices which
|
||||
// haven't been matched yet, match them.
|
||||
for (typename PendingEdgeSet::iterator it = pendingEdges.begin();
|
||||
it != pendingEdges.end(); ++it) {
|
||||
for (typename PendingEdgeSet::iterator it = pendingEdges.begin(); it != pendingEdges.end();
|
||||
++it) {
|
||||
Vertex* fromp = castVertexp((*it)->fromp());
|
||||
Vertex* top = castVertexp((*it)->top());
|
||||
if ((unmatchedOdds.find(fromp) != unmatchedOdds.end())
|
||||
|
|
@ -298,49 +292,43 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp,
|
||||
Vertex* startp,
|
||||
void findEulerTourRecurse(vl_unordered_set<unsigned>* markedEdgesp, Vertex* startp,
|
||||
std::vector<T_Key>* sortedOutp) {
|
||||
Vertex* cur_vertexp = startp;
|
||||
|
||||
// Go on a random tour. Fun!
|
||||
std::vector<Vertex*> tour;
|
||||
do {
|
||||
UINFO(6, "Adding "<<cur_vertexp->key()<<" to tour.\n");
|
||||
UINFO(6, "Adding " << cur_vertexp->key() << " to tour.\n");
|
||||
tour.push_back(cur_vertexp);
|
||||
|
||||
// Look for an arbitrary edge we've not yet marked
|
||||
for (V3GraphEdge* edgep = cur_vertexp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = cur_vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
vluint32_t edgeId = edgep->user();
|
||||
if (markedEdgesp->end() == markedEdgesp->find(edgeId)) {
|
||||
// This edge is not yet marked, so follow it.
|
||||
markedEdgesp->insert(edgeId);
|
||||
Vertex* neighborp = castVertexp(edgep->top());
|
||||
UINFO(6, "following edge "<<edgeId
|
||||
<<" from "<<cur_vertexp->key()
|
||||
<<" to "<<neighborp->key()<<endl);
|
||||
UINFO(6, "following edge " << edgeId << " from " << cur_vertexp->key()
|
||||
<< " to " << neighborp->key() << endl);
|
||||
cur_vertexp = neighborp;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
v3fatalSrc("No unmarked edges found in tour");
|
||||
found:
|
||||
;
|
||||
found:;
|
||||
} while (cur_vertexp != startp);
|
||||
UINFO(6, "stopped, got back to start of tour @ "<<cur_vertexp->key()<<endl);
|
||||
UINFO(6, "stopped, got back to start of tour @ " << cur_vertexp->key() << endl);
|
||||
|
||||
// Look for nodes on the tour that still have
|
||||
// un-marked edges. If we find one, recurse.
|
||||
for (typename std::vector<Vertex*>::iterator it = tour.begin();
|
||||
it != tour.end(); ++it) {
|
||||
for (typename std::vector<Vertex*>::iterator it = tour.begin(); it != tour.end(); ++it) {
|
||||
Vertex* vxp = *it;
|
||||
bool recursed;
|
||||
do {
|
||||
recursed = false;
|
||||
// Look for an arbitrary edge at vxp we've not yet marked
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp();
|
||||
edgep; edgep = edgep->outNextp()) {
|
||||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
vluint32_t edgeId = edgep->user();
|
||||
if (markedEdgesp->end() == markedEdgesp->find(edgeId)) {
|
||||
UINFO(6, "Recursing.\n");
|
||||
|
|
@ -349,38 +337,36 @@ public:
|
|||
goto recursed;
|
||||
}
|
||||
}
|
||||
recursed:
|
||||
;
|
||||
recursed:;
|
||||
} while (recursed);
|
||||
sortedOutp->push_back(vxp->key());
|
||||
}
|
||||
|
||||
UINFO(6, "Tour was: ");
|
||||
for (typename std::vector<Vertex*>::iterator it = tour.begin();
|
||||
it != tour.end(); ++it) {
|
||||
for (typename std::vector<Vertex*>::iterator it = tour.begin(); it != tour.end(); ++it) {
|
||||
Vertex* vxp = *it;
|
||||
UINFONL(6, " "<<vxp->key());
|
||||
UINFONL(6, " " << vxp->key());
|
||||
}
|
||||
UINFONL(6, "\n");
|
||||
}
|
||||
|
||||
void dumpGraph(std::ostream& os, const string& nameComment) const {
|
||||
// UINFO(0) as controlled by caller
|
||||
os<<"At "<<nameComment<<", dumping graph. Keys:\n";
|
||||
os << "At " << nameComment << ", dumping graph. Keys:\n";
|
||||
for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) {
|
||||
Vertex* tspvp = castVertexp(vxp);
|
||||
os<<" "<<tspvp->key()<<endl;
|
||||
os << " " << tspvp->key() << endl;
|
||||
for (V3GraphEdge* edgep = tspvp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
Vertex* neighborp = castVertexp(edgep->top());
|
||||
os<<" has edge "<<edgep->user()<<" to "<<neighborp->key()<<endl;
|
||||
os << " has edge " << edgep->user() << " to " << neighborp->key() << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
void dumpGraphFilePrefixed(const string& nameComment) const {
|
||||
if (v3Global.opt.dumpTree()) {
|
||||
string filename = v3Global.debugFilename(nameComment)+".txt";
|
||||
string filename = v3Global.debugFilename(nameComment) + ".txt";
|
||||
const vl_unique_ptr<std::ofstream> logp(V3File::new_ofstream(filename));
|
||||
if (logp->fail()) v3fatal("Can't write "<<filename);
|
||||
if (logp->fail()) v3fatal("Can't write " << filename);
|
||||
dumpGraph(*logp, nameComment);
|
||||
}
|
||||
}
|
||||
|
|
@ -402,9 +388,7 @@ public:
|
|||
for (V3GraphEdge* edgep = vxp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
degree++;
|
||||
}
|
||||
if (degree & 1) {
|
||||
result.push_back(tspvp->key());
|
||||
}
|
||||
if (degree & 1) { result.push_back(tspvp->key()); }
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
@ -427,9 +411,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
// Make this TSP implementation work for graphs of size 0 or 1
|
||||
// which, unfortunately, is a special case as the following
|
||||
// code assumes >= 2 nodes.
|
||||
if (states.empty()) {
|
||||
return;
|
||||
}
|
||||
if (states.empty()) { return; }
|
||||
if (states.size() == 1) {
|
||||
resultp->push_back(*(states.begin()));
|
||||
return;
|
||||
|
|
@ -470,8 +452,8 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
// Discard duplicate nodes that the Euler tour might contain.
|
||||
{
|
||||
vl_unordered_set<const TspStateBase*> seen;
|
||||
for (V3TSP::StateVec::iterator it = prelim_result.begin();
|
||||
it != prelim_result.end(); ++it) {
|
||||
for (V3TSP::StateVec::iterator it = prelim_result.begin(); it != prelim_result.end();
|
||||
++it) {
|
||||
const TspStateBase* elemp = *it;
|
||||
if (seen.find(elemp) == seen.end()) {
|
||||
seen.insert(elemp);
|
||||
|
|
@ -492,7 +474,7 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
for (unsigned i = 0; i < resultp->size(); ++i) {
|
||||
const TspStateBase* ap = (*resultp)[i];
|
||||
const TspStateBase* bp
|
||||
= (i+1 == resultp->size()) ? (*resultp)[0] : (*resultp)[i+1];
|
||||
= (i + 1 == resultp->size()) ? (*resultp)[0] : (*resultp)[i + 1];
|
||||
unsigned cost = ap->cost(bp);
|
||||
if (cost > max_cost) {
|
||||
max_cost = cost;
|
||||
|
|
@ -508,12 +490,10 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
V3TSP::StateVec new_result;
|
||||
unsigned i = max_cost_idx + 1;
|
||||
UASSERT(i < resultp->size(), "Algorithm size error");
|
||||
while(i != max_cost_idx) {
|
||||
while (i != max_cost_idx) {
|
||||
new_result.push_back((*resultp)[i]);
|
||||
i++;
|
||||
if (i >= resultp->size()) {
|
||||
i = 0;
|
||||
}
|
||||
if (i >= resultp->size()) { i = 0; }
|
||||
}
|
||||
new_result.push_back((*resultp)[i]);
|
||||
|
||||
|
|
@ -527,17 +507,17 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) {
|
|||
|
||||
class TspTestState : public V3TSP::TspStateBase {
|
||||
public:
|
||||
TspTestState(unsigned xpos, unsigned ypos) :
|
||||
m_xpos(xpos),
|
||||
m_ypos(ypos),
|
||||
m_serial(++m_serialNext) {}
|
||||
TspTestState(unsigned xpos, unsigned ypos)
|
||||
: m_xpos(xpos)
|
||||
, m_ypos(ypos)
|
||||
, m_serial(++m_serialNext) {}
|
||||
~TspTestState() {}
|
||||
virtual int cost(const TspStateBase* otherp) const {
|
||||
return cost(dynamic_cast<const TspTestState*>(otherp));
|
||||
}
|
||||
static unsigned diff(unsigned a, unsigned b) {
|
||||
if (a>b) return a-b;
|
||||
return b-a;
|
||||
if (a > b) return a - b;
|
||||
return b - a;
|
||||
}
|
||||
virtual int cost(const TspTestState* otherp) const {
|
||||
// For test purposes, each TspTestState is merely a point
|
||||
|
|
@ -546,21 +526,16 @@ public:
|
|||
unsigned xabs, yabs;
|
||||
xabs = diff(otherp->m_xpos, m_xpos);
|
||||
yabs = diff(otherp->m_ypos, m_ypos);
|
||||
return lround(sqrt(xabs*xabs + yabs*yabs));
|
||||
}
|
||||
unsigned xpos() const {
|
||||
return m_xpos;
|
||||
}
|
||||
unsigned ypos() const {
|
||||
return m_ypos;
|
||||
return lround(sqrt(xabs * xabs + yabs * yabs));
|
||||
}
|
||||
unsigned xpos() const { return m_xpos; }
|
||||
unsigned ypos() const { return m_ypos; }
|
||||
|
||||
bool operator< (const TspStateBase& other) const {
|
||||
return operator< (dynamic_cast<const TspTestState&>(other));
|
||||
}
|
||||
bool operator< (const TspTestState& other) const {
|
||||
return m_serial < other.m_serial;
|
||||
bool operator<(const TspStateBase& other) const {
|
||||
return operator<(dynamic_cast<const TspTestState&>(other));
|
||||
}
|
||||
bool operator<(const TspTestState& other) const { return m_serial < other.m_serial; }
|
||||
|
||||
private:
|
||||
unsigned m_xpos;
|
||||
unsigned m_ypos;
|
||||
|
|
@ -574,11 +549,11 @@ void V3TSP::selfTestStates() {
|
|||
// Linear test -- coords all along the x-axis
|
||||
{
|
||||
V3TSP::StateVec states;
|
||||
TspTestState s10(10,0);
|
||||
TspTestState s60(60,0);
|
||||
TspTestState s20(20,0);
|
||||
TspTestState s100(100,0);
|
||||
TspTestState s5(5,0);
|
||||
TspTestState s10(10, 0);
|
||||
TspTestState s60(60, 0);
|
||||
TspTestState s20(20, 0);
|
||||
TspTestState s100(100, 0);
|
||||
TspTestState s5(5, 0);
|
||||
states.push_back(&s10);
|
||||
states.push_back(&s60);
|
||||
states.push_back(&s20);
|
||||
|
|
@ -595,12 +570,11 @@ void V3TSP::selfTestStates() {
|
|||
expect.push_back(&s10);
|
||||
expect.push_back(&s5);
|
||||
if (VL_UNCOVERABLE(expect != result)) {
|
||||
for (V3TSP::StateVec::iterator it = result.begin();
|
||||
it != result.end(); ++it) {
|
||||
for (V3TSP::StateVec::iterator it = result.begin(); it != result.end(); ++it) {
|
||||
const TspTestState* statep = dynamic_cast<const TspTestState*>(*it);
|
||||
cout<<statep->xpos()<<" ";
|
||||
cout << statep->xpos() << " ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout << endl;
|
||||
v3fatalSrc("TSP linear self-test fail. Result (above) did not match expectation.");
|
||||
}
|
||||
}
|
||||
|
|
@ -609,13 +583,13 @@ void V3TSP::selfTestStates() {
|
|||
// Test that tspSort() will rotate the list for minimum cost.
|
||||
{
|
||||
V3TSP::StateVec states;
|
||||
TspTestState a(0,0);
|
||||
TspTestState b(100,0);
|
||||
TspTestState c(200,0);
|
||||
TspTestState d(200,100);
|
||||
TspTestState e(150,150);
|
||||
TspTestState f(0,150);
|
||||
TspTestState g(0,100);
|
||||
TspTestState a(0, 0);
|
||||
TspTestState b(100, 0);
|
||||
TspTestState c(200, 0);
|
||||
TspTestState d(200, 100);
|
||||
TspTestState e(150, 150);
|
||||
TspTestState f(0, 150);
|
||||
TspTestState g(0, 100);
|
||||
|
||||
states.push_back(&a);
|
||||
states.push_back(&b);
|
||||
|
|
@ -638,13 +612,13 @@ void V3TSP::selfTestStates() {
|
|||
expect.push_back(&e);
|
||||
|
||||
if (VL_UNCOVERABLE(expect != result)) {
|
||||
for (V3TSP::StateVec::iterator it = result.begin();
|
||||
it != result.end(); ++it) {
|
||||
for (V3TSP::StateVec::iterator it = result.begin(); it != result.end(); ++it) {
|
||||
const TspTestState* statep = dynamic_cast<const TspTestState*>(*it);
|
||||
cout<<statep->xpos()<<","<<statep->ypos()<<" ";
|
||||
cout << statep->xpos() << "," << statep->ypos() << " ";
|
||||
}
|
||||
cout<<endl;
|
||||
v3fatalSrc("TSP 2d cycle=false self-test fail. Result (above) did not match expectation.");
|
||||
cout << endl;
|
||||
v3fatalSrc(
|
||||
"TSP 2d cycle=false self-test fail. Result (above) did not match expectation.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -687,9 +661,9 @@ void V3TSP::selfTestString() {
|
|||
|
||||
if (VL_UNCOVERABLE(expect != result)) {
|
||||
for (std::vector<string>::const_iterator it = result.begin(); it != result.end(); ++it) {
|
||||
cout<<*it<<" ";
|
||||
cout << *it << " ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout << endl;
|
||||
v3fatalSrc("TSP string self-test fail. Result (above) did not match expectation.");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
184
src/V3Table.cpp
184
src/V3Table.cpp
|
|
@ -38,8 +38,10 @@
|
|||
// Table class functions
|
||||
|
||||
// CONFIG
|
||||
static const double TABLE_MAX_BYTES = 1*1024*1024; // 1MB is max table size (better be lots of instructs to be worth it!)
|
||||
static const double TABLE_TOTAL_BYTES = 64*1024*1024; // 64MB is close to max memory of some systems (256MB or so), so don't get out of control
|
||||
// 1MB is max table size (better be lots of instructs to be worth it!)
|
||||
static const double TABLE_MAX_BYTES = 1 * 1024 * 1024;
|
||||
// 64MB is close to max memory of some systems (256MB or so), so don't get out of control
|
||||
static const double TABLE_TOTAL_BYTES = 64 * 1024 * 1024;
|
||||
static const double TABLE_SPACE_TIME_MULT = 8; // Worth 8 bytes of data to replace a instruction
|
||||
static const int TABLE_MIN_NODE_COUNT = 32; // If < 32 instructions, not worth the effort
|
||||
|
||||
|
|
@ -52,12 +54,11 @@ class TableSimulateVisitor : public SimulateVisitor {
|
|||
TableVisitor* m_cbthis; ///< Class for callback
|
||||
|
||||
public:
|
||||
virtual void varRefCb(AstVarRef* nodep); ///< Call other-this function on all new var references
|
||||
///< Call other-this function on all new var references
|
||||
virtual void varRefCb(AstVarRef* nodep);
|
||||
|
||||
// CONSTRUCTORS
|
||||
explicit TableSimulateVisitor(TableVisitor* cbthis) {
|
||||
m_cbthis = cbthis;
|
||||
}
|
||||
explicit TableSimulateVisitor(TableVisitor* cbthis) { m_cbthis = cbthis; }
|
||||
virtual ~TableSimulateVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -70,28 +71,28 @@ private:
|
|||
// Cleared on each always/assignw
|
||||
|
||||
// STATE
|
||||
double m_totalBytes; // Total bytes in tables created
|
||||
VDouble0 m_statTablesCre; // Statistic tracking
|
||||
double m_totalBytes; // Total bytes in tables created
|
||||
VDouble0 m_statTablesCre; // Statistic tracking
|
||||
|
||||
// State cleared on each module
|
||||
AstNodeModule* m_modp; // Current MODULE
|
||||
int m_modTables; // Number of tables created in this module
|
||||
AstNodeModule* m_modp; // Current MODULE
|
||||
int m_modTables; // Number of tables created in this module
|
||||
typedef std::deque<AstVarScope*> ModTableVector;
|
||||
ModTableVector m_modTableVscs; // All tables created
|
||||
|
||||
// State cleared on each scope
|
||||
AstScope* m_scopep; // Current SCOPE
|
||||
AstScope* m_scopep; // Current SCOPE
|
||||
|
||||
// State cleared on each always/assignw
|
||||
bool m_assignDly; // Consists of delayed assignments instead of normal assignments
|
||||
int m_inWidth; // Input table width
|
||||
int m_outWidth; // Output table width
|
||||
bool m_assignDly; // Consists of delayed assignments instead of normal assignments
|
||||
int m_inWidth; // Input table width
|
||||
int m_outWidth; // Output table width
|
||||
std::deque<AstVarScope*> m_inVarps; // Input variable list
|
||||
std::deque<AstVarScope*> m_outVarps; // Output variable list
|
||||
std::deque<bool> m_outNotSet; // True if output variable is not set at some point
|
||||
std::deque<AstVarScope*> m_outVarps; // Output variable list
|
||||
std::deque<bool> m_outNotSet; // True if output variable is not set at some point
|
||||
|
||||
// When creating a table
|
||||
std::deque<AstVarScope*> m_tableVarps; // Table being created
|
||||
std::deque<AstVarScope*> m_tableVarps; // Table being created
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -105,7 +106,7 @@ private:
|
|||
m_outNotSet.clear();
|
||||
|
||||
// Collect stats
|
||||
TableSimulateVisitor chkvis (this);
|
||||
TableSimulateVisitor chkvis(this);
|
||||
chkvis.mainTableCheck(nodep);
|
||||
m_assignDly = chkvis.isAssignDly();
|
||||
// Also sets m_inWidth
|
||||
|
|
@ -115,12 +116,12 @@ private:
|
|||
|
||||
// Calc data storage in bytes
|
||||
size_t chgWidth = m_outVarps.size(); // Width of one change-it-vector
|
||||
if (chgWidth<8) chgWidth = 8;
|
||||
if (chgWidth < 8) chgWidth = 8;
|
||||
double space = (pow(static_cast<double>(2.0), static_cast<double>(m_inWidth))
|
||||
* static_cast<double>(m_outWidth + chgWidth));
|
||||
// Instruction count bytes (ok, it's space also not time :)
|
||||
double bytesPerInst = 4;
|
||||
double time = ((chkvis.instrCount()*bytesPerInst + chkvis.dataCount())
|
||||
double time = ((chkvis.instrCount() * bytesPerInst + chkvis.dataCount())
|
||||
+ 1); // +1 so won't div by zero
|
||||
if (chkvis.instrCount() < TABLE_MIN_NODE_COUNT) {
|
||||
chkvis.clearOptimizable(nodep, "Table has too few nodes involved");
|
||||
|
|
@ -134,16 +135,15 @@ private:
|
|||
if (m_totalBytes > TABLE_TOTAL_BYTES) {
|
||||
chkvis.clearOptimizable(nodep, "Table out of memory");
|
||||
}
|
||||
if (!m_outWidth || !m_inWidth) {
|
||||
chkvis.clearOptimizable(nodep, "Table has no outputs");
|
||||
}
|
||||
UINFO(4, " Test: Opt="<<(chkvis.optimizable()?"OK":"NO")
|
||||
<<", Instrs="<<chkvis.instrCount()<<" Data="<<chkvis.dataCount()
|
||||
<<" inw="<<m_inWidth<<" outw="<<m_outWidth
|
||||
<<" Spacetime="<<(space/time)<<"("<<space<<"/"<<time<<")"
|
||||
<<": "<<nodep<<endl);
|
||||
if (!m_outWidth || !m_inWidth) { chkvis.clearOptimizable(nodep, "Table has no outputs"); }
|
||||
UINFO(4, " Test: Opt=" << (chkvis.optimizable() ? "OK" : "NO")
|
||||
<< ", Instrs=" << chkvis.instrCount()
|
||||
<< " Data=" << chkvis.dataCount() << " inw=" << m_inWidth
|
||||
<< " outw=" << m_outWidth << " Spacetime=" << (space / time) << "("
|
||||
<< space << "/" << time << ")"
|
||||
<< ": " << nodep << endl);
|
||||
if (chkvis.optimizable()) {
|
||||
UINFO(3, " Table Optimize spacetime="<<(space/time)<<" "<<nodep<<endl);
|
||||
UINFO(3, " Table Optimize spacetime=" << (space / time) << " " << nodep << endl);
|
||||
m_totalBytes += space;
|
||||
}
|
||||
return chkvis.optimizable();
|
||||
|
|
@ -152,7 +152,7 @@ private:
|
|||
public:
|
||||
void simulateVarRefCb(AstVarRef* nodep) {
|
||||
// Called by TableSimulateVisitor on each unique varref encountered
|
||||
UINFO(9," SimVARREF "<<nodep<<endl);
|
||||
UINFO(9, " SimVARREF " << nodep << endl);
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
if (nodep->lvalue()) {
|
||||
m_outWidth += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
|
||||
|
|
@ -172,25 +172,21 @@ private:
|
|||
++m_statTablesCre;
|
||||
|
||||
// Index into our table
|
||||
AstVar* indexVarp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP,
|
||||
"__Vtableidx" + cvtToStr(m_modTables),
|
||||
VFlagBitPacked(), m_inWidth);
|
||||
AstVar* indexVarp
|
||||
= new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP,
|
||||
"__Vtableidx" + cvtToStr(m_modTables), VFlagBitPacked(), m_inWidth);
|
||||
m_modp->addStmtp(indexVarp);
|
||||
AstVarScope* indexVscp = new AstVarScope(indexVarp->fileline(), m_scopep, indexVarp);
|
||||
m_scopep->addVarp(indexVscp);
|
||||
|
||||
// Change it variable
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNodeArrayDType* dtypep
|
||||
= new AstUnpackArrayDType(fl,
|
||||
nodep->findBitDType(m_outVarps.size(),
|
||||
m_outVarps.size(), AstNumeric::UNSIGNED),
|
||||
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
||||
AstNodeArrayDType* dtypep = new AstUnpackArrayDType(
|
||||
fl, nodep->findBitDType(m_outVarps.size(), m_outVarps.size(), AstNumeric::UNSIGNED),
|
||||
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
||||
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
||||
AstVar* chgVarp
|
||||
= new AstVar(fl, AstVarType::MODULETEMP,
|
||||
"__Vtablechg" + cvtToStr(m_modTables),
|
||||
dtypep);
|
||||
AstVar* chgVarp = new AstVar(fl, AstVarType::MODULETEMP,
|
||||
"__Vtablechg" + cvtToStr(m_modTables), dtypep);
|
||||
chgVarp->isConst(true);
|
||||
chgVarp->valuep(new AstInitArray(nodep->fileline(), dtypep, NULL));
|
||||
m_modp->addStmtp(chgVarp);
|
||||
|
|
@ -215,7 +211,7 @@ private:
|
|||
// Keep sensitivity list, but delete all else
|
||||
nodeap->bodysp()->unlinkFrBackWithNext()->deleteTree();
|
||||
nodeap->addStmtp(stmtsp);
|
||||
if (debug()>=6) nodeap->dumpTree(cout, " table_new: ");
|
||||
if (debug() >= 6) nodeap->dumpTree(cout, " table_new: ");
|
||||
} else { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Creating table under unknown node type");
|
||||
}
|
||||
|
|
@ -226,23 +222,22 @@ private:
|
|||
|
||||
void createTableVars(AstNode* nodep) {
|
||||
// Create table for each output
|
||||
typedef std::map<string,int> NameCounts;
|
||||
typedef std::map<string, int> NameCounts;
|
||||
NameCounts namecounts;
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
|
||||
it != m_outVarps.end(); ++it) {
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it != m_outVarps.end();
|
||||
++it) {
|
||||
AstVarScope* outvscp = *it;
|
||||
AstVar* outvarp = outvscp->varp();
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNodeArrayDType* dtypep
|
||||
= new AstUnpackArrayDType(fl, outvarp->dtypep(),
|
||||
new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
||||
AstNodeArrayDType* dtypep = new AstUnpackArrayDType(
|
||||
fl, outvarp->dtypep(), new AstRange(fl, VL_MASK_I(m_inWidth), 0));
|
||||
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
|
||||
string name = "__Vtable"+cvtToStr(m_modTables)+"_"+outvarp->name();
|
||||
string name = "__Vtable" + cvtToStr(m_modTables) + "_" + outvarp->name();
|
||||
NameCounts::iterator nit = namecounts.find(name);
|
||||
if (nit != namecounts.end()) {
|
||||
// Multiple scopes can have same var name. We could append the
|
||||
// scope name but that is very long, so just deduplicate.
|
||||
name += "__dedup"+cvtToStr(++nit->second);
|
||||
name += "__dedup" + cvtToStr(++nit->second);
|
||||
} else {
|
||||
namecounts[name] = 0;
|
||||
}
|
||||
|
|
@ -261,18 +256,19 @@ private:
|
|||
// Concat inputs into a single temp variable (inside always)
|
||||
// First var in inVars becomes the LSB of the concat
|
||||
AstNode* concatp = NULL;
|
||||
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) {
|
||||
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin(); it != m_inVarps.end();
|
||||
++it) {
|
||||
AstVarScope* invscp = *it;
|
||||
AstVarRef* refp = new AstVarRef(nodep->fileline(), invscp, false);
|
||||
if (concatp) {
|
||||
concatp = new AstConcat(nodep->fileline(), refp, concatp);
|
||||
} else concatp = refp;
|
||||
} else {
|
||||
concatp = refp;
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* stmtsp = new AstAssign
|
||||
(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), indexVscp, true),
|
||||
concatp);
|
||||
AstNode* stmtsp = new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), indexVscp, true), concatp);
|
||||
return stmtsp;
|
||||
}
|
||||
|
||||
|
|
@ -281,15 +277,15 @@ private:
|
|||
// There may be a simulation path by which the output doesn't change value.
|
||||
// We could bail on these cases, or we can have a "change it" boolean.
|
||||
// We've chosen the latter route, since recirc is common in large FSMs.
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
|
||||
it != m_outVarps.end(); ++it) {
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it != m_outVarps.end();
|
||||
++it) {
|
||||
m_outNotSet.push_back(false);
|
||||
}
|
||||
uint32_t inValueNextInitArray = 0;
|
||||
TableSimulateVisitor simvis (this);
|
||||
for (uint32_t inValue=0; inValue <= VL_MASK_I(m_inWidth); inValue++) {
|
||||
TableSimulateVisitor simvis(this);
|
||||
for (uint32_t inValue = 0; inValue <= VL_MASK_I(m_inWidth); inValue++) {
|
||||
// Make a new simulation structure so we can set new input values
|
||||
UINFO(8," Simulating "<<std::hex<<inValue<<endl);
|
||||
UINFO(8, " Simulating " << std::hex << inValue << endl);
|
||||
|
||||
// Above simulateVisitor clears user 3, so
|
||||
// all outputs default to NULL to mean 'recirculating'.
|
||||
|
|
@ -297,42 +293,42 @@ private:
|
|||
|
||||
// Set all inputs to the constant
|
||||
uint32_t shift = 0;
|
||||
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin();
|
||||
it != m_inVarps.end(); ++it) {
|
||||
for (std::deque<AstVarScope*>::iterator it = m_inVarps.begin(); it != m_inVarps.end();
|
||||
++it) {
|
||||
AstVarScope* invscp = *it;
|
||||
// LSB is first variable, so extract it that way
|
||||
AstConst cnst(invscp->fileline(), AstConst::WidthedValue(), invscp->width(),
|
||||
VL_MASK_I(invscp->width()) & (inValue>>shift));
|
||||
VL_MASK_I(invscp->width()) & (inValue >> shift));
|
||||
simvis.newValue(invscp, &cnst);
|
||||
shift += invscp->width();
|
||||
// We're just using32 bit arithmetic, because there's no
|
||||
// way the input table can be 2^32 bytes!
|
||||
UASSERT_OBJ(shift <= 32, nodep, "shift overflow");
|
||||
UINFO(8," Input "<<invscp->name()<<" = "<<cnst.name()<<endl);
|
||||
UINFO(8, " Input " << invscp->name() << " = " << cnst.name() << endl);
|
||||
}
|
||||
|
||||
// Simulate
|
||||
simvis.mainTableEmulate(nodep);
|
||||
UASSERT_OBJ(simvis.optimizable(), simvis.whyNotNodep(),
|
||||
"Optimizable cleared, even though earlier test run said not: "
|
||||
<<simvis.whyNotMessage());
|
||||
<< simvis.whyNotMessage());
|
||||
|
||||
// If a output changed, add it to table
|
||||
int outnum = 0;
|
||||
V3Number outputChgMask (nodep, m_outVarps.size(), 0);
|
||||
V3Number outputChgMask(nodep, m_outVarps.size(), 0);
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
|
||||
it != m_outVarps.end(); ++it) {
|
||||
AstVarScope* outvscp = *it;
|
||||
V3Number* outnump = simvis.fetchOutNumberNull(outvscp);
|
||||
AstNode* setp;
|
||||
if (!outnump) {
|
||||
UINFO(8," Output "<<outvscp->name()<<" never set\n");
|
||||
UINFO(8, " Output " << outvscp->name() << " never set\n");
|
||||
m_outNotSet[outnum] = true;
|
||||
// Value in table is arbitrary, but we need something
|
||||
setp = new AstConst(outvscp->fileline(),
|
||||
AstConst::WidthedValue(), outvscp->width(), 0);
|
||||
setp = new AstConst(outvscp->fileline(), AstConst::WidthedValue(),
|
||||
outvscp->width(), 0);
|
||||
} else {
|
||||
UINFO(8," Output "<<outvscp->name()<<" = "<<*outnump<<endl);
|
||||
UINFO(8, " Output " << outvscp->name() << " = " << *outnump << endl);
|
||||
// m_tableVarps[inValue] = num;
|
||||
// Mark changed bit, too
|
||||
outputChgMask.setBit(outnum, 1);
|
||||
|
|
@ -343,7 +339,7 @@ private:
|
|||
outnum++;
|
||||
}
|
||||
|
||||
{ // Set changed table
|
||||
{ // Set changed table
|
||||
UASSERT_OBJ(inValue == inValueNextInitArray, nodep,
|
||||
"InitArray requires us to have the values in inValue order");
|
||||
inValueNextInitArray++;
|
||||
|
|
@ -359,7 +355,7 @@ private:
|
|||
AstVar* var1p = vsc1p->varp();
|
||||
for (std::deque<AstVarScope*>::iterator it = m_modTableVscs.begin();
|
||||
it != m_modTableVscs.end(); ++it) {
|
||||
AstVarScope* vsc2p= *it;
|
||||
AstVarScope* vsc2p = *it;
|
||||
AstVar* var2p = vsc2p->varp();
|
||||
if (var1p->width() == var2p->width()
|
||||
&& (var1p->dtypep()->arrayUnpackedElements()
|
||||
|
|
@ -367,7 +363,7 @@ private:
|
|||
const AstNode* init1p = VN_CAST(var1p->valuep(), InitArray);
|
||||
const AstNode* init2p = VN_CAST(var2p->valuep(), InitArray);
|
||||
if (init1p->sameGateTree(init2p)) {
|
||||
UINFO(8," Duplicate table var "<<vsc2p<<" == "<<vsc1p<<endl);
|
||||
UINFO(8, " Duplicate table var " << vsc2p << " == " << vsc1p << endl);
|
||||
VL_DO_DANGLING(vsc1p->unlinkFrBack()->deleteTree(), vsc1p);
|
||||
return vsc2p;
|
||||
}
|
||||
|
|
@ -377,31 +373,30 @@ private:
|
|||
return vsc1p;
|
||||
}
|
||||
|
||||
void createOutputAssigns(AstNode* nodep, AstNode* stmtsp,
|
||||
AstVarScope* indexVscp, AstVarScope* chgVscp) {
|
||||
void createOutputAssigns(AstNode* nodep, AstNode* stmtsp, AstVarScope* indexVscp,
|
||||
AstVarScope* chgVscp) {
|
||||
// We walk through the changemask table, and if all ones know
|
||||
// the output is set on all branches and therefore eliminate the
|
||||
// if. If all uses of the changemask disappear, dead code
|
||||
// elimination will remove it for us.
|
||||
// Set each output from array ref into our table
|
||||
int outnum = 0;
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin();
|
||||
it != m_outVarps.end(); ++it) {
|
||||
for (std::deque<AstVarScope*>::iterator it = m_outVarps.begin(); it != m_outVarps.end();
|
||||
++it) {
|
||||
AstVarScope* outvscp = *it;
|
||||
AstNode* alhsp = new AstVarRef(nodep->fileline(), outvscp, true);
|
||||
AstNode* arhsp
|
||||
= new AstArraySel(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false),
|
||||
new AstVarRef(nodep->fileline(), indexVscp, false));
|
||||
AstNode* arhsp = new AstArraySel(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), m_tableVarps[outnum], false),
|
||||
new AstVarRef(nodep->fileline(), indexVscp, false));
|
||||
AstNode* outasnp
|
||||
= (m_assignDly
|
||||
? static_cast<AstNode*>(new AstAssignDly(nodep->fileline(), alhsp, arhsp))
|
||||
: static_cast<AstNode*>(new AstAssign(nodep->fileline(), alhsp, arhsp)));
|
||||
? static_cast<AstNode*>(new AstAssignDly(nodep->fileline(), alhsp, arhsp))
|
||||
: static_cast<AstNode*>(new AstAssign(nodep->fileline(), alhsp, arhsp)));
|
||||
AstNode* outsetp = outasnp;
|
||||
|
||||
// Is the value set in only some branches of the table?
|
||||
if (m_outNotSet[outnum]) {
|
||||
V3Number outputChgMask (nodep, m_outVarps.size(), 0);
|
||||
V3Number outputChgMask(nodep, m_outVarps.size(), 0);
|
||||
outputChgMask.setBit(outnum, 1);
|
||||
outsetp = new AstIf(
|
||||
nodep->fileline(),
|
||||
|
|
@ -418,11 +413,8 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
int origModTables = m_modTables;
|
||||
|
|
@ -438,13 +430,13 @@ private:
|
|||
m_modTableVscs = origModTableVscs;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
m_scopep = nodep;
|
||||
iterateChildren(nodep);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
UINFO(4," ALWAYS "<<nodep<<endl);
|
||||
UINFO(4, " ALWAYS " << nodep << endl);
|
||||
if (treeTest(nodep)) {
|
||||
// Well, then, I'll be a memory hog.
|
||||
VL_DO_DANGLING(createTable(nodep), nodep);
|
||||
|
|
@ -470,7 +462,7 @@ public:
|
|||
m_totalBytes = 0;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~TableVisitor() {
|
||||
virtual ~TableVisitor() { //
|
||||
V3Stats::addStat("Optimizations, Tables created", m_statTablesCre);
|
||||
}
|
||||
};
|
||||
|
|
@ -487,9 +479,7 @@ void TableSimulateVisitor::varRefCb(AstVarRef* nodep) {
|
|||
// Table class functions
|
||||
|
||||
void V3Table::tableAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
TableVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ TableVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("table", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
526
src/V3Task.cpp
526
src/V3Task.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -551,7 +551,7 @@ private:
|
|||
// Assign trace code, add to tree, return node for change tree or null
|
||||
// Look for identical copies
|
||||
uint32_t codePreassigned = 0;
|
||||
// if (debug()>=9) nodep->dumpTree(cout, "- assnnode: ");
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, "- assnnode: ");
|
||||
// Find non-duplicated node; note some nodep's maybe null, as they were deleted below
|
||||
TraceTraceVertex* dupvertexp = vvertexp;
|
||||
if (dupvertexp->duplicatep()) {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -51,16 +51,12 @@ class UndrivenVarEntry {
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit UndrivenVarEntry(AstVar* varp) { // Construction for when a var is used
|
||||
UINFO(9, "create "<<varp<<endl);
|
||||
UINFO(9, "create " << varp << endl);
|
||||
m_varp = varp;
|
||||
m_wholeFlags.resize(FLAGS_PER_BIT);
|
||||
for (int i = 0; i < FLAGS_PER_BIT; i++) {
|
||||
m_wholeFlags[i] = false;
|
||||
}
|
||||
for (int i = 0; i < FLAGS_PER_BIT; i++) m_wholeFlags[i] = false;
|
||||
m_bitFlags.resize(varp->width() * FLAGS_PER_BIT);
|
||||
for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) {
|
||||
m_bitFlags[i] = false;
|
||||
}
|
||||
for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) m_bitFlags[i] = false;
|
||||
}
|
||||
~UndrivenVarEntry() {}
|
||||
|
||||
|
|
@ -81,60 +77,63 @@ private:
|
|||
bool prev = false;
|
||||
int msb = 0;
|
||||
// bit==-1 loops below; we do one extra iteration so end with prev=false
|
||||
for (int bit=(m_bitFlags.size()/FLAGS_PER_BIT)-1; bit >= -1; --bit) {
|
||||
if (bit>=0
|
||||
for (int bit = (m_bitFlags.size() / FLAGS_PER_BIT) - 1; bit >= -1; --bit) {
|
||||
if (bit >= 0
|
||||
&& ((which == BN_UNUSED && !usedFlag(bit) && drivenFlag(bit))
|
||||
|| (which == BN_UNDRIVEN && usedFlag(bit) && !drivenFlag(bit))
|
||||
|| (which == BN_BOTH && !usedFlag(bit) && !drivenFlag(bit)))) {
|
||||
if (!prev) { prev=true; msb = bit; }
|
||||
if (!prev) {
|
||||
prev = true;
|
||||
msb = bit;
|
||||
}
|
||||
} else if (prev) {
|
||||
AstBasicDType* bdtypep = m_varp->basicp();
|
||||
int lsb = bit+1;
|
||||
int lsb = bit + 1;
|
||||
if (bits != "") bits += ",";
|
||||
if (lsb==msb) {
|
||||
bits += cvtToStr(lsb+bdtypep->lsb());
|
||||
if (lsb == msb) {
|
||||
bits += cvtToStr(lsb + bdtypep->lsb());
|
||||
} else {
|
||||
if (bdtypep->littleEndian()) {
|
||||
bits += cvtToStr(lsb+bdtypep->lsb())+":"+cvtToStr(msb+bdtypep->lsb());
|
||||
bits += cvtToStr(lsb + bdtypep->lsb()) + ":"
|
||||
+ cvtToStr(msb + bdtypep->lsb());
|
||||
} else {
|
||||
bits += cvtToStr(msb+bdtypep->lsb())+":"+cvtToStr(lsb+bdtypep->lsb());
|
||||
bits += cvtToStr(msb + bdtypep->lsb()) + ":"
|
||||
+ cvtToStr(lsb + bdtypep->lsb());
|
||||
}
|
||||
}
|
||||
prev = false;
|
||||
}
|
||||
}
|
||||
return "["+bits+"]";
|
||||
return "[" + bits + "]";
|
||||
}
|
||||
|
||||
public:
|
||||
void usedWhole() {
|
||||
UINFO(9, "set u[*] "<<m_varp->name()<<endl);
|
||||
UINFO(9, "set u[*] " << m_varp->name() << endl);
|
||||
m_wholeFlags[FLAG_USED] = true;
|
||||
}
|
||||
void drivenWhole() {
|
||||
UINFO(9, "set d[*] "<<m_varp->name()<<endl);
|
||||
UINFO(9, "set d[*] " << m_varp->name() << endl);
|
||||
m_wholeFlags[FLAG_DRIVEN] = true;
|
||||
}
|
||||
void usedBit(int bit, int width) {
|
||||
UINFO(9, "set u["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
|
||||
UINFO(9, "set u[" << (bit + width - 1) << ":" << bit << "] " << m_varp->name() << endl);
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (bitNumOk(bit + i)) {
|
||||
m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED] = true;
|
||||
}
|
||||
if (bitNumOk(bit + i)) m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED] = true;
|
||||
}
|
||||
}
|
||||
void drivenBit(int bit, int width) {
|
||||
UINFO(9, "set d["<<(bit+width-1)<<":"<<bit<<"] "<<m_varp->name()<<endl);
|
||||
UINFO(9, "set d[" << (bit + width - 1) << ":" << bit << "] " << m_varp->name() << endl);
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (bitNumOk(bit + i)) {
|
||||
m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN] = true;
|
||||
}
|
||||
if (bitNumOk(bit + i)) m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN] = true;
|
||||
}
|
||||
}
|
||||
bool isUsedNotDrivenBit(int bit, int width) const {
|
||||
for (int i = 0; i < width; i++) {
|
||||
if (bitNumOk(bit + i)
|
||||
&& (m_wholeFlags[FLAG_USED] || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_USED])
|
||||
&& !(m_wholeFlags[FLAG_DRIVEN] || m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN]))
|
||||
&& !(m_wholeFlags[FLAG_DRIVEN]
|
||||
|| m_bitFlags[(bit + i) * FLAGS_PER_BIT + FLAG_DRIVEN]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -183,39 +182,43 @@ public:
|
|||
// UNDRIVEN is considered more serious - as is more likely a bug,
|
||||
// thus undriven+unused bits get UNUSED warnings, as they're not as buggy.
|
||||
if (!unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSED, "Signal is not driven, nor used: "
|
||||
<<nodep->prettyNameQ());
|
||||
nodep->v3warn(UNUSED,
|
||||
"Signal is not driven, nor used: " << nodep->prettyNameQ());
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||
}
|
||||
} else if (allD && !anyU) {
|
||||
if (!unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSED, "Signal is not used: "<<nodep->prettyNameQ());
|
||||
nodep->v3warn(UNUSED, "Signal is not used: " << nodep->prettyNameQ());
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||
}
|
||||
} else if (!anyD && allU) {
|
||||
nodep->v3warn(UNDRIVEN, "Signal is not driven: "<<nodep->prettyNameQ());
|
||||
nodep->v3warn(UNDRIVEN, "Signal is not driven: " << nodep->prettyNameQ());
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once
|
||||
} else {
|
||||
// Bits have different dispositions
|
||||
bool setU=false; bool setD=false;
|
||||
bool setU = false;
|
||||
bool setD = false;
|
||||
if (anynotDU && !unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSED, "Bits of signal are not driven, nor used: "
|
||||
<<nodep->prettyNameQ()
|
||||
<<bitNames(BN_BOTH));
|
||||
<< nodep->prettyNameQ() << bitNames(BN_BOTH));
|
||||
setU = true;
|
||||
}
|
||||
if (anyDnotU && !unusedMatch(nodep)) {
|
||||
nodep->v3warn(UNUSED, "Bits of signal are not used: "<<nodep->prettyNameQ()
|
||||
<<bitNames(BN_UNUSED));
|
||||
nodep->v3warn(UNUSED, "Bits of signal are not used: " << nodep->prettyNameQ()
|
||||
<< bitNames(BN_UNUSED));
|
||||
setU = true;
|
||||
}
|
||||
if (anyUnotD) {
|
||||
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "<<nodep->prettyNameQ()
|
||||
<<bitNames(BN_UNDRIVEN));
|
||||
nodep->v3warn(UNDRIVEN, "Bits of signal are not driven: "
|
||||
<< nodep->prettyNameQ() << bitNames(BN_UNDRIVEN));
|
||||
setD = true;
|
||||
}
|
||||
if (setU) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true); // Warn only once
|
||||
if (setD) nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true); // Warn only once
|
||||
if (setU) { // Warn only once
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNUSED, true);
|
||||
}
|
||||
if (setD) { // Warn only once
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNDRIVEN, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -246,17 +249,21 @@ private:
|
|||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
UndrivenVarEntry* getEntryp(AstVar* nodep, int which_user) {
|
||||
if (!(which_user==1 ? nodep->user1p() : nodep->user2p())) {
|
||||
if (!(which_user == 1 ? nodep->user1p() : nodep->user2p())) {
|
||||
UndrivenVarEntry* entryp = new UndrivenVarEntry(nodep);
|
||||
//UINFO(9," Associate u="<<which_user<<" "<<cvtToHex(this)<<" "<<nodep->name()<<endl);
|
||||
// UINFO(9," Associate u="<<which_user<<" "<<cvtToHex(this)<<" "<<nodep->name()<<endl);
|
||||
m_entryps[which_user].push_back(entryp);
|
||||
if (which_user==1) nodep->user1p(entryp);
|
||||
else if (which_user==2) nodep->user2p(entryp);
|
||||
else nodep->v3fatalSrc("Bad case");
|
||||
if (which_user == 1) {
|
||||
nodep->user1p(entryp);
|
||||
} else if (which_user == 2) {
|
||||
nodep->user2p(entryp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad case");
|
||||
}
|
||||
return entryp;
|
||||
} else {
|
||||
UndrivenVarEntry* entryp = reinterpret_cast<UndrivenVarEntry*>
|
||||
(which_user==1 ? nodep->user1p() : nodep->user2p());
|
||||
UndrivenVarEntry* entryp = reinterpret_cast<UndrivenVarEntry*>(
|
||||
which_user == 1 ? nodep->user1p() : nodep->user2p());
|
||||
return entryp;
|
||||
}
|
||||
}
|
||||
|
|
@ -266,35 +273,33 @@ private:
|
|||
if (!varp->isParam() && !varp->isGenVar() && !varp->isUsedLoopIdx()
|
||||
&& !m_inBBox // We may have falsely considered a SysIgnore as a driver
|
||||
&& !VN_IS(nodep, VarXRef) // Xrefs might point at two different instances
|
||||
&& !varp->fileline()->warnIsOff(V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable
|
||||
nodep->v3warn(ALWCOMBORDER, "Always_comb variable driven after use: "
|
||||
<<nodep->prettyNameQ());
|
||||
varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER, true); // Complain just once for any usage
|
||||
&& !varp->fileline()->warnIsOff(
|
||||
V3ErrorCode::ALWCOMBORDER)) { // Warn only once per variable
|
||||
nodep->v3warn(ALWCOMBORDER,
|
||||
"Always_comb variable driven after use: " << nodep->prettyNameQ());
|
||||
varp->fileline()->modifyWarnOff(V3ErrorCode::ALWCOMBORDER,
|
||||
true); // Complain just once for any usage
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVar* nodep) VL_OVERRIDE {
|
||||
for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) {
|
||||
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
|
||||
// For assigns and non-combo always, do just usr==1, to look
|
||||
// for module-wide undriven etc.
|
||||
// For non-combo always, run both usr==1 for above, and also
|
||||
// usr==2 for always-only checks.
|
||||
UndrivenVarEntry* entryp = getEntryp(nodep, usr);
|
||||
if (nodep->isNonOutput()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
if (nodep->isNonOutput() || nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
entryp->drivenWhole();
|
||||
}
|
||||
if (nodep->isWritable()
|
||||
|| nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
if (nodep->isWritable() || nodep->isSigPublic() || nodep->isSigUserRWPublic()
|
||||
|| nodep->isSigUserRdPublic()
|
||||
|| (m_taskp && (m_taskp->dpiImport() || m_taskp->dpiExport()))) {
|
||||
entryp->usedWhole();
|
||||
}
|
||||
if (nodep->valuep()) {
|
||||
entryp->drivenWhole();
|
||||
}
|
||||
if (nodep->valuep()) entryp->drivenWhole();
|
||||
}
|
||||
// Discover variables used in bit definitions, etc
|
||||
iterateChildren(nodep);
|
||||
|
|
@ -311,14 +316,14 @@ private:
|
|||
AstNodeVarRef* varrefp = VN_CAST(nodep->fromp(), NodeVarRef);
|
||||
AstConst* constp = VN_CAST(nodep->lsbp(), Const);
|
||||
if (varrefp && constp && !constp->num().isFourState()) {
|
||||
for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) {
|
||||
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
|
||||
UndrivenVarEntry* entryp = getEntryp(varrefp->varp(), usr);
|
||||
int lsb = constp->toUInt();
|
||||
if (m_inBBox || varrefp->lvalue()) {
|
||||
// Don't warn if already driven earlier as "a=0; if(a) a=1;" is fine.
|
||||
if (usr==2 && m_alwaysCombp
|
||||
if (usr == 2 && m_alwaysCombp
|
||||
&& entryp->isUsedNotDrivenBit(lsb, nodep->width())) {
|
||||
UINFO(9," Select. Entryp="<<cvtToHex(entryp)<<endl);
|
||||
UINFO(9, " Select. Entryp=" << cvtToHex(entryp) << endl);
|
||||
warnAlwCombOrder(varrefp);
|
||||
}
|
||||
entryp->drivenBit(lsb, nodep->width());
|
||||
|
|
@ -335,25 +340,27 @@ private:
|
|||
if (nodep->lvalue()
|
||||
&& !VN_IS(nodep, VarXRef)) { // Ignore interface variables and similar ugly items
|
||||
if (m_inProcAssign && !nodep->varp()->varType().isProcAssignable()
|
||||
&& !nodep->varp()->isDeclTyped()
|
||||
&& !nodep->varp()->isClassMember()
|
||||
&& !nodep->varp()->isFuncLocal()) {
|
||||
&& !nodep->varp()->isDeclTyped() //
|
||||
&& !nodep->varp()->isClassMember() && !nodep->varp()->isFuncLocal()) {
|
||||
nodep->v3warn(PROCASSWIRE, "Procedural assignment to wire, perhaps intended var"
|
||||
<< " (IEEE 1800-2017 6.5): " << nodep->prettyNameQ());
|
||||
<< " (IEEE 1800-2017 6.5): "
|
||||
<< nodep->prettyNameQ());
|
||||
}
|
||||
if (m_inContAssign && !nodep->varp()->varType().isContAssignable()
|
||||
&& !nodep->fileline()->language().systemVerilog()) {
|
||||
nodep->v3warn(CONTASSREG, "Continuous assignment to reg, perhaps intended wire"
|
||||
<< " (IEEE 1364-2005 6.1; Verilog only, legal in SV): "
|
||||
<< nodep->prettyNameQ());
|
||||
nodep->v3warn(CONTASSREG,
|
||||
"Continuous assignment to reg, perhaps intended wire"
|
||||
<< " (IEEE 1364-2005 6.1; Verilog only, legal in SV): "
|
||||
<< nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
for (int usr=1; usr<(m_alwaysCombp?3:2); ++usr) {
|
||||
for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) {
|
||||
UndrivenVarEntry* entryp = getEntryp(nodep->varp(), usr);
|
||||
bool fdrv = nodep->lvalue() && nodep->varp()->attrFileDescr(); // FD's are also being read from
|
||||
bool fdrv = nodep->lvalue()
|
||||
&& nodep->varp()->attrFileDescr(); // FD's are also being read from
|
||||
if (m_inBBox || nodep->lvalue()) {
|
||||
if (usr==2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) {
|
||||
UINFO(9," Full bus. Entryp="<<cvtToHex(entryp)<<endl);
|
||||
if (usr == 2 && m_alwaysCombp && entryp->isUsedNotDrivenAny()) {
|
||||
UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl);
|
||||
warnAlwCombOrder(nodep);
|
||||
}
|
||||
entryp->drivenWhole();
|
||||
|
|
@ -398,11 +405,14 @@ private:
|
|||
AstAlways* prevAlwp = m_alwaysCombp;
|
||||
{
|
||||
AstNode::user2ClearTree();
|
||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," "<<nodep<<endl);
|
||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) m_alwaysCombp = nodep;
|
||||
else m_alwaysCombp = NULL;
|
||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " " << nodep << endl);
|
||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) {
|
||||
m_alwaysCombp = nodep;
|
||||
} else {
|
||||
m_alwaysCombp = NULL;
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9," Done "<<nodep<<endl);
|
||||
if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " Done " << nodep << endl);
|
||||
}
|
||||
m_alwaysCombp = prevAlwp;
|
||||
}
|
||||
|
|
@ -456,6 +466,6 @@ public:
|
|||
// Undriven class functions
|
||||
|
||||
void V3Undriven::undrivenAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UndrivenVisitor visitor (nodep);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
UndrivenVisitor visitor(nodep);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,15 +49,15 @@ private:
|
|||
// AstSel::user() -> bool. Set true if already processed
|
||||
// AstArraySel::user() -> bool. Set true if already processed
|
||||
// AstNode::user2p() -> AstIf* Inserted if assignment for conditional
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Current module
|
||||
bool m_constXCvt; // Convert X's
|
||||
VDouble0 m_statUnkVars; // Statistic tracking
|
||||
AstAssignW* m_assignwp; // Current assignment
|
||||
AstAssignDly* m_assigndlyp; // Current assignment
|
||||
AstNodeModule* m_modp; // Current module
|
||||
bool m_constXCvt; // Convert X's
|
||||
VDouble0 m_statUnkVars; // Statistic tracking
|
||||
AstAssignW* m_assignwp; // Current assignment
|
||||
AstAssignDly* m_assigndlyp; // Current assignment
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
|
@ -81,7 +81,7 @@ private:
|
|||
if (m_assignwp) {
|
||||
// Wire assigns must become always statements to deal with insertion
|
||||
// of multiple statements. Perhaps someday make all wassigns into always's?
|
||||
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
|
||||
UINFO(5, " IM_WireRep " << m_assignwp << endl);
|
||||
m_assignwp->convertToAlways();
|
||||
VL_DO_CLEAR(pushDeletep(m_assignwp), m_assignwp = NULL);
|
||||
}
|
||||
|
|
@ -98,8 +98,7 @@ private:
|
|||
AstNode* prep = nodep;
|
||||
|
||||
// Scan back to put the condlvalue above all selects (IE top of the lvalue)
|
||||
while (VN_IS(prep->backp(), NodeSel)
|
||||
|| VN_IS(prep->backp(), Sel)) {
|
||||
while (VN_IS(prep->backp(), NodeSel) || VN_IS(prep->backp(), Sel)) {
|
||||
prep = prep->backp();
|
||||
}
|
||||
FileLine* fl = nodep->fileline();
|
||||
|
|
@ -111,30 +110,24 @@ private:
|
|||
UASSERT_OBJ(!needDly, prep, "Should have already converted to non-delay");
|
||||
AstNRelinker replaceHandle;
|
||||
AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
|
||||
AstNode* newp = new AstLogAnd(condp->fileline(),
|
||||
condp, earliercondp);
|
||||
UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl);
|
||||
AstNode* newp = new AstLogAnd(condp->fileline(), condp, earliercondp);
|
||||
UINFO(4, "Edit BOUNDLVALUE " << newp << endl);
|
||||
replaceHandle.relink(newp);
|
||||
}
|
||||
else {
|
||||
string name = (string("__Vlvbound")+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
|
||||
prep->dtypep());
|
||||
} else {
|
||||
string name = (string("__Vlvbound") + cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name, prep->dtypep());
|
||||
m_modp->addStmtp(varp);
|
||||
|
||||
AstNode* abovep = prep->backp(); // Grab above point before lose it w/ next replace
|
||||
prep->replaceWith(new AstVarRef(fl, varp, true));
|
||||
AstIf* newp = new AstIf(fl, condp,
|
||||
(needDly
|
||||
? static_cast<AstNode*>
|
||||
(new AstAssignDly(fl, prep,
|
||||
new AstVarRef(fl, varp, false)))
|
||||
: static_cast<AstNode*>
|
||||
(new AstAssign(fl, prep,
|
||||
new AstVarRef(fl, varp, false)))),
|
||||
(needDly ? static_cast<AstNode*>(new AstAssignDly(
|
||||
fl, prep, new AstVarRef(fl, varp, false)))
|
||||
: static_cast<AstNode*>(new AstAssign(
|
||||
fl, prep, new AstVarRef(fl, varp, false)))),
|
||||
NULL);
|
||||
newp->branchPred(VBranchPred::BP_LIKELY);
|
||||
if (debug()>=9) newp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
|
||||
abovep->addNextStmt(newp, abovep);
|
||||
prep->user2p(newp); // Save so we may LogAnd it next time
|
||||
}
|
||||
|
|
@ -142,7 +135,7 @@ private:
|
|||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
AstNodeModule* origModp = m_modp;
|
||||
{
|
||||
m_modp = nodep;
|
||||
|
|
@ -173,7 +166,7 @@ private:
|
|||
m_constXCvt = true;
|
||||
}
|
||||
void visitEqNeqCase(AstNodeBiop* nodep) {
|
||||
UINFO(4," N/EQCASE->EQ "<<nodep<<endl);
|
||||
UINFO(4, " N/EQCASE->EQ " << nodep << endl);
|
||||
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
|
||||
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
||||
if (VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const)) {
|
||||
|
|
@ -187,14 +180,16 @@ private:
|
|||
// If we got ==1'bx it can never be true (but 1'bx==1'bx can be!)
|
||||
if (((VN_IS(lhsp, Const) && VN_CAST(lhsp, Const)->num().isFourState())
|
||||
|| (VN_IS(rhsp, Const) && VN_CAST(rhsp, Const)->num().isFourState()))) {
|
||||
newp = new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
1, (VN_IS(nodep, EqCase) ? 0 : 1));
|
||||
newp = new AstConst(nodep->fileline(), AstConst::WidthedValue(), 1,
|
||||
(VN_IS(nodep, EqCase) ? 0 : 1));
|
||||
VL_DO_DANGLING(lhsp->deleteTree(), lhsp);
|
||||
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
|
||||
} else {
|
||||
if (VN_IS(nodep, EqCase)) {
|
||||
newp = new AstEq(nodep->fileline(), lhsp, rhsp);
|
||||
} else { newp = new AstNeq(nodep->fileline(), lhsp, rhsp); }
|
||||
} else {
|
||||
newp = new AstNeq(nodep->fileline(), lhsp, rhsp);
|
||||
}
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
|
|
@ -203,7 +198,7 @@ private:
|
|||
}
|
||||
}
|
||||
void visitEqNeqWild(AstNodeBiop* nodep) {
|
||||
UINFO(4," N/EQWILD->EQ "<<nodep<<endl);
|
||||
UINFO(4, " N/EQWILD->EQ " << nodep << endl);
|
||||
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
|
||||
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
||||
if (VN_IS(nodep->lhsp(), Const) && VN_IS(nodep->rhsp(), Const)) {
|
||||
|
|
@ -215,21 +210,24 @@ private:
|
|||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* newp;
|
||||
if (!VN_IS(rhsp, Const)) {
|
||||
nodep->v3error("Unsupported: RHS of ==? or !=? must be constant to be synthesizable"); // Says spec.
|
||||
nodep->v3error("Unsupported: RHS of ==? or !=? must be "
|
||||
"constant to be synthesizable"); // Says spec.
|
||||
// Replace with anything that won't cause more errors
|
||||
newp = new AstEq(nodep->fileline(), lhsp, rhsp);
|
||||
} else {
|
||||
// X or Z's become mask, ala case statements.
|
||||
V3Number nummask (rhsp, rhsp->width());
|
||||
V3Number nummask(rhsp, rhsp->width());
|
||||
nummask.opBitsNonX(VN_CAST(rhsp, Const)->num());
|
||||
V3Number numval (rhsp, rhsp->width());
|
||||
V3Number numval(rhsp, rhsp->width());
|
||||
numval.opBitsOne(VN_CAST(rhsp, Const)->num());
|
||||
AstNode* and1p = new AstAnd(nodep->fileline(), lhsp,
|
||||
new AstConst(nodep->fileline(), nummask));
|
||||
AstNode* and2p = new AstConst(nodep->fileline(), numval);
|
||||
if (VN_IS(nodep, EqWild)) {
|
||||
newp = new AstEq(nodep->fileline(), and1p, and2p);
|
||||
} else { newp = new AstNeq(nodep->fileline(), and1p, and2p); }
|
||||
newp = new AstEq(nodep->fileline(), and1p, and2p);
|
||||
} else {
|
||||
newp = new AstNeq(nodep->fileline(), and1p, and2p);
|
||||
}
|
||||
VL_DO_DANGLING(rhsp->deleteTree(), rhsp);
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
|
|
@ -239,42 +237,33 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstEqCase* nodep) VL_OVERRIDE {
|
||||
visitEqNeqCase(nodep);
|
||||
}
|
||||
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE {
|
||||
visitEqNeqCase(nodep);
|
||||
}
|
||||
virtual void visit(AstEqWild* nodep) VL_OVERRIDE {
|
||||
visitEqNeqWild(nodep);
|
||||
}
|
||||
virtual void visit(AstNeqWild* nodep) VL_OVERRIDE {
|
||||
visitEqNeqWild(nodep);
|
||||
}
|
||||
virtual void visit(AstEqCase* nodep) VL_OVERRIDE { visitEqNeqCase(nodep); }
|
||||
virtual void visit(AstNeqCase* nodep) VL_OVERRIDE { visitEqNeqCase(nodep); }
|
||||
virtual void visit(AstEqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); }
|
||||
virtual void visit(AstNeqWild* nodep) VL_OVERRIDE { visitEqNeqWild(nodep); }
|
||||
virtual void visit(AstIsUnknown* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
// Ahh, we're two state, so this is easy
|
||||
UINFO(4," ISUNKNOWN->0 "<<nodep<<endl);
|
||||
UINFO(4, " ISUNKNOWN->0 " << nodep << endl);
|
||||
AstConst* newp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
virtual void visit(AstConst* nodep) VL_OVERRIDE {
|
||||
if (m_constXCvt
|
||||
&& nodep->num().isFourState()) {
|
||||
UINFO(4," CONST4 "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout, " Const_old: ");
|
||||
if (m_constXCvt && nodep->num().isFourState()) {
|
||||
UINFO(4, " CONST4 " << nodep << endl);
|
||||
if (debug() >= 9) nodep->dumpTree(cout, " Const_old: ");
|
||||
// CONST(num) -> VARREF(newvarp)
|
||||
// -> VAR(newvarp)
|
||||
// -> INITIAL(VARREF(newvarp, OR(num_No_Xs,AND(random,num_1s_Where_X))
|
||||
V3Number numb1 (nodep, nodep->width());
|
||||
V3Number numb1(nodep, nodep->width());
|
||||
numb1.opBitsOne(nodep->num());
|
||||
V3Number numbx (nodep, nodep->width());
|
||||
V3Number numbx(nodep, nodep->width());
|
||||
numbx.opBitsXZ(nodep->num());
|
||||
if (v3Global.opt.xAssign()!="unique") {
|
||||
if (v3Global.opt.xAssign() != "unique") {
|
||||
// All X bits just become 0; fastest simulation, but not nice
|
||||
V3Number numnew (nodep, numb1.width());
|
||||
if (v3Global.opt.xAssign()=="1") {
|
||||
V3Number numnew(nodep, numb1.width());
|
||||
if (v3Global.opt.xAssign() == "1") {
|
||||
numnew.opOr(numb1, numbx);
|
||||
} else {
|
||||
numnew.opAssign(numb1);
|
||||
|
|
@ -282,42 +271,36 @@ private:
|
|||
AstConst* newp = new AstConst(nodep->fileline(), numnew);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
UINFO(4," -> "<<newp<<endl);
|
||||
UINFO(4, " -> " << newp << endl);
|
||||
} else {
|
||||
// Make a Vxrand variable
|
||||
// We use the special XTEMP type so it doesn't break pure functions
|
||||
UASSERT_OBJ(m_modp, nodep, "X number not under module");
|
||||
string newvarname = (string("__Vxrand")
|
||||
+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* newvarp
|
||||
= new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname,
|
||||
VFlagLogicPacked(), nodep->width());
|
||||
string newvarname = (string("__Vxrand") + cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::XTEMP, newvarname,
|
||||
VFlagLogicPacked(), nodep->width());
|
||||
++m_statUnkVars;
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
AstNodeVarRef* newref1p = new AstVarRef(nodep->fileline(), newvarp, false);
|
||||
replaceHandle.relink(newref1p); // Replace const with varref
|
||||
AstInitial* newinitp
|
||||
= new AstInitial(
|
||||
nodep->fileline(),
|
||||
new AstAssign(
|
||||
nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), newvarp, true),
|
||||
new AstOr(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), numb1),
|
||||
new AstAnd(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), numbx),
|
||||
new AstRand(nodep->fileline(),
|
||||
nodep->dtypep(), true)))));
|
||||
AstInitial* newinitp = new AstInitial(
|
||||
nodep->fileline(),
|
||||
new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, true),
|
||||
new AstOr(
|
||||
nodep->fileline(), new AstConst(nodep->fileline(), numb1),
|
||||
new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), numbx),
|
||||
new AstRand(nodep->fileline(), nodep->dtypep(), true)))));
|
||||
// Add inits in front of other statement.
|
||||
// In the future, we should stuff the initp into the module's constructor.
|
||||
AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext();
|
||||
m_modp->addStmtp(newvarp);
|
||||
m_modp->addStmtp(newinitp);
|
||||
m_modp->addStmtp(afterp);
|
||||
if (debug()>=9) newref1p->dumpTree(cout, " _new: ");
|
||||
if (debug()>=9) newvarp->dumpTree(cout, " _new: ");
|
||||
if (debug()>=9) newinitp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newref1p->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newvarp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newinitp->dumpTree(cout, " _new: ");
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
|
|
@ -334,13 +317,12 @@ private:
|
|||
}
|
||||
// Find range of dtype we are selecting from
|
||||
// Similar code in V3Const::warnSelect
|
||||
int maxmsb = nodep->fromp()->dtypep()->width()-1;
|
||||
if (debug()>=9) nodep->dumpTree(cout, "sel_old: ");
|
||||
int maxmsb = nodep->fromp()->dtypep()->width() - 1;
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "sel_old: ");
|
||||
|
||||
// If (maxmsb >= selected), we're in bound
|
||||
AstNode* condp = new AstGte(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(),
|
||||
AstConst::WidthedValue(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->lsbp()->width(), maxmsb),
|
||||
nodep->lsbp()->cloneTree(false));
|
||||
// See if the condition is constant true (e.g. always in bound due to constant select)
|
||||
|
|
@ -349,24 +331,20 @@ private:
|
|||
if (condp->isOne()) {
|
||||
// We don't need to add a conditional; we know the existing expression is ok
|
||||
VL_DO_DANGLING(condp->deleteTree(), condp);
|
||||
}
|
||||
else if (!lvalue) {
|
||||
} else if (!lvalue) {
|
||||
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
V3Number xnum (nodep, nodep->width());
|
||||
V3Number xnum(nodep, nodep->width());
|
||||
xnum.setAllBitsX();
|
||||
AstNode* newp = new AstCondBound(nodep->fileline(),
|
||||
condp,
|
||||
nodep,
|
||||
AstNode* newp = new AstCondBound(nodep->fileline(), condp, nodep,
|
||||
new AstConst(nodep->fileline(), xnum));
|
||||
if (debug()>=9) newp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
|
||||
// Link in conditional
|
||||
replaceHandle.relink(newp);
|
||||
// Added X's, tristate them too
|
||||
iterate(newp);
|
||||
}
|
||||
else { // lvalue
|
||||
} else { // lvalue
|
||||
replaceBoundLvalue(nodep, condp);
|
||||
}
|
||||
}
|
||||
|
|
@ -378,7 +356,7 @@ private:
|
|||
virtual void visit(AstArraySel* nodep) VL_OVERRIDE {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
if (debug()==9) nodep->dumpTree(cout, "-in: ");
|
||||
if (debug() == 9) nodep->dumpTree(cout, "-in: ");
|
||||
// Guard against reading/writing past end of arrays
|
||||
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
|
||||
bool lvalue = false;
|
||||
|
|
@ -396,57 +374,51 @@ private:
|
|||
if (const AstNodeArrayDType* adtypep = VN_CAST(dtypep, NodeArrayDType)) {
|
||||
declElements = adtypep->elementsConst();
|
||||
} else {
|
||||
nodep->v3error("Select from non-array "<<dtypep->prettyTypeName());
|
||||
nodep->v3error("Select from non-array " << dtypep->prettyTypeName());
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout, "arraysel_old: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "arraysel_old: ");
|
||||
|
||||
// See if the condition is constant true
|
||||
AstNode* condp = new AstGte(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(),
|
||||
nodep->bitp()->width(), declElements-1),
|
||||
nodep->bitp()->width(), declElements - 1),
|
||||
nodep->bitp()->cloneTree(false));
|
||||
// Note below has null backp(); the Edit function knows how to deal with that.
|
||||
condp = V3Const::constifyEdit(condp);
|
||||
if (condp->isOne()) {
|
||||
// We don't need to add a conditional; we know the existing expression is ok
|
||||
VL_DO_DANGLING(condp->deleteTree(), condp);
|
||||
}
|
||||
else if (!lvalue
|
||||
// Making a scalar would break if we're making an array
|
||||
&& !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
} else if (!lvalue
|
||||
// Making a scalar would break if we're making an array
|
||||
&& !VN_IS(nodep->dtypep()->skipRefp(), NodeArrayDType)) {
|
||||
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
|
||||
AstNRelinker replaceHandle;
|
||||
nodep->unlinkFrBack(&replaceHandle);
|
||||
V3Number xnum (nodep, nodep->width());
|
||||
V3Number xnum(nodep, nodep->width());
|
||||
if (nodep->isString()) {
|
||||
xnum = V3Number(V3Number::String(), nodep, "");
|
||||
} else {
|
||||
xnum.setAllBitsX();
|
||||
}
|
||||
AstNode* newp = new AstCondBound(nodep->fileline(),
|
||||
condp, nodep,
|
||||
AstNode* newp = new AstCondBound(nodep->fileline(), condp, nodep,
|
||||
new AstConst(nodep->fileline(), xnum));
|
||||
if (debug()>=9) newp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
|
||||
// Link in conditional, can blow away temp xor
|
||||
replaceHandle.relink(newp);
|
||||
// Added X's, tristate them too
|
||||
iterate(newp);
|
||||
}
|
||||
else if (!lvalue) { // Mid-multidimension read, just use zero
|
||||
} else if (!lvalue) { // Mid-multidimension read, just use zero
|
||||
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
|
||||
AstNRelinker replaceHandle;
|
||||
AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
|
||||
AstNode* newp = new AstCondBound(bitp->fileline(),
|
||||
condp, bitp,
|
||||
new AstConst(bitp->fileline(),
|
||||
AstConst::WidthedValue(),
|
||||
bitp->width(), 0));
|
||||
AstNode* newp = new AstCondBound(
|
||||
bitp->fileline(), condp, bitp,
|
||||
new AstConst(bitp->fileline(), AstConst::WidthedValue(), bitp->width(), 0));
|
||||
// Added X's, tristate them too
|
||||
if (debug()>=9) newp->dumpTree(cout, " _new: ");
|
||||
if (debug() >= 9) newp->dumpTree(cout, " _new: ");
|
||||
replaceHandle.relink(newp);
|
||||
iterate(newp);
|
||||
}
|
||||
else { // lvalue
|
||||
} else { // lvalue
|
||||
replaceBoundLvalue(nodep, condp);
|
||||
}
|
||||
}
|
||||
|
|
@ -463,7 +435,7 @@ public:
|
|||
m_constXCvt = false;
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~UnknownVisitor() {
|
||||
virtual ~UnknownVisitor() { //
|
||||
V3Stats::addStat("Unknowns, variables created", m_statUnkVars);
|
||||
}
|
||||
};
|
||||
|
|
@ -472,9 +444,7 @@ public:
|
|||
// Unknown class functions
|
||||
|
||||
void V3Unknown::unknownAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
UnknownVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ UnknownVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("unknown", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
|
|
|||
209
src/V3Unroll.cpp
209
src/V3Unroll.cpp
|
|
@ -43,35 +43,32 @@
|
|||
class UnrollVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVar* m_forVarp; // Iterator variable
|
||||
AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass)
|
||||
AstConst* m_varValuep; // Current value of loop
|
||||
AstNode* m_ignoreIncp; // Increment node to ignore
|
||||
bool m_varModeCheck; // Just checking RHS assignments
|
||||
bool m_varModeReplace; // Replacing varrefs
|
||||
bool m_varAssignHit; // Assign var hit
|
||||
bool m_generate; // Expand single generate For loop
|
||||
string m_beginName; // What name to give begin iterations
|
||||
VDouble0 m_statLoops; // Statistic tracking
|
||||
VDouble0 m_statIters; // Statistic tracking
|
||||
AstVar* m_forVarp; // Iterator variable
|
||||
AstVarScope* m_forVscp; // Iterator variable scope (NULL for generate pass)
|
||||
AstConst* m_varValuep; // Current value of loop
|
||||
AstNode* m_ignoreIncp; // Increment node to ignore
|
||||
bool m_varModeCheck; // Just checking RHS assignments
|
||||
bool m_varModeReplace; // Replacing varrefs
|
||||
bool m_varAssignHit; // Assign var hit
|
||||
bool m_generate; // Expand single generate For loop
|
||||
string m_beginName; // What name to give begin iterations
|
||||
VDouble0 m_statLoops; // Statistic tracking
|
||||
VDouble0 m_statIters; // Statistic tracking
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
bool cantUnroll(AstNode* nodep, const char* reason) {
|
||||
if (m_generate) {
|
||||
nodep->v3error("Unsupported: Can't unroll generate for; "<<reason);
|
||||
}
|
||||
UINFO(3," Can't Unroll: "<<reason<<" :"<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout, "-cant-");
|
||||
V3Stats::addStatSum(string("Unrolling gave up, ")+reason, 1);
|
||||
if (m_generate) nodep->v3error("Unsupported: Can't unroll generate for; " << reason);
|
||||
UINFO(3, " Can't Unroll: " << reason << " :" << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, "-cant-");
|
||||
V3Stats::addStatSum(string("Unrolling gave up, ") + reason, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
int unrollCount() {
|
||||
return m_generate ? v3Global.opt.unrollCount()*16
|
||||
: v3Global.opt.unrollCount();
|
||||
return m_generate ? v3Global.opt.unrollCount() * 16 : v3Global.opt.unrollCount();
|
||||
}
|
||||
|
||||
bool bodySizeOverRecurse(AstNode* nodep, int& bodySize, int bodyLimit) {
|
||||
|
|
@ -88,24 +85,27 @@ private:
|
|||
return bodySizeOverRecurse(nodep->nextp(), bodySize, bodyLimit);
|
||||
}
|
||||
|
||||
bool forUnrollCheck(AstNode* nodep,
|
||||
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
||||
AstNode* precondsp, AstNode* condp,
|
||||
AstNode* incp, // Maybe under nodep or in bodysp
|
||||
AstNode* bodysp) {
|
||||
bool
|
||||
forUnrollCheck(AstNode* nodep,
|
||||
AstNode* initp, // Maybe under nodep (no nextp), or standalone (ignore nextp)
|
||||
AstNode* precondsp, AstNode* condp,
|
||||
AstNode* incp, // Maybe under nodep or in bodysp
|
||||
AstNode* bodysp) {
|
||||
// To keep the IF levels low, we return as each test fails.
|
||||
UINFO(4, " FOR Check "<<nodep<<endl);
|
||||
if (initp) UINFO(6, " Init "<<initp<<endl);
|
||||
if (precondsp) UINFO(6, " Pcon "<<precondsp<<endl);
|
||||
if (condp) UINFO(6, " Cond "<<condp<<endl);
|
||||
if (incp) UINFO(6, " Inc "<<incp<<endl);
|
||||
UINFO(4, " FOR Check " << nodep << endl);
|
||||
if (initp) UINFO(6, " Init " << initp << endl);
|
||||
if (precondsp) UINFO(6, " Pcon " << precondsp << endl);
|
||||
if (condp) UINFO(6, " Cond " << condp << endl);
|
||||
if (incp) UINFO(6, " Inc " << incp << endl);
|
||||
|
||||
// Initial value check
|
||||
AstAssign* initAssp = VN_CAST(initp, Assign);
|
||||
if (!initAssp) return cantUnroll(nodep, "no initial assignment");
|
||||
UASSERT_OBJ(!(initp->nextp() && initp->nextp()!=nodep), nodep,
|
||||
UASSERT_OBJ(!(initp->nextp() && initp->nextp() != nodep), nodep,
|
||||
"initial assignment shouldn't be a list");
|
||||
if (!VN_IS(initAssp->lhsp(), VarRef)) return cantUnroll(nodep, "no initial assignment to simple variable");
|
||||
if (!VN_IS(initAssp->lhsp(), VarRef)) {
|
||||
return cantUnroll(nodep, "no initial assignment to simple variable");
|
||||
}
|
||||
//
|
||||
// Condition check
|
||||
UASSERT_OBJ(!condp->nextp(), nodep, "conditional shouldn't be a list");
|
||||
|
|
@ -118,9 +118,9 @@ private:
|
|||
m_forVarp = VN_CAST(initAssp->lhsp(), VarRef)->varp();
|
||||
m_forVscp = VN_CAST(initAssp->lhsp(), VarRef)->varScopep();
|
||||
if (VN_IS(nodep, GenFor) && !m_forVarp->isGenVar()) {
|
||||
nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->prettyNameQ()<<endl);
|
||||
}
|
||||
else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) {
|
||||
nodep->v3error("Non-genvar used in generate for: " //
|
||||
<< m_forVarp->prettyNameQ() << endl);
|
||||
} else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) {
|
||||
nodep->v3error("Genvar not legal in non-generate for (IEEE 1800-2017 27.4): "
|
||||
<< m_forVarp->prettyNameQ() << endl
|
||||
<< nodep->warnMore()
|
||||
|
|
@ -148,28 +148,33 @@ private:
|
|||
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
|
||||
|
||||
//
|
||||
if (m_forVscp) { UINFO(8, " Loop Variable: "<<m_forVscp<<endl); }
|
||||
else { UINFO(8, " Loop Variable: "<<m_forVarp<<endl); }
|
||||
if (debug()>=9) nodep->dumpTree(cout, "- for: ");
|
||||
|
||||
if (m_forVscp) {
|
||||
UINFO(8, " Loop Variable: " << m_forVscp << endl);
|
||||
} else {
|
||||
UINFO(8, " Loop Variable: " << m_forVarp << endl);
|
||||
}
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "- for: ");
|
||||
|
||||
if (!m_generate) {
|
||||
AstAssign *incpAssign = VN_CAST(incp, Assign);
|
||||
if (!canSimulate(incpAssign->rhsp())) return cantUnroll(incp, "Unable to simulate increment");
|
||||
AstAssign* incpAssign = VN_CAST(incp, Assign);
|
||||
if (!canSimulate(incpAssign->rhsp())) {
|
||||
return cantUnroll(incp, "Unable to simulate increment");
|
||||
}
|
||||
if (!canSimulate(condp)) return cantUnroll(condp, "Unable to simulate condition");
|
||||
|
||||
// Check whether to we actually want to try and unroll.
|
||||
int loops;
|
||||
if (!countLoops(initAssp, condp, incp, unrollCount(), loops))
|
||||
if (!countLoops(initAssp, condp, incp, unrollCount(), loops)) {
|
||||
return cantUnroll(nodep, "Unable to simulate loop");
|
||||
}
|
||||
|
||||
// Less than 10 statements in the body?
|
||||
int bodySize = 0;
|
||||
int bodyLimit = v3Global.opt.unrollStmts();
|
||||
if (loops>0) bodyLimit = v3Global.opt.unrollStmts() / loops;
|
||||
if (bodySizeOverRecurse(precondsp, bodySize/*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(bodysp, bodySize/*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(incp, bodySize/*ref*/, bodyLimit)) {
|
||||
if (loops > 0) bodyLimit = v3Global.opt.unrollStmts() / loops;
|
||||
if (bodySizeOverRecurse(precondsp, bodySize /*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(bodysp, bodySize /*ref*/, bodyLimit)
|
||||
|| bodySizeOverRecurse(incp, bodySize /*ref*/, bodyLimit)) {
|
||||
return cantUnroll(nodep, "too many statements");
|
||||
}
|
||||
}
|
||||
|
|
@ -182,7 +187,7 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool canSimulate(AstNode *nodep) {
|
||||
bool canSimulate(AstNode* nodep) {
|
||||
SimulateVisitor simvis;
|
||||
AstNode* clonep = nodep->cloneTree(true);
|
||||
simvis.mainCheckTree(clonep);
|
||||
|
|
@ -190,8 +195,8 @@ private:
|
|||
return simvis.optimizable();
|
||||
}
|
||||
|
||||
bool simulateTree(AstNode *nodep, const V3Number *loopValue,
|
||||
AstNode *dtypep, V3Number &outNum) {
|
||||
bool simulateTree(AstNode* nodep, const V3Number* loopValue, AstNode* dtypep,
|
||||
V3Number& outNum) {
|
||||
AstNode* clonep = nodep->cloneTree(true);
|
||||
UASSERT_OBJ(clonep, nodep, "Failed to clone tree");
|
||||
if (loopValue) {
|
||||
|
|
@ -210,7 +215,7 @@ private:
|
|||
simvis.mainParamEmulate(clonep);
|
||||
if (!simvis.optimizable()) {
|
||||
UINFO(3, "Unable to simulate" << endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout, "- _simtree: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "- _simtree: ");
|
||||
VL_DO_DANGLING(clonep->deleteTree(), clonep);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -223,7 +228,7 @@ private:
|
|||
}
|
||||
// Patch up datatype
|
||||
if (dtypep) {
|
||||
AstConst new_con (clonep->fileline(), *res);
|
||||
AstConst new_con(clonep->fileline(), *res);
|
||||
new_con.dtypeFrom(dtypep);
|
||||
outNum = new_con.num();
|
||||
VL_DO_DANGLING(clonep->deleteTree(), clonep);
|
||||
|
|
@ -234,20 +239,18 @@ private:
|
|||
return true;
|
||||
}
|
||||
|
||||
bool countLoops(AstAssign *initp, AstNode *condp, AstNode *incp, int max, int &outLoopsr) {
|
||||
bool countLoops(AstAssign* initp, AstNode* condp, AstNode* incp, int max, int& outLoopsr) {
|
||||
outLoopsr = 0;
|
||||
V3Number loopValue = V3Number(initp);
|
||||
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) {
|
||||
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { //
|
||||
return false;
|
||||
}
|
||||
while (true) {
|
||||
V3Number res = V3Number(initp);
|
||||
if (!simulateTree(condp, &loopValue, NULL, res)) {
|
||||
if (!simulateTree(condp, &loopValue, NULL, res)) { //
|
||||
return false;
|
||||
}
|
||||
if (!res.isEqOne()) {
|
||||
break;
|
||||
}
|
||||
if (!res.isEqOne()) break;
|
||||
|
||||
outLoopsr++;
|
||||
|
||||
|
|
@ -258,21 +261,16 @@ private:
|
|||
return false;
|
||||
}
|
||||
loopValue.opAssign(newLoopValue);
|
||||
if (outLoopsr > max) {
|
||||
return false;
|
||||
}
|
||||
if (outLoopsr > max) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool forUnroller(AstNode* nodep,
|
||||
AstAssign* initp,
|
||||
AstNode* condp,
|
||||
AstNode* precondsp,
|
||||
bool forUnroller(AstNode* nodep, AstAssign* initp, AstNode* condp, AstNode* precondsp,
|
||||
AstNode* incp, AstNode* bodysp) {
|
||||
UINFO(9, "forUnroller "<<nodep<<endl);
|
||||
UINFO(9, "forUnroller " << nodep << endl);
|
||||
V3Number loopValue = V3Number(nodep);
|
||||
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) {
|
||||
if (!simulateTree(initp->rhsp(), NULL, initp, loopValue)) { //
|
||||
return false;
|
||||
}
|
||||
AstNode* stmtsp = NULL;
|
||||
|
|
@ -301,7 +299,7 @@ private:
|
|||
if (stmtsp) {
|
||||
int times = 0;
|
||||
while (true) {
|
||||
UINFO(8," Looping "<<loopValue<<endl);
|
||||
UINFO(8, " Looping " << loopValue << endl);
|
||||
V3Number res = V3Number(nodep);
|
||||
if (!simulateTree(condp, &loopValue, NULL, res)) {
|
||||
nodep->v3error("Loop unrolling failed.");
|
||||
|
|
@ -309,8 +307,7 @@ private:
|
|||
}
|
||||
if (!res.isEqOne()) {
|
||||
break; // Done with the loop
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Replace iterator values with constant.
|
||||
AstNode* oneloopp = stmtsp->cloneTree(true);
|
||||
|
||||
|
|
@ -318,8 +315,8 @@ private:
|
|||
|
||||
// Iteration requires a back, so put under temporary node
|
||||
if (oneloopp) {
|
||||
AstBegin* tempp = new AstBegin(oneloopp->fileline(),
|
||||
"[EditWrapper]", oneloopp);
|
||||
AstBegin* tempp
|
||||
= new AstBegin(oneloopp->fileline(), "[EditWrapper]", oneloopp);
|
||||
m_varModeReplace = true;
|
||||
iterateAndNextNull(tempp->stmtsp());
|
||||
m_varModeReplace = false;
|
||||
|
|
@ -332,19 +329,23 @@ private:
|
|||
oneloopp = new AstBegin(oneloopp->fileline(), nname, oneloopp, true);
|
||||
}
|
||||
VL_DO_CLEAR(pushDeletep(m_varValuep), m_varValuep = NULL);
|
||||
if (newbodysp) newbodysp->addNext(oneloopp);
|
||||
else newbodysp = oneloopp;
|
||||
if (newbodysp) {
|
||||
newbodysp->addNext(oneloopp);
|
||||
} else {
|
||||
newbodysp = oneloopp;
|
||||
}
|
||||
|
||||
++m_statIters;
|
||||
if (++times > unrollCount()*3) {
|
||||
nodep->v3error("Loop unrolling took too long;"
|
||||
" probably this is an infinite loop, or set --unroll-count above "
|
||||
<<unrollCount());
|
||||
if (++times > unrollCount() * 3) {
|
||||
nodep->v3error(
|
||||
"Loop unrolling took too long;"
|
||||
" probably this is an infinite loop, or set --unroll-count above "
|
||||
<< unrollCount());
|
||||
break;
|
||||
}
|
||||
|
||||
// loopValue += valInc
|
||||
AstAssign *incpass = VN_CAST(incp, Assign);
|
||||
AstAssign* incpass = VN_CAST(incp, Assign);
|
||||
V3Number newLoopValue = V3Number(nodep);
|
||||
if (!simulateTree(incpass->rhsp(), &loopValue, incpass, newLoopValue)) {
|
||||
nodep->v3error("Loop unrolling failed");
|
||||
|
|
@ -359,13 +360,16 @@ private:
|
|||
initp = NULL;
|
||||
}
|
||||
// Replace the FOR()
|
||||
if (newbodysp) nodep->replaceWith(newbodysp);
|
||||
else nodep->unlinkFrBack();
|
||||
if (newbodysp) {
|
||||
nodep->replaceWith(newbodysp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
if (bodysp) { VL_DO_DANGLING(pushDeletep(bodysp), bodysp); }
|
||||
if (precondsp) { VL_DO_DANGLING(pushDeletep(precondsp), precondsp); }
|
||||
if (initp) { VL_DO_DANGLING(pushDeletep(initp), initp); }
|
||||
if (incp && !incp->backp()) { VL_DO_DANGLING(pushDeletep(incp), incp); }
|
||||
if (debug()>=9 && newbodysp) newbodysp->dumpTree(cout, "- _new: ");
|
||||
if (debug() >= 9 && newbodysp) newbodysp->dumpTree(cout, "- _new: ");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -374,7 +378,9 @@ private:
|
|||
if (m_varModeCheck || m_varModeReplace) {
|
||||
} else {
|
||||
// Constify before unroll call, as it may change what is underneath.
|
||||
if (nodep->precondsp()) V3Const::constifyEdit(nodep->precondsp()); // precondsp may change
|
||||
if (nodep->precondsp()) {
|
||||
V3Const::constifyEdit(nodep->precondsp()); // precondsp may change
|
||||
}
|
||||
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
|
||||
// Grab initial value
|
||||
AstNode* initp = NULL; // Should be statement before the while.
|
||||
|
|
@ -385,16 +391,17 @@ private:
|
|||
AstNode* incp = NULL; // Should be last statement
|
||||
if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp());
|
||||
// cppcheck-suppress duplicateCondition
|
||||
if (nodep->incsp()) incp = nodep->incsp();
|
||||
else {
|
||||
if (nodep->incsp()) {
|
||||
incp = nodep->incsp();
|
||||
} else {
|
||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
|
||||
if (incp) VL_DO_DANGLING(V3Const::constifyEdit(incp), incp);
|
||||
// Again, as may have changed
|
||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
|
||||
if (incp) { VL_DO_DANGLING(V3Const::constifyEdit(incp), incp); }
|
||||
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
|
||||
}
|
||||
// And check it
|
||||
if (forUnrollCheck(nodep, initp,
|
||||
nodep->precondsp(), nodep->condp(),
|
||||
incp, nodep->bodysp())) {
|
||||
if (forUnrollCheck(nodep, initp, nodep->precondsp(), nodep->condp(), incp,
|
||||
nodep->bodysp())) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
|
||||
}
|
||||
}
|
||||
|
|
@ -418,9 +425,8 @@ private:
|
|||
// condition, but they'll become while's which can be
|
||||
// deleted by V3Const.
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
} else if (forUnrollCheck(nodep, nodep->initsp(),
|
||||
NULL, nodep->condp(),
|
||||
nodep->incsp(), nodep->bodysp())) {
|
||||
} else if (forUnrollCheck(nodep, nodep->initsp(), NULL, nodep->condp(), nodep->incsp(),
|
||||
nodep->bodysp())) {
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep); // Did replacement
|
||||
} else {
|
||||
nodep->v3error("For loop doesn't have genvar index, or is malformed");
|
||||
|
|
@ -436,17 +442,13 @@ private:
|
|||
}
|
||||
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
if (m_varModeCheck
|
||||
&& nodep->varp() == m_forVarp
|
||||
&& nodep->varScopep() == m_forVscp
|
||||
if (m_varModeCheck && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
|
||||
&& nodep->lvalue()) {
|
||||
UINFO(8," Itervar assigned to: "<<nodep<<endl);
|
||||
UINFO(8, " Itervar assigned to: " << nodep << endl);
|
||||
m_varAssignHit = true;
|
||||
}
|
||||
|
||||
if (m_varModeReplace
|
||||
&& nodep->varp() == m_forVarp
|
||||
&& nodep->varScopep() == m_forVscp
|
||||
if (m_varModeReplace && nodep->varp() == m_forVarp && nodep->varScopep() == m_forVscp
|
||||
&& !nodep->lvalue()) {
|
||||
AstNode* newconstp = m_varValuep->cloneTree(false);
|
||||
nodep->replaceWith(newconstp);
|
||||
|
|
@ -492,20 +494,19 @@ public:
|
|||
//######################################################################
|
||||
// Unroll class functions
|
||||
|
||||
UnrollStateful::UnrollStateful() : m_unrollerp(new UnrollVisitor) { }
|
||||
UnrollStateful::UnrollStateful()
|
||||
: m_unrollerp(new UnrollVisitor) {}
|
||||
UnrollStateful::~UnrollStateful() { delete m_unrollerp; }
|
||||
|
||||
void UnrollStateful::unrollGen(AstNodeFor* nodep, const string& beginName) {
|
||||
UINFO(5,__FUNCTION__<<": "<<endl);
|
||||
UINFO(5, __FUNCTION__ << ": " << endl);
|
||||
m_unrollerp->process(nodep, true, beginName);
|
||||
}
|
||||
|
||||
void UnrollStateful::unrollAll(AstNetlist* nodep) {
|
||||
m_unrollerp->process(nodep, false, "");
|
||||
}
|
||||
void UnrollStateful::unrollAll(AstNetlist* nodep) { m_unrollerp->process(nodep, false, ""); }
|
||||
|
||||
void V3Unroll::unrollAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
UnrollStateful unroller;
|
||||
unroller.unrollAll(nodep);
|
||||
|
|
|
|||
2027
src/V3Width.cpp
2027
src/V3Width.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -120,13 +120,15 @@ private:
|
|||
nodep->replaceWith(newp);
|
||||
AstNode* oldp = nodep;
|
||||
nodep = newp;
|
||||
// if (debug()>4) oldp->dumpTree(cout, " fixConstSize_old: ");
|
||||
// if (debug()>4) newp->dumpTree(cout, " _new: ");
|
||||
// if (debug() > 4) oldp->dumpTree(cout, " fixConstSize_old: ");
|
||||
// if (debug() > 4) newp->dumpTree(cout, " _new: ");
|
||||
VL_DO_DANGLING(pushDeletep(oldp), oldp);
|
||||
}
|
||||
editDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { visitIterateNodeDType(nodep); }
|
||||
virtual void visit(AstNodeDType* nodep) VL_OVERRIDE { //
|
||||
visitIterateNodeDType(nodep);
|
||||
}
|
||||
virtual void visit(AstNodeUOrStructDType* nodep) VL_OVERRIDE {
|
||||
if (nodep->user1SetOnce()) return; // Process once
|
||||
visitIterateNodeDType(nodep);
|
||||
|
|
|
|||
|
|
@ -65,13 +65,16 @@ private:
|
|||
AstNodeDType* m_errp; // Node that was found, for error reporting if not known type
|
||||
AstNodeDType* m_dtypep; // Data type for the 'from' slice
|
||||
VNumRange m_fromRange; // Numeric range bounds for the 'from' slice
|
||||
FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange)
|
||||
{ m_errp = errp; m_dtypep = dtypep; m_fromRange = fromRange; }
|
||||
FromData(AstNodeDType* errp, AstNodeDType* dtypep, const VNumRange& fromRange) {
|
||||
m_errp = errp;
|
||||
m_dtypep = dtypep;
|
||||
m_fromRange = fromRange;
|
||||
}
|
||||
~FromData() {}
|
||||
};
|
||||
FromData fromDataForArray(AstNode* nodep, AstNode* basefromp) {
|
||||
// What is the data type and information for this SEL-ish's from()?
|
||||
UINFO(9," fromData start ddtypep = "<<basefromp<<endl);
|
||||
UINFO(9, " fromData start ddtypep = " << basefromp << endl);
|
||||
VNumRange fromRange; // constructs to isRanged(false)
|
||||
while (basefromp) {
|
||||
if (VN_IS(basefromp, AttrOf)) {
|
||||
|
|
@ -83,33 +86,29 @@ private:
|
|||
UASSERT_OBJ(basefromp && basefromp->dtypep(), nodep, "Select with no from dtype");
|
||||
AstNodeDType* ddtypep = basefromp->dtypep()->skipRefp();
|
||||
AstNodeDType* errp = ddtypep;
|
||||
UINFO(9," fromData.ddtypep = "<<ddtypep<<endl);
|
||||
UINFO(9, " fromData.ddtypep = " << ddtypep << endl);
|
||||
if (const AstNodeArrayDType* adtypep = VN_CAST(ddtypep, NodeArrayDType)) {
|
||||
fromRange = adtypep->declRange();
|
||||
}
|
||||
else if (VN_IS(ddtypep, AssocArrayDType)) {
|
||||
}
|
||||
else if (VN_IS(ddtypep, DynArrayDType)) {
|
||||
}
|
||||
else if (VN_IS(ddtypep, QueueDType)) {
|
||||
}
|
||||
else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) {
|
||||
} else if (VN_IS(ddtypep, AssocArrayDType)) {
|
||||
} else if (VN_IS(ddtypep, DynArrayDType)) {
|
||||
} else if (VN_IS(ddtypep, QueueDType)) {
|
||||
} else if (const AstNodeUOrStructDType* adtypep = VN_CAST(ddtypep, NodeUOrStructDType)) {
|
||||
fromRange = adtypep->declRange();
|
||||
}
|
||||
else if (AstBasicDType* adtypep = VN_CAST(ddtypep, BasicDType)) {
|
||||
} else if (AstBasicDType* adtypep = VN_CAST(ddtypep, BasicDType)) {
|
||||
if (adtypep->isString() && VN_IS(nodep, SelBit)) {
|
||||
} else if (adtypep->isRanged()) {
|
||||
UASSERT_OBJ(!(adtypep->rangep()
|
||||
&& (!VN_IS(adtypep->rangep()->msbp(), Const)
|
||||
|| !VN_IS(adtypep->rangep()->lsbp(), Const))),
|
||||
nodep, "Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
|
||||
UASSERT_OBJ(
|
||||
!(adtypep->rangep()
|
||||
&& (!VN_IS(adtypep->rangep()->msbp(), Const)
|
||||
|| !VN_IS(adtypep->rangep()->lsbp(), Const))),
|
||||
nodep,
|
||||
"Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
|
||||
fromRange = adtypep->declRange();
|
||||
} else {
|
||||
nodep->v3error("Illegal bit or array select; type does not have a bit range, or "
|
||||
<< "bad dimension: data type is " << errp->prettyDTypeNameQ());
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: "
|
||||
<< "data type is " << errp->prettyDTypeNameQ());
|
||||
}
|
||||
|
|
@ -123,7 +122,7 @@ private:
|
|||
return lhsp;
|
||||
} else if (VN_IS(lhsp, Const)) {
|
||||
// Optional vs just making add/sub below, but saves constification some work
|
||||
V3Number num (lhsp, lhsp->width());
|
||||
V3Number num(lhsp, lhsp->width());
|
||||
num.opSub(VN_CAST(lhsp, Const)->num(), V3Number(lhsp, 32, rhs));
|
||||
num.isSigned(lhsp->isSigned());
|
||||
AstNode* newp = new AstConst(lhsp->fileline(), num);
|
||||
|
|
@ -135,8 +134,9 @@ private:
|
|||
newp->dtypeFrom(lhsp);
|
||||
return newp;
|
||||
} else { // rhs < 0;
|
||||
AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
|
||||
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
|
||||
AstNode* newp
|
||||
= new AstAdd(lhsp->fileline(), lhsp,
|
||||
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
|
||||
// We must make sure sub gets sign of original value, not from the constant
|
||||
newp->dtypeFrom(lhsp);
|
||||
return newp;
|
||||
|
|
@ -145,9 +145,8 @@ private:
|
|||
AstNode* newSubNeg(vlsint32_t lhs, AstNode* rhsp) {
|
||||
// Return lhs-rhs
|
||||
// We must make sure sub gets sign of original value
|
||||
AstNode* newp = new AstSub(rhsp->fileline(),
|
||||
new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs),
|
||||
rhsp);
|
||||
AstNode* newp = new AstSub(
|
||||
rhsp->fileline(), new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs), rhsp);
|
||||
newp->dtypeFrom(rhsp); // Important as AstSub default is lhs's sign
|
||||
return newp;
|
||||
}
|
||||
|
|
@ -176,13 +175,13 @@ private:
|
|||
|
||||
AstNodeDType* sliceDType(AstPackArrayDType* nodep, int msb, int lsb) {
|
||||
// Return slice needed for msb/lsb, either as original dtype or a new slice dtype
|
||||
if (nodep->declRange().elements() == (msb-lsb+1) // Extracting whole of original array
|
||||
if (nodep->declRange().elements() == (msb - lsb + 1) // Extracting whole of original array
|
||||
&& nodep->declRange().lo() == lsb) {
|
||||
return nodep;
|
||||
} else {
|
||||
// Need a slice data type, which is an array of the extracted
|
||||
// type, but with (presumably) different size
|
||||
VNumRange newRange (msb, lsb, nodep->declRange().littleEndian());
|
||||
VNumRange newRange(msb, lsb, nodep->declRange().littleEndian());
|
||||
AstNodeDType* vardtypep
|
||||
= new AstPackArrayDType(nodep->fileline(),
|
||||
nodep->subDTypep(), // Need to strip off array reference
|
||||
|
|
@ -198,85 +197,78 @@ private:
|
|||
virtual void visit(AstSelBit* nodep) VL_OVERRIDE {
|
||||
// Select of a non-width specified part of an array, i.e. "array[2]"
|
||||
// This select style has a lsb and msb (no user specified width)
|
||||
UINFO(6,"SELBIT "<<nodep<<endl);
|
||||
if (debug()>=9) nodep->backp()->dumpTree(cout, "--SELBT0: ");
|
||||
UINFO(6, "SELBIT " << nodep << endl);
|
||||
if (debug() >= 9) nodep->backp()->dumpTree(cout, "--SELBT0: ");
|
||||
// lhsp/rhsp do not need to be constant
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting
|
||||
if (debug()>=9) nodep->dumpTree(cout, "--SELBT2: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "--SELBT2: ");
|
||||
FromData fromdata = fromDataForArray(nodep, fromp);
|
||||
AstNodeDType* ddtypep = fromdata.m_dtypep;
|
||||
VNumRange fromRange = fromdata.m_fromRange;
|
||||
UINFO(6," ddtypep "<<ddtypep<<endl);
|
||||
UINFO(6, " ddtypep " << ddtypep << endl);
|
||||
if (AstUnpackArrayDType* adtypep = VN_CAST(ddtypep, UnpackArrayDType)) {
|
||||
// SELBIT(array, index) -> ARRAYSEL(array, index)
|
||||
AstNode* subp = rhsp;
|
||||
if (fromRange.lo()!=0 || fromRange.hi()<0) {
|
||||
if (fromRange.lo() != 0 || fromRange.hi() < 0) {
|
||||
subp = newSubNeg(subp, fromRange.lo());
|
||||
}
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(),
|
||||
fromp, subp);
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
// SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
|
||||
AstNode* subp = rhsp;
|
||||
if (fromRange.lo()!=0 || fromRange.hi()<0) {
|
||||
if (fromRange.lo() != 0 || fromRange.hi() < 0) {
|
||||
if (fromRange.littleEndian()) {
|
||||
subp = newSubNeg(fromRange.hi(), subp);
|
||||
} else {
|
||||
subp = newSubNeg(subp, fromRange.lo());
|
||||
}
|
||||
}
|
||||
UASSERT_OBJ(!(!fromRange.elements()
|
||||
|| (adtypep->width() % fromRange.elements())!=0), adtypep,
|
||||
"Array extraction with width miscomputed "
|
||||
<<adtypep->width()<<"/"<<fromRange.elements());
|
||||
UASSERT_OBJ(!(!fromRange.elements() || (adtypep->width() % fromRange.elements()) != 0),
|
||||
adtypep,
|
||||
"Array extraction with width miscomputed " << adtypep->width() << "/"
|
||||
<< fromRange.elements());
|
||||
int elwidth = adtypep->width() / fromRange.elements();
|
||||
AstSel* newp
|
||||
= new AstSel(nodep->fileline(),
|
||||
fromp,
|
||||
new AstMul(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(),
|
||||
AstConst::Unsized32(), elwidth),
|
||||
subp),
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth));
|
||||
AstSel* newp = new AstSel(
|
||||
nodep->fileline(), fromp,
|
||||
new AstMul(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth), subp),
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth));
|
||||
newp->declRange(fromRange);
|
||||
newp->declElWidth(elwidth);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstAssocArrayDType* adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (AstAssocArrayDType* adtypep = VN_CAST(ddtypep, AssocArrayDType)) {
|
||||
// SELBIT(array, index) -> ASSOCSEL(array, index)
|
||||
AstNode* subp = rhsp;
|
||||
AstAssocSel* newp = new AstAssocSel(nodep->fileline(),
|
||||
fromp, subp);
|
||||
AstAssocSel* newp = new AstAssocSel(nodep->fileline(), fromp, subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (AstDynArrayDType* adtypep = VN_CAST(ddtypep, DynArrayDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* subp = rhsp;
|
||||
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(),
|
||||
fromp, "at", subp);
|
||||
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (AstQueueDType* adtypep = VN_CAST(ddtypep, QueueDType)) {
|
||||
// SELBIT(array, index) -> CMETHODCALL(queue, "at", index)
|
||||
AstNode* subp = rhsp;
|
||||
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(),
|
||||
fromp, "at", subp);
|
||||
AstCMethodHard* newp = new AstCMethodHard(nodep->fileline(), fromp, "at", subp);
|
||||
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTq: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
|
||||
// SELBIT(string, index) -> GETC(string, index)
|
||||
AstNodeVarRef* varrefp = VN_CAST(fromp, NodeVarRef);
|
||||
if (!varrefp) nodep->v3error("Unsupported: String array operation on non-variable");
|
||||
|
|
@ -291,29 +283,25 @@ private:
|
|||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(ddtypep, BasicDType)) {
|
||||
// SELBIT(range, index) -> SEL(array, index, 1)
|
||||
AstSel* newp = new AstSel(nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(rhsp, fromRange),
|
||||
AstSel* newp = new AstSel(nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange),
|
||||
// Unsized so width from user
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
|
||||
newp->declRange(fromRange);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct
|
||||
UINFO(6, " new " << newp << endl);
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(ddtypep, NodeUOrStructDType)) { // A bit from the packed struct
|
||||
// SELBIT(range, index) -> SEL(array, index, 1)
|
||||
AstSel* newp = new AstSel(nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(rhsp, fromRange),
|
||||
AstSel* newp = new AstSel(nodep->fileline(), fromp, newSubLsbOf(rhsp, fromRange),
|
||||
// Unsized so width from user
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
|
||||
newp->declRange(fromRange);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
UINFO(6, " new " << newp << endl);
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELBTn: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: "
|
||||
<< "data type is" << fromdata.m_errp->prettyDTypeNameQ());
|
||||
// How to recover? We'll strip a dimension.
|
||||
|
|
@ -326,20 +314,22 @@ private:
|
|||
// Select of a range specified part of an array, i.e. "array[2:3]"
|
||||
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
|
||||
// This select style has a (msb or lsb) and width
|
||||
UINFO(6,"SELEXTRACT "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout, "--SELEX0: ");
|
||||
UINFO(6, "SELEXTRACT " << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, "--SELEX0: ");
|
||||
// Below 2 lines may change nodep->widthp()
|
||||
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
|
||||
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
|
||||
//if (debug()>=9) nodep->dumpTree(cout, "--SELEX3: ");
|
||||
checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, "--SELEX3: ");
|
||||
checkConstantOrReplace(nodep->lsbp(),
|
||||
"First value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
checkConstantOrReplace(nodep->msbp(),
|
||||
"Second value of [a:b] isn't a constant, maybe you want +: or -:");
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
|
||||
vlsint32_t msb = VN_CAST(msbp, Const)->toSInt();
|
||||
vlsint32_t lsb = VN_CAST(lsbp, Const)->toSInt();
|
||||
vlsint32_t elem = (msb>lsb) ? (msb-lsb+1) : (lsb-msb+1);
|
||||
vlsint32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1);
|
||||
FromData fromdata = fromDataForArray(nodep, fromp);
|
||||
AstNodeDType* ddtypep = fromdata.m_dtypep;
|
||||
VNumRange fromRange = fromdata.m_fromRange;
|
||||
|
|
@ -347,90 +337,101 @@ private:
|
|||
// Slice extraction
|
||||
if (fromRange.elements() == elem
|
||||
&& fromRange.lo() == lsb) { // Extracting whole of original array
|
||||
nodep->replaceWith(fromp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->replaceWith(fromp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (fromRange.elements() == 1) { // Extracting single element
|
||||
AstArraySel* newp = new AstArraySel(nodep->fileline(), fromp, lsbp);
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // Slice
|
||||
AstSliceSel* newp = new AstSliceSel(nodep->fileline(), fromp,
|
||||
VNumRange(VNumRange::LeftRight(),
|
||||
msb, lsb));
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
VNumRange(VNumRange::LeftRight(), msb, lsb));
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
}
|
||||
else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
} else if (AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
// SELEXTRACT(array, msb, lsb) -> SEL(array,
|
||||
// lsb*width-of-subindex, width-of-subindex*(msb-lsb))
|
||||
UASSERT_OBJ(!(!fromRange.elements()
|
||||
|| (adtypep->width() % fromRange.elements())!=0), adtypep,
|
||||
"Array extraction with width miscomputed "
|
||||
<<adtypep->width()<<"/"<<fromRange.elements());
|
||||
UASSERT_OBJ(!(!fromRange.elements() || (adtypep->width() % fromRange.elements()) != 0),
|
||||
adtypep,
|
||||
"Array extraction with width miscomputed " << adtypep->width() << "/"
|
||||
<< fromRange.elements());
|
||||
if (fromRange.littleEndian()) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<<lsb<<":"<<msb<<"]");
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
nodep->v3error("["
|
||||
<< msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<< lsb << ":" << msb << "]");
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
int elwidth = adtypep->width() / fromRange.elements();
|
||||
AstSel* newp = new AstSel(nodep->fileline(),
|
||||
fromp,
|
||||
new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange),
|
||||
new AstConst(nodep->fileline(),
|
||||
AstConst::Unsized32(), elwidth)),
|
||||
new AstConst(nodep->fileline(),
|
||||
AstConst::Unsized32(), (msb-lsb+1)*elwidth));
|
||||
AstSel* newp = new AstSel(
|
||||
nodep->fileline(), fromp,
|
||||
new AstMul(nodep->fileline(), newSubLsbOf(lsbp, fromRange),
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), elwidth)),
|
||||
new AstConst(nodep->fileline(), AstConst::Unsized32(), (msb - lsb + 1) * elwidth));
|
||||
newp->declRange(fromRange);
|
||||
newp->declElWidth(elwidth);
|
||||
newp->dtypeFrom(sliceDType(adtypep, msb, lsb));
|
||||
//if (debug()>=9) newp->dumpTree(cout, "--EXTBTn: ");
|
||||
// if (debug() >= 9) newp->dumpTree(cout, "--EXTBTn: ");
|
||||
UASSERT_OBJ(newp->widthMin() == newp->widthConst(), nodep, "Width mismatch");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (VN_IS(ddtypep, BasicDType)) {
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(ddtypep, BasicDType)) {
|
||||
if (fromRange.littleEndian()) {
|
||||
// Below code assumes big bit endian; just works out if we swap
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<<lsb<<":"<<msb<<"]");
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
nodep->v3error("["
|
||||
<< msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<< lsb << ":" << msb << "]");
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
AstNode* widthp = new AstConst(msbp->fileline(),
|
||||
AstConst::Unsized32(), // Unsized so width from user
|
||||
msb +1-lsb);
|
||||
AstSel* newp = new AstSel(nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(lsbp, fromRange),
|
||||
widthp);
|
||||
msb + 1 - lsb);
|
||||
AstSel* newp
|
||||
= new AstSel(nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp);
|
||||
newp->declRange(fromRange);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
//if (debug()>=9) newp->dumpTree(cout, "--SELEXnew: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else if (VN_IS(ddtypep, NodeUOrStructDType)) {
|
||||
UINFO(6, " new " << newp << endl);
|
||||
// if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else if (VN_IS(ddtypep, NodeUOrStructDType)) {
|
||||
// Classes aren't little endian
|
||||
if (lsb > msb) {
|
||||
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<<lsb<<":"<<msb<<"]");
|
||||
int x = msb; msb = lsb; lsb = x;
|
||||
nodep->v3error("["
|
||||
<< msb << ":" << lsb
|
||||
<< "] Range extract has backward bit ordering, perhaps you wanted ["
|
||||
<< lsb << ":" << msb << "]");
|
||||
int x = msb;
|
||||
msb = lsb;
|
||||
lsb = x;
|
||||
}
|
||||
AstNode* widthp = new AstConst(msbp->fileline(),
|
||||
AstConst::Unsized32(), // Unsized so width from user
|
||||
msb +1-lsb);
|
||||
AstSel* newp = new AstSel(nodep->fileline(),
|
||||
fromp,
|
||||
newSubLsbOf(lsbp, fromRange),
|
||||
widthp);
|
||||
msb + 1 - lsb);
|
||||
AstSel* newp
|
||||
= new AstSel(nodep->fileline(), fromp, newSubLsbOf(lsbp, fromRange), widthp);
|
||||
newp->declRange(fromRange);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
//if (debug()>=9) newp->dumpTree(cout, "--SELEXnew: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
UINFO(6, " new " << newp << endl);
|
||||
// if (debug() >= 9) newp->dumpTree(cout, "--SELEXnew: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal range select; type already selected, or bad dimension: "
|
||||
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
||||
UINFO(1, " Related ddtype: " << ddtypep << endl);
|
||||
|
|
@ -447,38 +448,40 @@ private:
|
|||
void replaceSelPlusMinus(AstNodePreSel* nodep) {
|
||||
// Select of a range specified with +: or -:, i.e. "array[2+:3], [2-:3]"
|
||||
// This select style has a lsb and width
|
||||
UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
|
||||
UINFO(6, "SELPLUS/MINUS " << nodep << endl);
|
||||
// Below 2 lines may change nodep->widthp()
|
||||
if (debug()>=9) nodep->dumpTree(cout, "--SELPM0: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM0: ");
|
||||
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
|
||||
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
|
||||
if (debug()>=9) nodep->dumpTree(cout, "--SELPM3: ");
|
||||
if (debug() >= 9) nodep->dumpTree(cout, "--SELPM3: ");
|
||||
// Now replace it with an AstSel
|
||||
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* widthp = nodep->thsp()->unlinkFrBack();
|
||||
int width = VN_CAST(widthp, Const)->toSInt();
|
||||
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "
|
||||
<<widthp->prettyName());
|
||||
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
|
||||
if (width > (1 << 28)) {
|
||||
nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "
|
||||
<< widthp->prettyName());
|
||||
}
|
||||
if (width < 0) nodep->v3error("Width of :+ or :- is < 0: " << widthp->prettyName());
|
||||
FromData fromdata = fromDataForArray(nodep, fromp);
|
||||
AstNodeDType* ddtypep = fromdata.m_dtypep;
|
||||
VNumRange fromRange = fromdata.m_fromRange;
|
||||
if (VN_IS(ddtypep, BasicDType)
|
||||
|| VN_IS(ddtypep, PackArrayDType)
|
||||
if (VN_IS(ddtypep, BasicDType) || VN_IS(ddtypep, PackArrayDType)
|
||||
|| (VN_IS(ddtypep, NodeUOrStructDType)
|
||||
&& VN_CAST(ddtypep, NodeUOrStructDType)->packedUnsup())) {
|
||||
int elwidth = 1;
|
||||
AstNode* newwidthp = widthp;
|
||||
if (const AstPackArrayDType* adtypep = VN_CAST(ddtypep, PackArrayDType)) {
|
||||
elwidth = adtypep->width() / fromRange.elements();
|
||||
newwidthp = new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth);
|
||||
newwidthp
|
||||
= new AstConst(nodep->fileline(), AstConst::Unsized32(), width * elwidth);
|
||||
}
|
||||
AstNode* newlsbp = NULL;
|
||||
if (VN_IS(nodep, SelPlus)) {
|
||||
if (fromRange.littleEndian()) {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
|
||||
newlsbp = newSubNeg((fromRange.hi()-width+1), rhsp);
|
||||
newlsbp = newSubNeg((fromRange.hi() - width + 1), rhsp);
|
||||
} else {
|
||||
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
|
||||
newlsbp = newSubNeg(rhsp, fromRange.lo());
|
||||
|
|
@ -489,22 +492,23 @@ private:
|
|||
newlsbp = newSubNeg(fromRange.hi(), rhsp);
|
||||
} else {
|
||||
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
|
||||
newlsbp = newSubNeg(rhsp, fromRange.lo()+(width-1));
|
||||
newlsbp = newSubNeg(rhsp, fromRange.lo() + (width - 1));
|
||||
}
|
||||
} else {
|
||||
nodep->v3fatalSrc("Bad Case");
|
||||
}
|
||||
if (elwidth != 1) newlsbp = new AstMul(nodep->fileline(), newlsbp,
|
||||
new AstConst(nodep->fileline(), elwidth));
|
||||
AstSel* newp = new AstSel(nodep->fileline(),
|
||||
fromp, newlsbp, newwidthp);
|
||||
if (elwidth != 1) {
|
||||
newlsbp = new AstMul(nodep->fileline(), newlsbp,
|
||||
new AstConst(nodep->fileline(), elwidth));
|
||||
}
|
||||
AstSel* newp = new AstSel(nodep->fileline(), fromp, newlsbp, newwidthp);
|
||||
newp->declRange(fromRange);
|
||||
newp->declElWidth(elwidth);
|
||||
UINFO(6," new "<<newp<<endl);
|
||||
if (debug()>=9) newp->dumpTree(cout, "--SELNEW: ");
|
||||
nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
else { // NULL=bad extract, or unknown node type
|
||||
UINFO(6, " new " << newp << endl);
|
||||
if (debug() >= 9) newp->dumpTree(cout, "--SELNEW: ");
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else { // NULL=bad extract, or unknown node type
|
||||
nodep->v3error("Illegal +: or -: select; type already selected, or bad dimension: "
|
||||
<< "data type is " << fromdata.m_errp->prettyDTypeNameQ());
|
||||
// How to recover? We'll strip a dimension.
|
||||
|
|
@ -516,12 +520,8 @@ private:
|
|||
if (!rhsp->backp()) { VL_DO_DANGLING(pushDeletep(rhsp), rhsp); }
|
||||
if (!widthp->backp()) { VL_DO_DANGLING(pushDeletep(widthp), widthp); }
|
||||
}
|
||||
virtual void visit(AstSelPlus* nodep) VL_OVERRIDE {
|
||||
replaceSelPlusMinus(nodep);
|
||||
}
|
||||
virtual void visit(AstSelMinus* nodep) VL_OVERRIDE {
|
||||
replaceSelPlusMinus(nodep);
|
||||
}
|
||||
virtual void visit(AstSelPlus* nodep) VL_OVERRIDE { replaceSelPlusMinus(nodep); }
|
||||
virtual void visit(AstSelMinus* nodep) VL_OVERRIDE { replaceSelPlusMinus(nodep); }
|
||||
// If adding new visitors, ensure V3Width's visit(TYPE) calls into here
|
||||
|
||||
//--------------------
|
||||
|
|
@ -534,9 +534,7 @@ private:
|
|||
public:
|
||||
// CONSTRUCTORS
|
||||
WidthSelVisitor() {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
return iterateSubtreeReturnEdits(nodep);
|
||||
}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); }
|
||||
virtual ~WidthSelVisitor() {}
|
||||
};
|
||||
|
||||
|
|
@ -544,7 +542,7 @@ public:
|
|||
// Width class functions
|
||||
|
||||
AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) {
|
||||
UINFO(4,__FUNCTION__<<": "<<nodep<<endl);
|
||||
UINFO(4, __FUNCTION__ << ": " << nodep << endl);
|
||||
WidthSelVisitor visitor;
|
||||
nodep = visitor.mainAcceptEdit(nodep);
|
||||
return nodep;
|
||||
|
|
|
|||
Loading…
Reference in New Issue