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
|
* Verilator 3.855 devel
|
||||||
|
|
||||||
|
*** Support modport import, bug696. [Jeremy Bennett]
|
||||||
|
|
||||||
*** Add --trace-structs to show struct names, bug673. [Chris Randall]
|
*** Add --trace-structs to show struct names, bug673. [Chris Randall]
|
||||||
|
|
||||||
**** Fix tracing of packed structs, bug705. [Jie Xu]
|
**** Fix tracing of packed structs, bug705. [Jie Xu]
|
||||||
|
|
|
||||||
|
|
@ -753,6 +753,13 @@ void AstJumpGo::dump(ostream& str) {
|
||||||
if (labelp()) { labelp()->dump(str); }
|
if (labelp()) { labelp()->dump(str); }
|
||||||
else { str<<"%Error:UNLINKED"; }
|
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) {
|
void AstModportVarRef::dump(ostream& str) {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
str<<" "<<varType();
|
str<<" "<<varType();
|
||||||
|
|
|
||||||
|
|
@ -1384,10 +1384,32 @@ struct AstIface : public AstNodeModule {
|
||||||
ASTNODE_NODE_FUNCS(Iface, IFACE)
|
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 {
|
struct AstModportVarRef : public AstNode {
|
||||||
// A input/output/etc variable referenced under a modport
|
// A input/output/etc variable referenced under a modport
|
||||||
// The storage for the variable itself is inside the interface, thus this is a reference
|
// The storage for the variable itself is inside the interface, thus this is a reference
|
||||||
// PARENT: AstIface
|
// PARENT: AstModport
|
||||||
private:
|
private:
|
||||||
string m_name; // Name of the variable referenced
|
string m_name; // Name of the variable referenced
|
||||||
AstVarType m_type; // Type of the variable (in/out)
|
AstVarType m_type; // Type of the variable (in/out)
|
||||||
|
|
@ -1398,8 +1420,9 @@ public:
|
||||||
ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
|
ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
|
||||||
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
|
virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
|
||||||
virtual void dump(ostream& str);
|
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; }
|
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 isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
|
||||||
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
|
bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
|
||||||
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
|
||||||
|
|
@ -1411,13 +1434,13 @@ struct AstModport : public AstNode {
|
||||||
private:
|
private:
|
||||||
string m_name; // Name of the modport
|
string m_name; // Name of the modport
|
||||||
public:
|
public:
|
||||||
AstModport(FileLine* fl, const string& name, AstModportVarRef* varsp)
|
AstModport(FileLine* fl, const string& name, AstNode* varsp)
|
||||||
: AstNode(fl), m_name(name) {
|
: AstNode(fl), m_name(name) {
|
||||||
addNOp1p(varsp); }
|
addNOp1p(varsp); }
|
||||||
virtual string name() const { return m_name; }
|
virtual string name() const { return m_name; }
|
||||||
virtual bool maybePointedTo() const { return true; }
|
virtual bool maybePointedTo() const { return true; }
|
||||||
ASTNODE_NODE_FUNCS(Modport, MODPORT)
|
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 {
|
struct AstCell : public AstNode {
|
||||||
|
|
|
||||||
|
|
@ -1202,6 +1202,26 @@ class LinkDotIfaceVisitor : public AstNVisitor {
|
||||||
}
|
}
|
||||||
m_curSymp = oldCurSymp;
|
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*) {
|
virtual void visit(AstModportVarRef* nodep, AstNUser*) {
|
||||||
UINFO(5," fiv: "<<nodep<<endl);
|
UINFO(5," fiv: "<<nodep<<endl);
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,6 @@ struct V3ParseBisonYYSType {
|
||||||
AstCell* cellp;
|
AstCell* cellp;
|
||||||
AstConst* constp;
|
AstConst* constp;
|
||||||
AstMemberDType* memberp;
|
AstMemberDType* memberp;
|
||||||
AstModportVarRef* modportvarrefp;
|
|
||||||
AstNodeModule* modulep;
|
AstNodeModule* modulep;
|
||||||
AstNodeClassDType* classp;
|
AstNodeClassDType* classp;
|
||||||
AstNodeDType* dtypep;
|
AstNodeDType* dtypep;
|
||||||
|
|
|
||||||
|
|
@ -353,6 +353,11 @@ private:
|
||||||
}
|
}
|
||||||
nodep->iterateChildren(*this);
|
nodep->iterateChildren(*this);
|
||||||
}
|
}
|
||||||
|
virtual void visit(AstModportFTaskRef* nodep, AstNUser*) {
|
||||||
|
// The crossrefs are dealt with in V3LinkDot
|
||||||
|
nodep->ftaskp(NULL);
|
||||||
|
nodep->iterateChildren(*this);
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------
|
//--------------------
|
||||||
// Default
|
// Default
|
||||||
|
|
|
||||||
|
|
@ -1058,22 +1058,27 @@ modport_item<nodep>: // ==IEEE: modport_item
|
||||||
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
|
id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
modportPortsDeclList<modportvarrefp>:
|
modportPortsDeclList<nodep>:
|
||||||
modportPortsDecl { $$ = $1; }
|
modportPortsDecl { $$ = $1; }
|
||||||
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVarRef(); }
|
| modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
|
// IEEE: modport_ports_declaration + modport_simple_ports_declaration
|
||||||
// + (modport_tf_ports_declaration+import_export) + modport_clocking_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'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.
|
// 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
|
// // IEEE: modport_simple_ports_declaration
|
||||||
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
|
port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
|
||||||
// // IEEE: modport_clocking_declaration
|
// // IEEE: modport_clocking_declaration
|
||||||
//UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
|
| yCLOCKING idAny/*clocking_identifier*/ { $1->v3error("Unsupported: Modport clocking"); }
|
||||||
//UNSUP yIMPORT modport_tf_port { }
|
// // IEEE: yIMPORT modport_tf_port
|
||||||
//UNSUP yEXPORT 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.
|
// Continuations of above after a comma.
|
||||||
// // IEEE: modport_simple_ports_declaration
|
// // IEEE: modport_simple_ports_declaration
|
||||||
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
|
| modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
|
||||||
|
|
@ -2632,6 +2637,11 @@ funcIsolateE<cint>:
|
||||||
| yVL_ISOLATE_ASSIGNMENTS { $$ = 1; }
|
| yVL_ISOLATE_ASSIGNMENTS { $$ = 1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
method_prototype:
|
||||||
|
task_prototype { }
|
||||||
|
| function_prototype { }
|
||||||
|
;
|
||||||
|
|
||||||
lifetimeE: // IEEE: [lifetime]
|
lifetimeE: // IEEE: [lifetime]
|
||||||
/* empty */ { }
|
/* empty */ { }
|
||||||
| lifetime { }
|
| lifetime { }
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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