mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support bind, to module names only, bug602.
This commit is contained in:
parent
aae0615ffd
commit
795e66eac9
2
Changes
2
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]
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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: "<<modName);
|
||||
}
|
||||
}
|
||||
return modp;
|
||||
}
|
||||
|
||||
// VISITs
|
||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||
AstNode::user1ClearTree();
|
||||
@ -180,6 +201,7 @@ private:
|
||||
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
|
||||
new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false);
|
||||
}
|
||||
// Note AstBind also has iteration on cells
|
||||
nodep->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: "<<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*) {
|
||||
// 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: "<<nodep<<endl);
|
||||
// Use findIdFallback instead of findIdFlat; it doesn't matter for now
|
||||
// but we might support modules-under-modules someday.
|
||||
AstNodeModule* modp = m_mods.rootp()->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: "<<nodep->modName());
|
||||
}
|
||||
}
|
||||
AstNodeModule* modp = resolveModule(nodep,nodep->modName());
|
||||
if (modp) {
|
||||
nodep->modp(modp);
|
||||
// Track module depths, so can sort list from parent down to children
|
||||
|
@ -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); }
|
||||
|
@ -282,6 +282,7 @@ class AstSenTree;
|
||||
%token<fl> yASSIGN "assign"
|
||||
%token<fl> yAUTOMATIC "automatic"
|
||||
%token<fl> yBEGIN "begin"
|
||||
%token<fl> yBIND "bind"
|
||||
%token<fl> yBIT "bit"
|
||||
%token<fl> yBREAK "break"
|
||||
%token<fl> yBUF "buf"
|
||||
@ -1512,7 +1513,7 @@ module_common_item<nodep>: // ==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<nodep>: // ==IEEE: module_or_generate_item_d
|
||||
//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
|
||||
//
|
||||
|
@ -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;
|
||||
|
20
test_regress/t/t_bind2.pl
Executable file
20
test_regress/t/t_bind2.pl
Executable 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
89
test_regress/t/t_bind2.v
Normal 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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user