diff --git a/Changes b/Changes index 020cb7193..6806f688e 100644 --- a/Changes +++ b/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] diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 178d8ffba..e61525605 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -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<<" "<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 { diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0463d75ce..f5da9b234 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1202,6 +1202,26 @@ class LinkDotIfaceVisitor : public AstNVisitor { } m_curSymp = oldCurSymp; } + virtual void visit(AstModportFTaskRef* nodep, AstNUser*) { + UINFO(5," fif: "<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: "<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: "<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: "<iterateChildren(*this); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 479ed4fb1..fb3f661fb 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -66,7 +66,6 @@ struct V3ParseBisonYYSType { AstCell* cellp; AstConst* constp; AstMemberDType* memberp; - AstModportVarRef* modportvarrefp; AstNodeModule* modulep; AstNodeClassDType* classp; AstNodeDType* dtypep; diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 3385f98dc..d076a3647 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -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 diff --git a/src/verilog.y b/src/verilog.y index 4837a21b6..f7bf4a9dd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1058,22 +1058,27 @@ modport_item: // ==IEEE: modport_item id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); } ; -modportPortsDeclList: +modportPortsDeclList: 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: +modportPortsDecl: // // IEEE: modport_simple_ports_declaration port_direction modportSimplePort { $$ = new AstModportVarRef($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($1,*$2,false); } + | yEXPORT id/*tf_identifier*/ { $$ = new AstModportFTaskRef($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($1,*$1,AstVarType::INOUT); } @@ -2632,6 +2637,11 @@ funcIsolateE: | yVL_ISOLATE_ASSIGNMENTS { $$ = 1; } ; +method_prototype: + task_prototype { } + | function_prototype { } + ; + lifetimeE: // IEEE: [lifetime] /* empty */ { } | lifetime { } diff --git a/test_regress/t/t_interface_modport_export.pl b/test_regress/t/t_interface_modport_export.pl new file mode 100755 index 000000000..4bd751bc4 --- /dev/null +++ b/test_regress/t/t_interface_modport_export.pl @@ -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; diff --git a/test_regress/t/t_interface_modport_export.v b/test_regress/t/t_interface_modport_export.v new file mode 100644 index 000000000..11a59f135 --- /dev/null +++ b/test_regress/t/t_interface_modport_export.v @@ -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 diff --git a/test_regress/t/t_interface_modport_import.pl b/test_regress/t/t_interface_modport_import.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_interface_modport_import.pl @@ -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; diff --git a/test_regress/t/t_interface_modport_import.v b/test_regress/t/t_interface_modport_import.v new file mode 100644 index 000000000..c963fbff7 --- /dev/null +++ b/test_regress/t/t_interface_modport_import.v @@ -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