Support modport import, bug696.

This commit is contained in:
Wilson Snyder 2013-12-21 06:51:15 -05:00
parent daf19e241e
commit bcefc17631
11 changed files with 247 additions and 11 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -66,7 +66,6 @@ struct V3ParseBisonYYSType {
AstCell* cellp;
AstConst* constp;
AstMemberDType* memberp;
AstModportVarRef* modportvarrefp;
AstNodeModule* modulep;
AstNodeClassDType* classp;
AstNodeDType* dtypep;

View File

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

View File

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

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, bug696");
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View 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

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

View 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