Support bind, to module names only, bug602.

This commit is contained in:
Wilson Snyder 2013-01-14 23:19:44 -05:00
parent aae0615ffd
commit 795e66eac9
10 changed files with 212 additions and 24 deletions

View File

@ -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 Verilated models. This may affect packed arrays that are public or
accessed via the VPI. accessed via the VPI.
*** Support bind, to module names only, bug602. [Ed Lander]
* Verilator 3.844 2013/01/09 * Verilator 3.844 2013/01/09
*** Support "unsigned int" DPI import functions, msg966. [Alex Lee] *** Support "unsigned int" DPI import functions, msg966. [Alex Lee]

View File

@ -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 combo blocks, as they may print multiple times when not desired, even on
compliant simulators as event ordering is not specified. 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 =head2 Dotted cross-hierarchy references
Verilator supports dotted references to variables, functions and tasks in Verilator supports dotted references to variables, functions and tasks in

View File

@ -1331,6 +1331,25 @@ public:
virtual void name(const string& name) { m_name = name; } 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 { struct AstPort : public AstNode {
// A port (in/out/inout) on a module // A port (in/out/inout) on a module
private: private:

View File

@ -90,6 +90,7 @@ private:
// NODE STATE // NODE STATE
// Entire netlist: // Entire netlist:
// AstNodeModule::user1p() // V3GraphVertex* Vertex describing this module // AstNodeModule::user1p() // V3GraphVertex* Vertex describing this module
// AstCell::user1() // bool Did it.
// Allocated across all readFiles in V3Global::readFiles: // Allocated across all readFiles in V3Global::readFiles:
// AstNode::user4p() // VSymEnt* Package and typedef symbol names // AstNode::user4p() // VSymEnt* Package and typedef symbol names
AstUser1InUse m_inuser1; AstUser1InUse m_inuser1;
@ -121,6 +122,26 @@ private:
return (nodep->user1p()->castGraphVertex()); 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: "<<modName);
}
}
return modp;
}
// VISITs // VISITs
virtual void visit(AstNetlist* nodep, AstNUser*) { virtual void visit(AstNetlist* nodep, AstNUser*) {
AstNode::user1ClearTree(); AstNode::user1ClearTree();
@ -180,6 +201,7 @@ private:
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph); if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false); new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false);
} }
// Note AstBind also has iteration on cells
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
nodep->checkTree(); nodep->checkTree();
m_modp = NULL; m_modp = NULL;
@ -192,28 +214,35 @@ private:
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(nodep->packagep()), 1, false); 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: "<<nodep<<endl);
AstNodeModule* modp = resolveModule(nodep,nodep->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*) { virtual void visit(AstCell* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it. // Cell: Resolve its filename. If necessary, parse it.
if (nodep->user1SetOnce()) return; // AstBind and AstNodeModule may call a cell twice
if (!nodep->modp()) { if (!nodep->modp()) {
UINFO(4,"Link Cell: "<<nodep<<endl); UINFO(4,"Link Cell: "<<nodep<<endl);
// Use findIdFallback instead of findIdFlat; it doesn't matter for now // Use findIdFallback instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday. // but we might support modules-under-modules someday.
AstNodeModule* modp = m_mods.rootp()->findIdFallback(nodep->modName())->nodep()->castNodeModule(); AstNodeModule* modp = resolveModule(nodep,nodep->modName());
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: "<<nodep->modName());
}
}
if (modp) { if (modp) {
nodep->modp(modp); nodep->modp(modp);
// Track module depths, so can sort list from parent down to children // Track module depths, so can sort list from parent down to children

View File

@ -398,6 +398,7 @@ word [a-zA-Z0-9_]+
"always_comb" { FL; return yALWAYS; } "always_comb" { FL; return yALWAYS; }
"always_ff" { FL; return yALWAYS; } "always_ff" { FL; return yALWAYS; }
"always_latch" { FL; return yALWAYS; } "always_latch" { FL; return yALWAYS; }
"bind" { FL; return yBIND; }
"bit" { FL; return yBIT; } "bit" { FL; return yBIT; }
"break" { FL; return yBREAK; } "break" { FL; return yBREAK; }
"byte" { FL; return yBYTE; } "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 */ /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
"$root" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); } "$root" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"alias" { 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); } "bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"binsof" { 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); } "class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }

View File

@ -282,6 +282,7 @@ class AstSenTree;
%token<fl> yASSIGN "assign" %token<fl> yASSIGN "assign"
%token<fl> yAUTOMATIC "automatic" %token<fl> yAUTOMATIC "automatic"
%token<fl> yBEGIN "begin" %token<fl> yBEGIN "begin"
%token<fl> yBIND "bind"
%token<fl> yBIT "bit" %token<fl> yBIT "bit"
%token<fl> yBREAK "break" %token<fl> yBREAK "break"
%token<fl> yBUF "buf" %token<fl> yBUF "buf"
@ -1512,7 +1513,7 @@ module_common_item<nodep>: // ==IEEE: module_common_item
// // + module_instantiation from module_or_generate_item // // + module_instantiation from module_or_generate_item
| etcInst { $$ = $1; } | etcInst { $$ = $1; }
| concurrent_assertion_item { $$ = $1; } | concurrent_assertion_item { $$ = $1; }
//UNSUP bind_directive { $$ = $1; } | bind_directive { $$ = $1; }
| continuous_assign { $$ = $1; } | continuous_assign { $$ = $1; }
// // IEEE: net_alias // // IEEE: net_alias
//UNSUP yALIAS variable_lvalue aliasEqList ';' { UNSUP } //UNSUP yALIAS variable_lvalue aliasEqList ';' { UNSUP }
@ -1549,6 +1550,31 @@ module_or_generate_item_declaration<nodep>: // ==IEEE: module_or_generate_item_d
//UNSUP yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = $1; } //UNSUP yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = $1; }
; ;
bind_directive<nodep>: // ==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($<fl>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<strp>: // ==IEEE: bind_target_instance
//UNSUP hierarchical_identifierBit { }
idAny { $$ = $1; }
;
bind_instantiation<nodep>: // ==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 // Generates
// //

View File

@ -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 # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bind");
compile ( compile (
); );
execute ( execute (
check_finished=>1, check_finished=>1,
); );
ok(1); ok(1);
1; 1;

20
test_regress/t/t_bind2.pl Executable file
View File

@ -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;

89
test_regress/t/t_bind2.v Normal file
View File

@ -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

View File

@ -14,7 +14,7 @@ module t (/*AUTOARG*/);
c_t [17:16] d; c_t [17:16] d;
} e_t; } 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 initial begin
e_t e; e_t e;