diff --git a/Changes b/Changes index 1b8aedeb5..986c8a9a8 100644 --- a/Changes +++ b/Changes @@ -9,6 +9,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Add check for assertOn for asserts, #2162. [Tobias Wölfel] +*** Fix genblk naming with directly nested generate blocks, #2176. [Alexander Grobman] + **** Fix undeclared VL_SHIFTR_WWQ, #2114. [Alex Solomatnikov] diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 835758651..127026a30 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1282,6 +1282,7 @@ void AstBegin::dump(std::ostream& str) const { if (unnamed()) str<<" [UNNAMED]"; if (generate()) str<<" [GEN]"; if (genforp()) str<<" [GENFOR]"; + if (implied()) str<<" [IMPLIED]"; } void AstCoverDecl::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index b7b5fe89e..02d2a316c 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -3736,16 +3736,19 @@ class AstBegin : public AstNode { // Children: statements private: string m_name; // Name of block - bool m_unnamed; // Originally unnamed + bool m_unnamed; // Originally unnamed (name change does not affect this) bool m_generate; // Underneath a generate + bool m_implied; // Not inserted by user public: // Node that simply puts name into the output stream - AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate=false) + AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, + bool implied = false) : ASTGEN_SUPER(fl) , m_name(name) { addNOp1p(stmtsp); - m_unnamed = (name==""); + m_unnamed = (name == ""); m_generate = generate; + m_implied = implied; } ASTNODE_NODE_FUNCS(Begin) virtual void dump(std::ostream& str) const; @@ -3760,6 +3763,7 @@ public: bool unnamed() const { return m_unnamed; } void generate(bool flag) { m_generate = flag; } bool generate() const { return m_generate; } + bool implied() const { return m_implied; } }; class AstInitial : public AstNode { diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 2cb65de2e..77650f7a4 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -125,7 +125,7 @@ private: while ((pos=dottedname.find("__DOT__")) != string::npos) { string ident = dottedname.substr(0, pos); dottedname = dottedname.substr(pos+strlen("__DOT__")); - if (!nodep->unnamed()) { + if (nodep->name() != "") { if (m_namedScope=="") m_namedScope = ident; else m_namedScope = m_namedScope + "__DOT__"+ident; } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 17db13e72..557e2769c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -914,20 +914,24 @@ class LinkDotFindVisitor : public AstNVisitor { } } } - int oldNum = m_beginNum; - AstBegin* oldbegin = m_beginp; - VSymEnt* oldCurSymp = m_curSymp; - { - m_beginNum = 0; - m_beginp = nodep; - m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); - m_curSymp->fallbackp(oldCurSymp); - // Iterate + if (nodep->name() == "") { iterateChildren(nodep); + } else { + int oldNum = m_beginNum; + AstBegin* oldbegin = m_beginp; + VSymEnt* oldCurSymp = m_curSymp; + { + m_beginNum = 0; + m_beginp = nodep; + m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); + m_curSymp->fallbackp(oldCurSymp); + // Iterate + iterateChildren(nodep); + } + m_curSymp = oldCurSymp; + m_beginp = oldbegin; + m_beginNum = oldNum; } - m_curSymp = oldCurSymp; - m_beginp = oldbegin; - m_beginNum = oldNum; } virtual void visit(AstNodeFTask* nodep) VL_OVERRIDE { // NodeTask: Remember its name for later resolution @@ -2449,8 +2453,10 @@ private: checkNoDot(nodep); VSymEnt* oldCurSymp = m_curSymp; { - m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); - UINFO(5," cur=se"<name() != "") { + m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep); + UINFO(5," cur=se"<addNext(new AstWhile(fl, condp, newp, incp)); - newp = new AstBegin(nodep->fileline(), "", stmtsp); + newp = new AstBegin(nodep->fileline(), "", stmtsp, false, true); dimension--; } //newp->dumpTree(cout, "-foreach-new:"); @@ -488,6 +488,21 @@ private: virtual void visit(AstBegin* nodep) VL_OVERRIDE { V3Config::applyCoverageBlock(m_modp, nodep); cleanFileline(nodep); + AstNode* backp = nodep->backp(); + // IEEE says directly nested item is not a new block + bool nestedIf = (nodep->implied() // User didn't provide begin/end + && (VN_IS(nodep->stmtsp(), GenIf) + || VN_IS(nodep->stmtsp(), GenCase)) // Has an if/case + && !nodep->stmtsp()->nextp()); // Has only one item + // 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) { + nodep->name("genblk"); + } iterateChildren(nodep); } virtual void visit(AstCase* nodep) VL_OVERRIDE { diff --git a/src/verilog.y b/src/verilog.y index 211e60a0b..f7b9320e7 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2047,18 +2047,18 @@ generate_block_or_null: // IEEE: generate_block_or_null (called from genc // ';' // is included in // // IEEE: generate_block // // Must always return a BEGIN node, or NULL - see GenFor construction - generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"genblk",$1,true)) : NULL; } + generate_item { $$ = $1 ? (new AstBegin($1->fileline(),"",$1,true,true)) : NULL; } | genItemBegin { $$ = $1; } ; genItemBegin: // IEEE: part of generate_block - yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"genblk",$2,true); } + yBEGIN ~c~genItemList yEND { $$ = new AstBegin($1,"",$2,true,false); } | yBEGIN yEND { $$ = NULL; } | id ':' yBEGIN ~c~genItemList yEND endLabelE - { $$ = new AstBegin($1,*$1,$4,true); GRAMMARP->endLabel($6,*$1,$6); } + { $$ = new AstBegin($1,*$1,$4,true,false); GRAMMARP->endLabel($6,*$1,$6); } | id ':' yBEGIN yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($5,*$1,$5); } | yBEGIN ':' idAny ~c~genItemList yEND endLabelE - { $$ = new AstBegin($3,*$3,$4,true); GRAMMARP->endLabel($6,*$3,$6); } + { $$ = new AstBegin($3,*$3,$4,true,false); GRAMMARP->endLabel($6,*$3,$6); } | yBEGIN ':' idAny yEND endLabelE { $$ = NULL; GRAMMARP->endLabel($5,*$3,$5); } ; @@ -2116,11 +2116,11 @@ loop_generate_construct: // ==IEEE: loop_generate_construct { // Convert BEGIN(...) to BEGIN(GENFOR(...)), as we need the BEGIN to hide the local genvar AstBegin* lowerBegp = VN_CAST($9, Begin); UASSERT_OBJ(!($9 && !lowerBegp), $9, "Child of GENFOR should have been begin"); - if (!lowerBegp) lowerBegp = new AstBegin($1,"genblk",NULL,true); // Empty body + if (!lowerBegp) lowerBegp = new AstBegin($1, "genblk", NULL, true, true); // Empty body AstNode* lowerNoBegp = lowerBegp->stmtsp(); if (lowerNoBegp) lowerNoBegp->unlinkFrBackWithNext(); // - AstBegin* blkp = new AstBegin($1,lowerBegp->name(),NULL,true); + AstBegin* blkp = new AstBegin($1, lowerBegp->name(), NULL, true, true); // V3LinkDot detects BEGIN(GENFOR(...)) as a special case AstNode* initp = $3; AstNode* varp = $3; if (VN_IS(varp, Var)) { // Genvar @@ -2793,10 +2793,10 @@ statement_item: // IEEE: statement_item statementFor: // IEEE: part of statement yFOR '(' for_initialization expr ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1,"",$3); + { $$ = new AstBegin($1, "", $3, false, true); $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock - { $$ = new AstBegin($1,"",$3); + { $$ = new AstBegin($1, "", $3, false, true); $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::LogicTrue()),$7,$5)); } ; @@ -4473,7 +4473,7 @@ assertion_item: // ==IEEE: assertion_item deferred_immediate_assertion_item: // ==IEEE: deferred_immediate_assertion_item deferred_immediate_assertion_statement { $$ = $1; } | id/*block_identifier*/ ':' deferred_immediate_assertion_statement - { $$ = new AstBegin($1, *$1, $3); } + { $$ = new AstBegin($1, *$1, $3, false, true); } ; procedural_assertion_statement: // ==IEEE: procedural_assertion_statement @@ -4528,7 +4528,8 @@ deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_ass concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement { $$ = $1; } - | id/*block_identifier*/ ':' concurrent_assertion_statement { $$ = new AstBegin($1, *$1, $3); } + | id/*block_identifier*/ ':' concurrent_assertion_statement + { $$ = new AstBegin($1, *$1, $3, false, true); } // // IEEE: checker_instantiation // // identical to module_instantiation; see etcInst ; diff --git a/test_regress/t/t_gen_genblk.out b/test_regress/t/t_gen_genblk.out new file mode 100644 index 000000000..abaca2eeb --- /dev/null +++ b/test_regress/t/t_gen_genblk.out @@ -0,0 +1,6 @@ +010: exp=top.t.show0 got=top.t.show0 +014: exp=top.t.genblk1.show1 got=top.t.genblk1.show1 +018: exp=top.t.genblk2.show2 got=top.t.genblk2.show2 +023: exp=top.t.genblk3.genblk1.show3 got=top.t.genblk3.genblk1.show3 +029: exp=top.t.x1.x3.show4 got=top.t.x1.x3.show4 +*-* All Finished *-* diff --git a/test_regress/t/t_gen_genblk.pl b/test_regress/t/t_gen_genblk.pl new file mode 100755 index 000000000..e109f0f6c --- /dev/null +++ b/test_regress/t/t_gen_genblk.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(simulator => 1); + +compile( + ); + +execute( + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_gen_genblk.v b/test_regress/t/t_gen_genblk.v new file mode 100644 index 000000000..bb28c18be --- /dev/null +++ b/test_regress/t/t_gen_genblk.v @@ -0,0 +1,51 @@ +module t (/*AUTOARG*/ + // Inputs + clk, reset_l + ); + + input clk; + input reset_l; + + generate + show #(`__LINE__, "top.t.show0") show0(); + + if (0) ; + else if (0) ; + else if (1) show #(`__LINE__, "top.t.genblk1.show1") show1(); + + if (0) begin end + else if (0) begin end + else if (1) begin show #(`__LINE__, "top.t.genblk2.show2") show2(); end + + if (0) ; + else begin + if (0) begin end + else if (1) begin show #(`__LINE__, "top.t.genblk3.genblk1.show3") show3(); end + end + + if (0) ; + else begin : x1 + if (0) begin : x2 end + else if (1) begin : x3 show #(`__LINE__, "top.t.x1.x3.show4") show4(); end + end + endgenerate + + int cyc; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + + end +endmodule + +module show #(parameter LINE=0, parameter string EXPT) (); + always @ (posedge t.clk) begin + if (t.cyc == LINE) begin + $display("%03d: exp=%s got=%m", LINE, EXPT); + end + end +endmodule diff --git a/test_regress/t/t_gen_genblk_noinl.pl b/test_regress/t/t_gen_genblk_noinl.pl new file mode 100755 index 000000000..901e0993c --- /dev/null +++ b/test_regress/t/t_gen_genblk_noinl.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +top_filename("t_gen_genblk.v"); + +scenarios(simulator => 1); + +compile( + v_flags2 => ["-Oi"], + ); + +execute( + expect_filename => "t/t_gen_genblk.out", + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_gen7.v b/test_regress/t/t_interface_gen7.v index dcec13228..c1a0d2a41 100644 --- a/test_regress/t/t_interface_gen7.v +++ b/test_regress/t/t_interface_gen7.v @@ -24,7 +24,7 @@ module t(); generate genvar the_genvar; - begin + begin : ia for (the_genvar = 0; the_genvar < 2; the_genvar++) begin : TestIf begin assign my_intf[the_genvar].val = '1; @@ -36,7 +36,7 @@ module t(); generate genvar the_second_genvar; - begin + begin : ib intf #(.PARAM(1)) my_intf [1:0] (); for (the_second_genvar = 0; the_second_genvar < 2; the_second_genvar++) begin : TestIf begin @@ -49,7 +49,7 @@ module t(); generate genvar the_third_genvar; - begin + begin : ic for (the_third_genvar = 0; the_third_genvar < 2; the_third_genvar++) begin : TestIf begin intf #(.PARAM(1)) my_intf [1:0] (); diff --git a/test_regress/t/t_var_dotted2.v b/test_regress/t/t_var_dotted2.v new file mode 100644 index 000000000..7138dbd86 --- /dev/null +++ b/test_regress/t/t_var_dotted2.v @@ -0,0 +1,131 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty 2020 by Wilson Snyder. + +`ifdef USE_INLINE + `define INLINE_MODULE /*verilator inline_module*/ +`else + `define INLINE_MODULE /*verilator public_module*/ +`endif + +module t (/*AUTOARG*/); + +`define DRAM1(bank) mem.mem_bank[bank].dccm.dccm_bank.ram_core +`define DRAM2(bank) mem.mem_bank2[bank].dccm.dccm_bank.ram_core +`define DRAM3(bank) mem.mem_bank3[bank].dccm.dccm_bank.ram_core +`define DRAM4(bank) mem.sub4.mem_bank4[bank].dccm.dccm_bank.ram_core + + initial begin + `DRAM1(0)[3] = 130; + `DRAM1(1)[3] = 131; + `DRAM2(0)[3] = 230; + `DRAM2(1)[3] = 231; + `DRAM3(0)[3] = 330; + `DRAM3(1)[3] = 331; + `DRAM4(0)[3] = 430; + `DRAM4(1)[3] = 431; + if (`DRAM1(0)[3] !== 130) $stop; + if (`DRAM1(1)[3] !== 131) $stop; + if (`DRAM2(0)[3] !== 230) $stop; + if (`DRAM2(1)[3] !== 231) $stop; + if (`DRAM3(0)[3] !== 330) $stop; + if (`DRAM3(1)[3] !== 331) $stop; + if (`DRAM4(0)[3] !== 430) $stop; + if (`DRAM4(1)[3] !== 431) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + + eh2_lsu_dccm_mem mem (/*AUTOINST*/); + +endmodule + +module eh2_lsu_dccm_mem +#( + DCCM_INDEX_DEPTH = 8192, + DCCM_NUM_BANKS = 2 + )( +); + `INLINE_MODULE + + // 8 Banks, 16KB each (2048 x 72) + for (genvar i=0; i 1); + +top_filename("t/t_var_dotted2.v"); + +compile( + v_flags2 => ['+define+NOUSE_INLINE',], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_dotted2_inl1.pl b/test_regress/t/t_var_dotted2_inl1.pl new file mode 100755 index 000000000..eba0adacc --- /dev/null +++ b/test_regress/t/t_var_dotted2_inl1.pl @@ -0,0 +1,23 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(simulator => 1); + +top_filename("t/t_var_dotted2.v"); + +compile( + v_flags2 => ['+define+USE_INLINE',], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_dotted_dup_bad.out b/test_regress/t/t_var_dotted_dup_bad.out new file mode 100644 index 000000000..bcda5f416 --- /dev/null +++ b/test_regress/t/t_var_dotted_dup_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_var_dotted_dup_bad.v:13: Duplicate declaration of cell: 'dccm_bank' + eh2_ram dccm_bank (.*); + ^~~~~~~~~ + t/t_var_dotted_dup_bad.v:10: ... Location of original declaration + eh2_ram dccm_bank (.*); + ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_var_dotted_dup_bad.pl b/test_regress/t/t_var_dotted_dup_bad.pl new file mode 100755 index 000000000..e142ae153 --- /dev/null +++ b/test_regress/t/t_var_dotted_dup_bad.pl @@ -0,0 +1,18 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2005 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. + +scenarios(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_dotted_dup_bad.v b/test_regress/t/t_var_dotted_dup_bad.v new file mode 100644 index 000000000..e22f6e514 --- /dev/null +++ b/test_regress/t/t_var_dotted_dup_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty 2020 by Wilson Snyder. + +module t (/*AUTOARG*/); + + generate + begin + eh2_ram dccm_bank (.*); + end + begin + eh2_ram dccm_bank (.*); // Error: duplicate + end + endgenerate + +endmodule + +module eh2_ram (); +endmodule diff --git a/test_regress/t/t_var_nonamebegin__log.out b/test_regress/t/t_var_nonamebegin__log.out index e9277860e..441195db4 100644 --- a/test_regress/t/t_var_nonamebegin__log.out +++ b/test_regress/t/t_var_nonamebegin__log.out @@ -1,9 +1,9 @@ ingen: {mod}.genblk1 top.t.genblk1 -d3a: {mod}.d3nameda top.t.d3nameda -b2: {mod} top.t -b3n: {mod}.b3named: top.t.b3named -b3: {mod} top.t -b4: {mod} top.t +d3a: {mod}.d3nameda top.t.unnamedblk1.d3nameda +b2: {mod} top.t.unnamedblk2 +b3n: {mod}.b3named: top.t.unnamedblk2.b3named +b3: {mod} top.t.unnamedblk2.unnamedblk3 +b4: {mod} top.t.unnamedblk2.unnamedblk3.unnamedblk4 t1 {mod}.tsk top.t -t2 {mod}.tsk top.t +t2 {mod}.tsk top.t.unnamedblk7 *-* All Finished *-* diff --git a/test_regress/t/t_var_notfound_bad.out b/test_regress/t/t_var_notfound_bad.out index cad5a6c9f..44bae4abf 100644 --- a/test_regress/t/t_var_notfound_bad.out +++ b/test_regress/t/t_var_notfound_bad.out @@ -13,7 +13,7 @@ : ... Suggested alternative: 'notfuncs' i = sub.nofuncs(); ^~~~~~~ - ... Known scopes under 'nofuncs': + ... Known scopes under 'nofuncs': sub %Error: t/t_var_notfound_bad.v:21: Can't find definition of task/function: 'notask' : ... Suggested alternative: 'nottask' notask();