diff --git a/Changes b/Changes index a6f40b958..3a5b4bbff 100644 --- a/Changes +++ b/Changes @@ -10,6 +10,8 @@ indicates the contributor was also the author of the fix; Thanks! Verilated models. This may affect packed arrays that are public or accessed via the VPI. +*** Support bind, to module names only, bug602. [Ed Lander] + * Verilator 3.844 2013/01/09 *** Support "unsigned int" DPI import functions, msg966. [Alex Lee] diff --git a/bin/verilator b/bin/verilator index 7bb434c17..8cb0fd01b 100755 --- a/bin/verilator +++ b/bin/verilator @@ -2327,6 +2327,11 @@ always @* to reduce missing activity items. Avoid putting $displays in combo blocks, as they may print multiple times when not desired, even on compliant simulators as event ordering is not specified. +=head2 Bind + +Verilator only supports "bind" to a target module name, not an instance +path. + =head2 Dotted cross-hierarchy references Verilator supports dotted references to variables, functions and tasks in diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 4747852ab..98d09db36 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -1331,6 +1331,25 @@ public: virtual void name(const string& name) { m_name = name; } }; +struct AstBind : public AstNode { + // Parents: MODULE + // Children: CELL +private: + string m_name; // Binding to name +public: + AstBind(FileLine* fl, const string& name, AstNode* cellsp) + : AstNode(fl) + , m_name(name) { + if (!cellsp->castCell()) cellsp->v3fatalSrc("Only cells allowed to be bound"); + addNOp1p(cellsp); + } + ASTNODE_NODE_FUNCS(Bind, BIND) + // ACCESSORS + virtual string name() const { return m_name; } // * = Bind Target name + virtual void name(const string& name) { m_name = name; } + AstNode* cellsp() const { return op1p(); } // op1= cells +}; + struct AstPort : public AstNode { // A port (in/out/inout) on a module private: diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 46deb2a6f..99a08bba0 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -90,6 +90,7 @@ private: // NODE STATE // Entire netlist: // AstNodeModule::user1p() // V3GraphVertex* Vertex describing this module + // AstCell::user1() // bool Did it. // Allocated across all readFiles in V3Global::readFiles: // AstNode::user4p() // VSymEnt* Package and typedef symbol names AstUser1InUse m_inuser1; @@ -121,6 +122,26 @@ private: return (nodep->user1p()->castGraphVertex()); } + AstNodeModule* resolveModule(AstNode* nodep, const string& modName) { + AstNodeModule* modp = m_mods.rootp()->findIdFallback(modName)->nodep()->castNodeModule(); + if (!modp) { + // Read-subfile + // If file not found, make AstNotFoundModule, rather than error out. + // We'll throw the error when we know the module will really be needed. + V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp); + parser.parseFile(nodep->fileline(), modName, false, ""); + V3Error::abortIfErrors(); + // We've read new modules, grab new pointers to their names + readModNames(); + // Check again + modp = m_mods.rootp()->findIdFallback(modName)->nodep()->castNodeModule(); + if (!modp) { + nodep->v3error("Can't resolve module reference: "<iterateChildren(*this); nodep->checkTree(); m_modp = NULL; @@ -192,28 +214,35 @@ private: new V3GraphEdge(&m_graph, vertex(m_modp), vertex(nodep->packagep()), 1, false); } + virtual void visit(AstBind* nodep, AstNUser*) { + // Bind: Has cells underneath that need to be put into the new module, and cells which need resolution + // 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: "<name()); + if (modp) { + AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext(); + // Module may have already linked, so need to pick up these new cells + AstNodeModule* oldModp = m_modp; + { + m_modp = modp; + modp->addStmtp(cellsp); // Important that this adds to end, as next iterate assumes does all cells + cellsp->iterateAndNext(*this); + } + m_modp = oldModp; + } + pushDeletep(nodep->unlinkFrBack()); + } + virtual void visit(AstCell* nodep, AstNUser*) { // Cell: Resolve its filename. If necessary, parse it. + if (nodep->user1SetOnce()) return; // AstBind and AstNodeModule may call a cell twice if (!nodep->modp()) { UINFO(4,"Link Cell: "<findIdFallback(nodep->modName())->nodep()->castNodeModule(); - if (!modp) { - // Read-subfile - // If file not found, make AstNotFoundModule, rather than error out. - // We'll throw the error when we know the module will really be needed. - V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp); - parser.parseFile(nodep->fileline(), nodep->modName(), false, ""); - V3Error::abortIfErrors(); - // We've read new modules, grab new pointers to their names - readModNames(); - // Check again - modp = m_mods.rootp()->findIdFallback(nodep->modName())->nodep()->castNodeModule(); - if (!modp) { - nodep->v3error("Can't resolve module reference: "<modName()); - } - } + AstNodeModule* modp = resolveModule(nodep,nodep->modName()); if (modp) { nodep->modp(modp); // Track module depths, so can sort list from parent down to children diff --git a/src/verilog.l b/src/verilog.l index 41e9ff577..f4bed2e2d 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -398,6 +398,7 @@ word [a-zA-Z0-9_]+ "always_comb" { FL; return yALWAYS; } "always_ff" { FL; return yALWAYS; } "always_latch" { FL; return yALWAYS; } + "bind" { FL; return yBIND; } "bit" { FL; return yBIT; } "break" { FL; return yBREAK; } "byte" { FL; return yBYTE; } @@ -440,7 +441,6 @@ word [a-zA-Z0-9_]+ /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */ "$root" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "alias" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } - "bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } diff --git a/src/verilog.y b/src/verilog.y index 6a593cc52..65e853c8e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -282,6 +282,7 @@ class AstSenTree; %token yASSIGN "assign" %token yAUTOMATIC "automatic" %token yBEGIN "begin" +%token yBIND "bind" %token yBIT "bit" %token yBREAK "break" %token yBUF "buf" @@ -1512,7 +1513,7 @@ module_common_item: // ==IEEE: module_common_item // // + module_instantiation from module_or_generate_item | etcInst { $$ = $1; } | concurrent_assertion_item { $$ = $1; } - //UNSUP bind_directive { $$ = $1; } + | bind_directive { $$ = $1; } | continuous_assign { $$ = $1; } // // IEEE: net_alias //UNSUP yALIAS variable_lvalue aliasEqList ';' { UNSUP } @@ -1549,6 +1550,31 @@ module_or_generate_item_declaration: // ==IEEE: module_or_generate_item_d //UNSUP yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = $1; } ; +bind_directive: // ==IEEE: bind_directive + bind_target_scope + // // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation + // // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier + yBIND bind_target_instance bind_instantiation { $$ = new AstBind($1,*$2,$3); } + | yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation { $$=NULL; $1->v3error("Unsupported: Bind with instance list"); } + ; + +bind_target_instance_list: // ==IEEE: bind_target_instance_list + bind_target_instance { } + | bind_target_instance_list ',' bind_target_instance { } + ; + +bind_target_instance: // ==IEEE: bind_target_instance + //UNSUP hierarchical_identifierBit { } + idAny { $$ = $1; } + ; + +bind_instantiation: // ==IEEE: bind_instantiation + // // IEEE: program_instantiation + // // IEEE: + module_instantiation + // // IEEE: + interface_instantiation + // // Need to get an AstBind instead of AstCell, so have special rules + instDecl { $$ = $1; } + ; + //************************************************ // Generates // diff --git a/test_regress/t/t_bind.pl b/test_regress/t/t_bind.pl index 87dfe1002..30da50378 100755 --- a/test_regress/t/t_bind.pl +++ b/test_regress/t/t_bind.pl @@ -7,14 +7,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. -$Self->{vlt} and $Self->unsupported("Verilator unsupported, bind"); - compile ( - ); + ); execute ( - check_finished=>1, - ); + check_finished=>1, + ); ok(1); 1; diff --git a/test_regress/t/t_bind2.pl b/test_regress/t/t_bind2.pl new file mode 100755 index 000000000..3a4d8b31a --- /dev/null +++ b/test_regress/t/t_bind2.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. + +$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug602"); + +compile ( + ); + +execute ( + check_finished=>1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_bind2.v b/test_regress/t/t_bind2.v new file mode 100644 index 000000000..6aeb26e7b --- /dev/null +++ b/test_regress/t/t_bind2.v @@ -0,0 +1,89 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2013 by Ed Lander. + +`define check(got,expec) do if ((got) != (expec)) begin $display("Line%0d: Got 0x%0x Exp 0x%0x\n", `__LINE__, (got), (expec)); $stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + reg [7:0] p1; + reg [7:0] p2; + reg [7:0] p3; + + initial begin + p1 = 8'h01; + p2 = 8'h02; + p3 = 8'h03; + end + + parameter int param1 = 8'h11; + parameter int param2 = 8'h12; + parameter int param3 = 8'h13; + + targetmod i_targetmod (/*AUTOINST*/ + // Inputs + .clk (clk)); + + //Binding i_targetmod to mycheck --instantiates i_mycheck inside i_targetmod + //param1 not over-riden (as mycheck) (=> 0x31) + //param2 explicitly bound to targetmod value (=> 0x22) + //param3 explicitly bound to top value (=> 0x13) + //p1 implictly bound (.*), takes value from targetmod (=> 0x04) + //p2 explictly bound to targetmod (=> 0x05) + //p3 explictly bound to top (=> 0x03) + + bind i_targetmod mycheck + #( + .param2(param2), + .param3(param3) + ) + i_mycheck (.p2(p2), .p3(p3), .*); + +endmodule + +module targetmod (input clk); + reg [7:0] p1; + reg [7:0] p2; + reg [7:0] p3; + + parameter int param1 = 8'h21; + parameter int param2 = 8'h22; + parameter int param3 = 8'h23; + + initial begin + p1 = 8'h04; + p2 = 8'h05; + p3 = 8'h06; + end +endmodule + +module mycheck (/*AUTOARG*/ + // Inputs + clk, p1, p2, p3 + ); + + input clk; + input [7:0] p1; + input [7:0] p2; + input [7:0] p3; + + parameter int param1 = 8'h31; + parameter int param2 = 8'h32; + parameter int param3 = 8'h33; + + always @ (posedge clk) begin + `check(param1,8'h31); + `check(param2,8'h22); + `check(param3,8'h23); + `check(p1,8'h04); + `check(p2,8'h05); + `check(p3,8'h06); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + diff --git a/test_regress/t/t_bitsel_struct2.v b/test_regress/t/t_bitsel_struct2.v index 1dd6bf179..27cb2cf91 100644 --- a/test_regress/t/t_bitsel_struct2.v +++ b/test_regress/t/t_bitsel_struct2.v @@ -14,7 +14,7 @@ module t (/*AUTOARG*/); c_t [17:16] d; } e_t; -`define check(got,expec) do if ((got) != (expec)) begin $display("Line%d: Got %b Exp %b\n", `__LINE__, (got), (expec)); $stop; end while(0); +`define check(got,expec) do if ((got) != (expec)) begin $display("Line%0d: Got %b Exp %b\n", `__LINE__, (got), (expec)); $stop; end while(0); initial begin e_t e;