forked from github/verilator
Support modport import, bug696.
This commit is contained in:
parent
daf19e241e
commit
bcefc17631
2
Changes
2
Changes
@ -5,6 +5,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.855 devel
|
||||
|
||||
*** Support modport import, bug696. [Jeremy Bennett]
|
||||
|
||||
*** Add --trace-structs to show struct names, bug673. [Chris Randall]
|
||||
|
||||
**** Fix tracing of packed structs, bug705. [Jie Xu]
|
||||
|
@ -753,6 +753,13 @@ void AstJumpGo::dump(ostream& str) {
|
||||
if (labelp()) { labelp()->dump(str); }
|
||||
else { str<<"%Error:UNLINKED"; }
|
||||
}
|
||||
void AstModportFTaskRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
if (isExport()) str<<" EXPORT";
|
||||
if (isImport()) str<<" IMPORT";
|
||||
if (ftaskp()) { str<<" -> "; ftaskp()->dump(str); }
|
||||
else { str<<" -> UNLINKED"; }
|
||||
}
|
||||
void AstModportVarRef::dump(ostream& str) {
|
||||
this->AstNode::dump(str);
|
||||
str<<" "<<varType();
|
||||
|
@ -1384,10 +1384,32 @@ struct AstIface : public AstNodeModule {
|
||||
ASTNODE_NODE_FUNCS(Iface, IFACE)
|
||||
};
|
||||
|
||||
struct AstModportFTaskRef : public AstNode {
|
||||
// An import/export referenced under a modport
|
||||
// The storage for the function itself is inside the interface/instantiator, thus this is a reference
|
||||
// PARENT: AstModport
|
||||
private:
|
||||
string m_name; // Name of the variable referenced
|
||||
bool m_export; // Type of the function (import/export)
|
||||
AstNodeFTask* m_ftaskp; // Link to the function
|
||||
public:
|
||||
AstModportFTaskRef(FileLine* fl, const string& name, bool isExport)
|
||||
: AstNode(fl), m_name(name), m_export(isExport), m_ftaskp(NULL) { }
|
||||
ASTNODE_NODE_FUNCS(ModportFTaskRef, MODPORTFTASKREF)
|
||||
virtual const char* broken() const { BROKEN_RTN(m_ftaskp && !m_ftaskp->brokeExists()); return NULL; }
|
||||
virtual void dump(ostream& str);
|
||||
virtual string name() const { return m_name; }
|
||||
virtual void cloneRelink() { if (m_ftaskp && m_ftaskp->clonep()) m_ftaskp = m_ftaskp->clonep()->castNodeFTask(); }
|
||||
bool isImport() const { return !m_export; }
|
||||
bool isExport() const { return m_export; }
|
||||
AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable
|
||||
void ftaskp(AstNodeFTask* ftaskp) { m_ftaskp=ftaskp; }
|
||||
};
|
||||
|
||||
struct AstModportVarRef : public AstNode {
|
||||
// A input/output/etc variable referenced under a modport
|
||||
// The storage for the variable itself is inside the interface, thus this is a reference
|
||||
// PARENT: AstIface
|
||||
// PARENT: AstModport
|
||||
private:
|
||||
string m_name; // Name of the variable referenced
|
||||
AstVarType m_type; // Type of the variable (in/out)
|
||||
@ -1398,8 +1420,9 @@ public:
|
||||
ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
|
||||
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
|
||||
virtual void dump(ostream& str);
|
||||
AstVarType varType() const { return m_type; } // * = Type of variable
|
||||
virtual void cloneRelink() { if (m_varp && m_varp->clonep()) m_varp = m_varp->clonep()->castVar(); }
|
||||
virtual string name() const { return m_name; }
|
||||
AstVarType varType() const { return m_type; } // * = Type of variable
|
||||
bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
|
||||
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
|
||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||
@ -1411,13 +1434,13 @@ struct AstModport : public AstNode {
|
||||
private:
|
||||
string m_name; // Name of the modport
|
||||
public:
|
||||
AstModport(FileLine* fl, const string& name, AstModportVarRef* varsp)
|
||||
AstModport(FileLine* fl, const string& name, AstNode* varsp)
|
||||
: AstNode(fl), m_name(name) {
|
||||
addNOp1p(varsp); }
|
||||
virtual string name() const { return m_name; }
|
||||
virtual bool maybePointedTo() const { return true; }
|
||||
ASTNODE_NODE_FUNCS(Modport, MODPORT)
|
||||
AstModportVarRef* varsp() const { return op1p()->castModportVarRef(); } // op1 = List of Vars
|
||||
AstNode* varsp() const { return op1p(); } // op1 = List of Vars
|
||||
};
|
||||
|
||||
struct AstCell : public AstNode {
|
||||
|
@ -1202,6 +1202,26 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
||||
}
|
||||
m_curSymp = oldCurSymp;
|
||||
}
|
||||
virtual void visit(AstModportFTaskRef* nodep, AstNUser*) {
|
||||
UINFO(5," fif: "<<nodep<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->isExport()) nodep->v3error("Unsupported: modport export");
|
||||
VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
|
||||
if (!symp) {
|
||||
nodep->v3error("Modport item not found: "<<nodep->prettyName());
|
||||
} else if (AstNodeFTask* ftaskp = symp->nodep()->castNodeFTask()) {
|
||||
// Make symbol under modport that points at the _interface_'s var, not the modport.
|
||||
nodep->ftaskp(ftaskp);
|
||||
m_statep->insertSym(m_curSymp, nodep->name(), ftaskp, NULL/*package*/);
|
||||
} else {
|
||||
nodep->v3error("Modport item is not a function/task: "<<nodep->prettyName());
|
||||
}
|
||||
if (m_statep->forScopeCreation()) {
|
||||
// Done with AstModportFTaskRef.
|
||||
// Delete to prevent problems if we dead-delete pointed to ftask
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstModportVarRef* nodep, AstNUser*) {
|
||||
UINFO(5," fiv: "<<nodep<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
|
@ -66,7 +66,6 @@ struct V3ParseBisonYYSType {
|
||||
AstCell* cellp;
|
||||
AstConst* constp;
|
||||
AstMemberDType* memberp;
|
||||
AstModportVarRef* modportvarrefp;
|
||||
AstNodeModule* modulep;
|
||||
AstNodeClassDType* classp;
|
||||
AstNodeDType* dtypep;
|
||||
|
@ -353,6 +353,11 @@ private:
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstModportFTaskRef* nodep, AstNUser*) {
|
||||
// The crossrefs are dealt with in V3LinkDot
|
||||
nodep->ftaskp(NULL);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
|
@ -1058,22 +1058,27 @@ modport_item<nodep>: // ==IEEE: modport_item
|
||||
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
|
||||
;
|
||||
|
||||
modportPortsDeclList<modportvarrefp>:
|
||||
modportPortsDeclList<nodep>:
|
||||
modportPortsDecl { $$ = $1; }
|
||||
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVarRef(); }
|
||||
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3); }
|
||||
;
|
||||
|
||||
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
|
||||
// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
|
||||
// We've expanded the lists each take to instead just have standalone ID ports.
|
||||
// We track the type as with the V2k series of defines, then create as each ID is seen.
|
||||
modportPortsDecl<modportvarrefp>:
|
||||
modportPortsDecl<nodep>:
|
||||
// // IEEE: modport_simple_ports_declaration
|
||||
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
|
||||
// // IEEE: modport_clocking_declaration
|
||||
//UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
|
||||
//UNSUP yIMPORT modport_tf_port { }
|
||||
//UNSUP yEXPORT modport_tf_port { }
|
||||
| yCLOCKING idAny/*clocking_identifier*/ { $1->v3error("Unsupported: Modport clocking"); }
|
||||
// // IEEE: yIMPORT modport_tf_port
|
||||
// // IEEE: yEXPORT modport_tf_port
|
||||
// // modport_tf_port expanded here
|
||||
| yIMPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($<fl>1,*$2,false); }
|
||||
| yEXPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($<fl>1,*$2,true); }
|
||||
| yIMPORT method_prototype { $1->v3error("Unsupported: Modport import with prototype"); }
|
||||
| yEXPORT method_prototype { $1->v3error("Unsupported: Modport export with prototype"); }
|
||||
// Continuations of above after a comma.
|
||||
// // IEEE: modport_simple_ports_declaration
|
||||
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
|
||||
@ -2632,6 +2637,11 @@ funcIsolateE<cint>:
|
||||
| yVL_ISOLATE_ASSIGNMENTS { $$ = 1; }
|
||||
;
|
||||
|
||||
method_prototype:
|
||||
task_prototype { }
|
||||
| function_prototype { }
|
||||
;
|
||||
|
||||
lifetimeE: // IEEE: [lifetime]
|
||||
/* empty */ { }
|
||||
| lifetime { }
|
||||
|
20
test_regress/t/t_interface_modport_export.pl
Executable file
20
test_regress/t/t_interface_modport_export.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, bug696");
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
74
test_regress/t/t_interface_modport_export.v
Normal file
74
test_regress/t/t_interface_modport_export.v
Normal file
@ -0,0 +1,74 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// A test of the export parameter used with modport
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2013 by Jeremy Bennett.
|
||||
|
||||
interface test_if;
|
||||
|
||||
// Pre-declare function
|
||||
extern function myfunc (input logic val);
|
||||
|
||||
// Interface variable
|
||||
logic data;
|
||||
|
||||
// Modport
|
||||
modport mp_e(
|
||||
export myfunc,
|
||||
output data
|
||||
);
|
||||
|
||||
// Modport
|
||||
modport mp_i(
|
||||
import myfunc,
|
||||
output data
|
||||
);
|
||||
|
||||
endinterface // test_if
|
||||
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
test_if i ();
|
||||
|
||||
testmod_callee testmod_callee_i (.ie (i.mp_e));
|
||||
testmod_caller testmod_caller_i (.clk (clk),
|
||||
.ii (i.mp_i));
|
||||
endmodule
|
||||
|
||||
|
||||
module testmod_callee
|
||||
(
|
||||
test_if.mp_e ie
|
||||
);
|
||||
|
||||
function automatic logic ie.myfunc (input logic val);
|
||||
begin
|
||||
myfunc = (val == 1'b0);
|
||||
end
|
||||
endfunction
|
||||
endmodule // testmod_caller
|
||||
|
||||
|
||||
module testmod_caller
|
||||
(
|
||||
input clk,
|
||||
test_if.mp_i ii
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
ii.data = 1'b0;
|
||||
if (ii.myfunc (1'b0)) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
18
test_regress/t/t_interface_modport_import.pl
Executable file
18
test_regress/t/t_interface_modport_import.pl
Executable file
@ -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 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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
58
test_regress/t/t_interface_modport_import.v
Normal file
58
test_regress/t/t_interface_modport_import.v
Normal file
@ -0,0 +1,58 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// A test of the import parameter used with modport
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2013 by Jeremy Bennett.
|
||||
|
||||
interface test_if;
|
||||
|
||||
// Interface variable
|
||||
logic data;
|
||||
|
||||
// Modport
|
||||
modport mp(
|
||||
import myfunc,
|
||||
output data
|
||||
);
|
||||
|
||||
function automatic logic myfunc (input logic val);
|
||||
begin
|
||||
myfunc = (val == 1'b0);
|
||||
end
|
||||
endfunction
|
||||
|
||||
endinterface // test_if
|
||||
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
test_if i ();
|
||||
|
||||
testmod testmod_i (.clk (clk),
|
||||
.i (i.mp));
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
module testmod
|
||||
(
|
||||
input clk,
|
||||
test_if.mp i
|
||||
);
|
||||
|
||||
always @(posedge clk) begin
|
||||
i.data = 1'b0;
|
||||
if (i.myfunc (1'b0)) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else begin
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user