From a3e463030d0e9f3057819b5c487af8738d372dcf Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 8 May 2009 13:16:19 -0400 Subject: [PATCH] Fix escaped identifiers with '.' causing conflicts, bug83. --- Changes | 5 +++++ src/V3Ast.cpp | 19 +++++++------------ src/V3EmitC.cpp | 33 ++++++++++++++++++--------------- src/V3EmitCBase.h | 1 + src/V3EmitCSyms.cpp | 6 +++--- src/V3EmitV.cpp | 2 +- src/V3File.cpp | 17 +++++++++++++++++ src/V3File.h | 2 ++ src/V3Premit.cpp | 2 +- test_regress/driver.pl | 21 ++++++++++++++++++--- test_regress/t/t_var_escape.v | 30 ++++++++++++++++++------------ 11 files changed, 91 insertions(+), 47 deletions(-) diff --git a/Changes b/Changes index b1b2eb0a4..8f0ce571c 100644 --- a/Changes +++ b/Changes @@ -7,6 +7,11 @@ indicates the contributor was also the author of the fix; Thanks! ** Verilator is now licensed under LGPL v3 and/or Artistic v2.0. +**** The front end parser has been re-factored to enable more SV parsing. + Code should parse the same, but minor parsing bugs may pop up now. + +**** Fix escaped identifiers with '.' causing conflicts, bug83. [J Baxter] + * Verilator 3.703 2009/05/02 *** Fix $clog2 calculation error with powers-of-2, bug81. [Patricio Kaplan] diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 0681e02a8..6fba33d07 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -86,9 +86,9 @@ void AstNode::init() { } string AstNode::encodeName(const string& namein) { - string name2 = namein; + // Encode signal name raw from parser, then not called again on same signal + const char* start = namein.c_str(); string out; - const char* start = name2.c_str(); for (const char* pos = start; *pos; pos++) { if ((pos==start) ? isalpha(pos[0]) // digits can't lead identifiers : isalnum(pos[0])) { @@ -100,17 +100,13 @@ string AstNode::encodeName(const string& namein) { } else { out += pos[0]; } - } else if (pos[0]=='.') { - out += "__DOT__"; - } else if (pos[0]=='[') { - out += "__BRA__"; - } else if (pos[0]==']') { - out += "__KET__"; } else { // Need the leading 0 so this will never collide with // a user identifier nor a temp we create in Verilator. - char hex[10]; sprintf(hex,"%02X",pos[0]); - out += "__0"; out += hex; + // 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. + char hex[10]; sprintf(hex,"__0%02X",pos[0]); + out += hex; } } return out; @@ -145,9 +141,8 @@ string AstNode::dedotName(const string& namein) { string AstNode::prettyName(const string& namein) { string pretty; - string name2 = namein; pretty = ""; - for (const char* pos = name2.c_str(); *pos; ) { + for (const char* pos = namein.c_str(); *pos; ) { if (0==strncmp(pos,"__BRA__",7)) { pretty += "["; pos += 7; diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index fa358f7ef..5604ccdea 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -207,12 +207,12 @@ public: // hiearchies itself, and if SystemPerl also did it, you'd end up // with (number-of-instant) times too many counts in this bin. puts(", first"); // Enable, passed from __Vconfigure parameter - puts(", \""); puts(nodep->fileline()->filename()); puts("\""); + puts(", "); putsQuoted(nodep->fileline()->filename()); puts(", "); puts(cvtToStr(nodep->fileline()->lineno())); puts(", "); puts(cvtToStr(nodep->column())); - puts(", \""); puts((nodep->hier()!=""?".":"")+nodep->hier()); puts("\""); - puts(", \""); puts(nodep->page()); puts("\""); - puts(", \""); puts(nodep->comment()); puts("\""); + puts(", "); putsQuoted((nodep->hier()!=""?".":"")+nodep->hier()); + puts(", "); putsQuoted(nodep->page()); + puts(", "); putsQuoted(nodep->comment()); puts(");\n"); } virtual void visit(AstCoverInc* nodep, AstNUser*) { @@ -339,16 +339,16 @@ public: puts("}\n"); } virtual void visit(AstStop* nodep, AstNUser*) { - puts("vl_stop(\""); - puts(nodep->fileline()->filename()); - puts("\","); + puts("vl_stop("); + putsQuoted(nodep->fileline()->filename()); + puts(","); puts(cvtToStr(nodep->fileline()->lineno())); puts(",\"\");\n"); } virtual void visit(AstFinish* nodep, AstNUser*) { - puts("vl_finish(\""); - puts(nodep->fileline()->filename()); - puts("\","); + puts("vl_finish("); + putsQuoted(nodep->fileline()->filename()); + puts(","); puts(cvtToStr(nodep->fileline()->lineno())); puts(",\"\");\n"); } @@ -830,8 +830,8 @@ void EmitCStmts::emitVarCtors() { } else puts(", "); if (ofp()->exceededWidth()) puts("\n "); - puts((*it)->name()); puts("(\""); - puts((*it)->name()); puts("\")"); + puts((*it)->name()); + puts("("); putsQuoted((*it)->name()); puts(")"); } if (!first) puts ("\n#endif\n"); ofp()->indentDec(); @@ -995,7 +995,7 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) { nodep->v3fatalSrc("Unknown displayEmit node type"); } puts("\""); - ofp()->putsNoTracking(emitDispState.m_format); + ofp()->putsNoTracking(emitDispState.m_format); // Not putsQuoted - already contains \s puts("\""); // Arguments for (unsigned i=0; i < emitDispState.m_argsp.size(); i++) { @@ -1299,7 +1299,9 @@ void EmitCImp::emitTextSection(AstType type) { puts("\n//*** Below code from `systemc in Verilog file\n"); } ofp()->putsNoTracking("//#line "+cvtToStr(nodep->fileline()->lineno()) - +" \""+nodep->fileline()->filename()+"\"\n"); + +" "); + ofp()->putsQuoted(nodep->fileline()->filename()); + ofp()->putsNoTracking("\n"); last_line = nodep->fileline()->lineno(); } ofp()->putsNoTracking(textp->text()); @@ -1838,7 +1840,8 @@ class EmitCTrace : EmitCStmts { } puts("(c+"+cvtToStr(nodep->code())); if (nodep->arrayWidth()) puts("+i*"+cvtToStr(nodep->widthWords())); - puts(",\""+nodep->showname()+"\""); + puts(","); + putsQuoted(nodep->showname()); if (nodep->arrayWidth()) { puts(",(i+"+cvtToStr(nodep->arrayLsb())+")"); } else { diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 90b878ee4..2cd45a8c9 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -107,6 +107,7 @@ public: V3OutCFile* ofp() const { return m_ofp; }; void puts(const string& str) { ofp()->puts(str); } void putbs(const string& str) { ofp()->putbs(str); } + void putsQuoted(const string& str) { ofp()->putsQuoted(str); } bool optSystemC() { return v3Global.opt.systemC(); } bool optSystemPerl() { return v3Global.opt.systemPerl(); } static string symClassName() { return v3Global.opt.prefix()+"__Syms"; } diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index d70847e01..093225fc6 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -209,9 +209,9 @@ void EmitCSyms::emitImp() { if (modp->isTop()) { } else { ofp()->printf("\t%c %-30s ", comma, scopep->nameDotless().c_str()); - puts("(Verilated::catName(topp->name(),\""); - puts("."+scopep->prettyName()); - puts("\"))\n"); + puts("(Verilated::catName(topp->name(),"); + putsQuoted("."+scopep->prettyName()); + puts("))\n"); comma=','; } } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index de1165245..bed46e7c8 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -177,7 +177,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { putbs(" ("); if (filep) { filep->iterateAndNext(*this); putbs(","); } puts("\""); - putsNoTracking(text); + putsNoTracking(text); // Not putsQuoted, as display text contains \ already puts("\""); for (AstNode* expp=exprsp; expp; expp = expp->nextp()) { puts(","); diff --git a/src/V3File.cpp b/src/V3File.cpp index 918c928b9..d6a5a35ce 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -431,6 +431,23 @@ void V3OutFile::putBreak () { } } +void V3OutFile::putsQuoted(const char* strg) { + // Quote \ and " for use inside C programs + // Don't use to quote a filename for #include - #include doesn't \ escape. + putcNoTracking('"'); + for (const char* cp=strg; *cp; cp++) { + if (*cp == '\\') { + putcNoTracking('\\'); + putcNoTracking('\\'); + } else if (*cp == '"') { + putcNoTracking('\\'); + putcNoTracking('"'); + } else { + putcNoTracking (*cp); + } + } + putcNoTracking('"'); +} void V3OutFile::putsNoTracking (const char *strg) { // Don't track {}'s, probably because it's a $display format string for (const char* cp=strg; *cp; cp++) { diff --git a/src/V3File.h b/src/V3File.h index f653d5bf5..b5fa61397 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -113,6 +113,8 @@ public: void puts(const string& strg) { puts(strg.c_str()); } void putsNoTracking(const char* strg); void putsNoTracking(const string& strg) { putsNoTracking(strg.c_str()); } + void putsQuoted(const char* strg); + void putsQuoted(const string& strg) { putsQuoted(strg.c_str()); } void putBreak(); // Print linebreak if line is too wide void putBreakExpr(); // Print linebreak in expression if line is too wide void putAlign(bool isstatic/*AlignClass*/, int align, int size=0/*=align*/, const char* prefix=""); // Declare a variable, with natural alignment diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 8983eca7d..f63b9cd1e 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -278,7 +278,7 @@ private: } // Autoflush - virtual void visit(AstDisplay* nodep, AstNUser* vup) { + virtual void visit(AstDisplay* nodep, AstNUser*) { startStatement(nodep); nodep->iterateChildren(*this); m_stmtp = NULL; diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 58b11352d..aba7fc662 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -44,6 +44,7 @@ my $opt_vcs; my $opt_v3; my $opt_stop; my $opt_optimize; +my $opt_trace; my $opt_gdb; my $opt_jobs = 1; my $opt_verbose; @@ -63,6 +64,7 @@ if (! GetOptions ( "gdb!" => \$opt_gdb, "optimize:s" => \$opt_optimize, "stop!" => \$opt_stop, + "trace!" => \$opt_trace, "verbose!" => \$opt_verbose, "<>" => \¶meter, )) { @@ -122,7 +124,7 @@ sub one_test { } else { $test->oprint("FAILED: ","*"x60,"\n"); push @fails, "\t#".$test->soprint("%Error: $test->{errors}\n"); - my $j = ($opt_jobs>1?" -j 2":""); + my $j = ($opt_jobs>1?" -j $opt_jobs":""); push @fails, "\t\tmake$j && test_regress/" .$test->{pl_filename}." ".join(' ',@Orig_ARGV_Sw)."\n"; $failcnt++; @@ -234,6 +236,7 @@ sub new { v_flags => [split(/\s+/,(" -f input.vc --debug-check" .($opt_verbose ? " +define+TEST_VERBOSE=1":"") .($opt_benchmark ? " +define+TEST_BENCHMARK=$opt_benchmark":"") + .($opt_trace ? " +define+WAVES=1":"") ))], v_flags2 => [], # Overridden in some sim files v_other_filenames => [], # After the filename so we can spec multiple files @@ -265,6 +268,7 @@ sub new { $self->{status_filename} ||= "$self->{obj_dir}/V".$self->{name}.".status"; $self->{run_log_filename} ||= "$self->{obj_dir}/vl_sim.log"; $self->{coverage_filename} ||= "$self->{obj_dir}/vl_coverage.pl"; + $self->{vcd_filename} ||= "$self->{obj_dir}/sim.vcd"; ($self->{top_filename} = $self->{pl_filename}) =~ s/\.pl$/\.v/; if (!$self->{make_top_shell}) { $self->{top_shell_filename} = $self->{top_filename}; @@ -349,7 +353,7 @@ sub compile { @{$param{verilator_flags2}}); $self->{sc} = 1 if ($checkflags =~ /-sc\b/); $self->{sp} = 1 if ($checkflags =~ /-sp\b/); - $self->{trace} = 1 if ($checkflags =~ /-trace\b/); + $self->{trace} = 1 if ($opt_trace || $checkflags =~ /-trace\b/); $self->{coverage} = 1 if ($checkflags =~ /-coverage\b/); if ($param{vcs}) { @@ -386,7 +390,7 @@ sub compile { unshift @verilator_flags, "--gdb $opt_gdb" if $opt_gdb; unshift @verilator_flags, @Opt_Driver_Verilator_Flags; unshift @verilator_flags, "--x-assign unique"; # More likely to be buggy -# unshift @verilator_flags, "--trace"; + unshift @verilator_flags, "--trace" if $opt_trace; if (defined $opt_optimize) { my $letters = ""; if ($opt_optimize =~ /[a-zA-Z]/) { @@ -786,7 +790,18 @@ sub _make_top { } print $fh " );\n"; + # Waves + print $fh "\n"; + print $fh "`ifdef WAVES\n"; + print $fh " initial begin\n"; + print $fh " \$display(\"-Tracing Waves to Dumpfile: $self->{vcd_filename}\");\n"; + print $fh " \$dumpfile(\"$self->{vcd_filename}\");\n"; + print $fh " \$dumpvars(12, t);\n"; + print $fh " end\n"; + print $fh "`endif\n"; + # Test + print $fh "\n"; print $fh " initial begin\n"; print $fh " fastclk=1;\n" if $self->{inputs}{fastclk}; print $fh " clk=1;\n" if $self->{inputs}{clk}; diff --git a/test_regress/t/t_var_escape.v b/test_regress/t/t_var_escape.v index 69a779687..bf4e3c1d9 100644 --- a/test_regress/t/t_var_escape.v +++ b/test_regress/t/t_var_escape.v @@ -5,7 +5,7 @@ module t (/*AUTOARG*/ // Outputs - \escaped_normal , double__underscore, \9num , \bra[ket]slash/dash-colon:9 , + \escaped_normal , double__underscore, \9num , \bra[ket]slash/dash-colon:9backslash\done , // Inputs clk ); @@ -24,20 +24,19 @@ module t (/*AUTOARG*/ output \9num ; wire \9num = cyc[0]; - output \bra[ket]slash/dash-colon:9 ; - wire \bra[ket]slash/dash-colon:9 = cyc[0]; + output \bra[ket]slash/dash-colon:9backslash\done ; + wire \bra[ket]slash/dash-colon:9backslash\done = cyc[0]; + wire \wire = cyc[0]; wire \check_alias = cyc[0]; wire \check:alias = cyc[0]; wire \check;alias = !cyc[0]; -`ifndef verilator - initial begin - $dumpfile("obj_dir/t_var_escape/t_var_escape_dump.vcd"); - $dumpvars( 0, t ); - $dumpon; - end -`endif + // These are *different entities*, bug83 + wire [31:0] \a0.cyc = ~a0.cyc; + wire [31:0] \other.cyc = ~a0.cyc; + + sub a0 (.cyc(cyc)); always @ (posedge clk) begin cyc <= cyc + 1; @@ -45,11 +44,13 @@ module t (/*AUTOARG*/ if (\escaped_normal != cyc[0]) $stop; if (double__underscore != cyc[0]) $stop; if (\9num != cyc[0]) $stop; - if (\bra[ket]slash/dash-colon:9 != cyc[0]) $stop; + if (\bra[ket]slash/dash-colon:9backslash\done != cyc[0]) $stop; + if (\wire != cyc[0]) $stop; if (\check_alias != cyc[0]) $stop; if (\check:alias != cyc[0]) $stop; if (\check;alias != !cyc[0]) $stop; - + if (\a0.cyc != ~cyc) $stop; + if (\other.cyc != ~cyc) $stop; if (cyc==10) begin $write("*-* All Finished *-*\n"); $finish; @@ -57,3 +58,8 @@ module t (/*AUTOARG*/ end endmodule + +module sub ( + input [31:0] cyc + ); +endmodule