diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 83ecf5ffa..f3e8950f8 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -423,10 +423,45 @@ private: } } + void preserveTopIfaces(AstNetlist* rootp) { + for (AstNodeModule* modp = rootp->modulesp(); modp && modp->level() <= 2; + modp = VN_AS(modp->nextp(), NodeModule)) { + for (AstNode* subnodep = modp->stmtsp(); subnodep; subnodep = subnodep->nextp()) { + if (AstVar* const varp = VN_CAST(subnodep, Var)) { + if (varp->isIfaceRef()) { + const AstNodeDType* const subtypep = varp->subDTypep(); + const AstIfaceRefDType* ifacerefp = nullptr; + if (VN_IS(subtypep, IfaceRefDType)) { + ifacerefp = VN_AS(varp->subDTypep(), IfaceRefDType); + } + else if (VN_IS(subtypep, BracketArrayDType)) { + const AstBracketArrayDType* const arrp = VN_AS(subtypep, BracketArrayDType); + const AstNodeDType* const arrsubtypep = arrp->subDTypep(); + if (VN_IS(arrsubtypep, IfaceRefDType)) { + ifacerefp = VN_AS(arrsubtypep, IfaceRefDType); + } + } + else if (VN_IS(subtypep, UnpackArrayDType)) { + const AstUnpackArrayDType* const arrp = VN_AS(subtypep, UnpackArrayDType); + const AstNodeDType* const arrsubtypep = arrp->subDTypep(); + if (VN_IS(arrsubtypep, IfaceRefDType)) { + ifacerefp = VN_AS(arrsubtypep, IfaceRefDType); + } + } + + if (ifacerefp && !ifacerefp->cellp() && (ifacerefp->ifacep()->user1() == 0)) { + ifacerefp->ifacep()->user1(1); + } + } + } + } + } + } + public: // CONSTRUCTORS DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes, - bool elimCells) + bool elimCells, bool elimTopIfaces) : m_elimUserVars{elimUserVars} , m_elimDTypes{elimDTypes} , m_elimCells{elimCells} { @@ -442,6 +477,7 @@ public: if (elimCells) deadCheckCells(); deadCheckClasses(); // Modules after vars, because might be vars we delete inside a mod we delete + if (!elimTopIfaces) preserveTopIfaces(nodep); deadCheckMod(); // We may have removed some datatypes, cleanup @@ -455,30 +491,30 @@ public: void V3Dead::deadifyModules(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { DeadVisitor{nodep, false, false, false, false}; } // Destruct before checking + { DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTree() >= 6); } void V3Dead::deadifyDTypes(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { DeadVisitor{nodep, false, true, false, false}; } // Destruct before checking + { DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTree() >= 3); } void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { DeadVisitor{nodep, false, true, true, false}; } // Destruct before checking + { DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTree() >= 3); } void V3Dead::deadifyAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { DeadVisitor{nodep, true, true, false, true}; } // Destruct before checking + { DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTree() >= 3); } void V3Dead::deadifyAllScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); - { DeadVisitor{nodep, true, true, true, true}; } // Destruct before checking + { DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTree() >= 3); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 75681218f..f5d93991a 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -308,6 +308,19 @@ public: if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp); return symp; } + VSymEnt* insertTopIface(AstCell* nodep, const string& scopename) { + VSymEnt* const symp = new VSymEnt{&m_syms, nodep}; + UINFO(9, + " INSERTtopiface se" << cvtToHex(symp) << " " << scopename << " " << nodep << endl); + symp->parentp(rootEntp()); // Needed so backward search can find name of top module + symp->fallbackp(dunitEntp()); // Needed so can find $unit stuff + nodep->user1p(symp); + if (nodep->modp()) nodep->modp()->user1p(symp); + checkDuplicate(rootEntp(), nodep, nodep->origName()); + rootEntp()->insert(nodep->origName(), symp); + if (forScopeCreation()) m_nameScopeSymMap.emplace(scopename, symp); + return symp; + } VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp, AstCell* nodep, const string& scopename) { UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); @@ -764,8 +777,46 @@ class LinkDotFindVisitor final : public VNVisitor { modp = VN_AS(modp->nextp(), NodeModule)) { UINFO(8, "Top Module: " << modp << endl); m_scope = "TOP"; + + if (m_statep->forPrearray() && v3Global.opt.topIfacesSupported()) { + for (AstNode* subnodep = modp->stmtsp(); subnodep; subnodep = subnodep->nextp()) { + if (AstVar* const varp = VN_CAST(subnodep, Var)) { + if (varp->isIfaceRef()) { + const AstNodeDType* const subtypep = varp->subDTypep(); + const AstIfaceRefDType* ifacerefp = nullptr; + if (VN_IS(subtypep, IfaceRefDType)) { + ifacerefp = VN_AS(varp->subDTypep(), IfaceRefDType); + } + else if (VN_IS(subtypep, BracketArrayDType)) { + const AstBracketArrayDType* const arrp = VN_AS(subtypep, BracketArrayDType); + const AstNodeDType* const arrsubtypep = arrp->subDTypep(); + if (VN_IS(arrsubtypep, IfaceRefDType)) { + ifacerefp = VN_AS(arrsubtypep, IfaceRefDType); + } + } + else if (VN_IS(subtypep, UnpackArrayDType)) { + const AstUnpackArrayDType* const arrp = VN_AS(subtypep, UnpackArrayDType); + const AstNodeDType* const arrsubtypep = arrp->subDTypep(); + if (VN_IS(arrsubtypep, IfaceRefDType)) { + ifacerefp = VN_AS(arrsubtypep, IfaceRefDType); + } + } + + if (ifacerefp && !ifacerefp->cellp()) { + // A dummy cell to keep the top level interface alive and correctly optimized for default parameter values + AstCell* ifacecellp = new AstCell{nodep->fileline(), nodep->fileline(), modp->name() + "__02E" + varp->name(), ifacerefp->ifaceName(), nullptr, nullptr, nullptr}; + ifacecellp->modp(ifacerefp->ifacep()); + m_curSymp = m_modSymp = m_statep->insertTopIface(ifacecellp, m_scope); + { iterate(ifacecellp); } + } + } + } + } + } + m_curSymp = m_modSymp = m_statep->insertTopCell(modp, m_scope); { iterate(modp); } + m_scope = ""; m_curSymp = m_modSymp = nullptr; } diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index cdb9b19c8..fbc4d86bd 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -200,6 +200,35 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { ioNames.insert(oldvarp->name()); } } + else if (v3Global.opt.topIfacesSupported() && oldvarp->isIfaceRef()) { + const AstNodeDType* const subtypep = oldvarp->subDTypep(); + if (VN_IS(subtypep, IfaceRefDType)) { + const AstIfaceRefDType* const ifacerefp = VN_AS(subtypep, IfaceRefDType); + if (!ifacerefp->cellp()) { + if (ioNames.find(oldvarp->name()) != ioNames.end()) { + // UINFO(8, "Multitop dup interface found: " << oldvarp << endl); + dupNames.insert(oldvarp->name()); + } else { + ioNames.insert(oldvarp->name()); + } + } + } + if (VN_IS(subtypep, UnpackArrayDType)) { + const AstUnpackArrayDType* const arrp = VN_AS(subtypep, UnpackArrayDType); + const AstNodeDType* const arrsubtypep = arrp->subDTypep(); + if (VN_IS(arrsubtypep, IfaceRefDType)) { + const AstIfaceRefDType* const ifacerefp = VN_AS(arrsubtypep, IfaceRefDType); + if (!ifacerefp->cellp()) { + if (ioNames.find(oldvarp->name()) != ioNames.end()) { + // UINFO(8, "Multitop dup interface array found: " << oldvarp << endl); + dupNames.insert(oldvarp->name()); + } else { + ioNames.insert(oldvarp->name()); + } + } + } + } + } } } } @@ -257,6 +286,81 @@ void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { pinp->modVarp(oldvarp); cellp->addPinsp(pinp); } + else if (v3Global.opt.topIfacesSupported() && oldvarp->isIfaceRef()) { + // for each interface port on oldmodp instantiate a corresponding interface cell in $root + const AstNodeDType* const subtypep = oldvarp->subDTypep(); + if (VN_IS(subtypep, IfaceRefDType)) { + const AstIfaceRefDType* const ifacerefp = VN_AS(subtypep, IfaceRefDType); + if (!ifacerefp->cellp()) { + string name = oldvarp->name(); + if (dupNames.find(name) != dupNames.end()) { + // __02E=. while __DOT__ looks nicer but will break V3LinkDot + name = oldmodp->name() + "__02E" + name; + } + + AstCell* ifacecellp = new AstCell{newmodp->fileline(), newmodp->fileline(), name, ifacerefp->ifaceName(), nullptr, nullptr, nullptr}; + ifacecellp->modp(ifacerefp->ifacep()); + newmodp->addStmtsp(ifacecellp); + + AstIfaceRefDType* const idtypep = new AstIfaceRefDType{newmodp->fileline(), name, ifacerefp->ifaceName()}; + idtypep->ifacep(nullptr); + idtypep->dtypep(idtypep); + idtypep->cellp(ifacecellp); + rootp->typeTablep()->addTypesp(idtypep); + + AstVar* varp = new AstVar{newmodp->fileline(), VVarType::IFACEREF, name + "__Viftop", idtypep}; + varp->isIfaceParent(true); + ifacecellp->addNextHere(varp); + ifacecellp->hasIfaceVar(true); + + AstPin* const pinp = new AstPin{ + oldvarp->fileline(), 0, varp->name(), + new AstVarRef{varp->fileline(), varp, + oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ}}; + pinp->modVarp(oldvarp); + cellp->addPinsp(pinp); + } + } + else if (VN_IS(subtypep, UnpackArrayDType)) { + const AstUnpackArrayDType* const oldarrp = VN_AS(subtypep, UnpackArrayDType); + const AstNodeDType* const arrsubtypep = oldarrp->subDTypep(); + if (VN_IS(arrsubtypep, IfaceRefDType)) { + const AstIfaceRefDType* const ifacerefp = VN_AS(arrsubtypep, IfaceRefDType); + if (!ifacerefp->cellp()) { + string name = oldvarp->name(); + if (dupNames.find(name) != dupNames.end()) { + // __02E=. while __DOT__ looks nicer but will break V3LinkDot + name = oldmodp->name() + "__02E" + name; + } + + AstUnpackArrayDType* arraydtypep = VN_AS(oldvarp->dtypep(), UnpackArrayDType); + AstCell* ifacearraycellp = new AstCell{newmodp->fileline(), newmodp->fileline(), name, ifacerefp->ifaceName(), nullptr, nullptr, arraydtypep->rangep()->cloneTree(true)}; + ifacearraycellp->modp(ifacerefp->ifacep()); + newmodp->addStmtsp(ifacearraycellp); + + AstIfaceRefDType* const idtypep = new AstIfaceRefDType{newmodp->fileline(), name, ifacerefp->ifaceName()}; + idtypep->ifacep(nullptr); + idtypep->dtypep(idtypep); + idtypep->cellp(ifacearraycellp); + rootp->typeTablep()->addTypesp(idtypep); + + AstNodeArrayDType* const arrp = new AstUnpackArrayDType{newmodp->fileline(), idtypep, arraydtypep->rangep()->cloneTree(true)}; + AstVar* varp = new AstVar{newmodp->fileline(), VVarType::IFACEREF, name + "__Viftop", arrp}; + varp->isIfaceParent(true); + ifacearraycellp->addNextHere(varp); + ifacearraycellp->hasIfaceVar(true); + rootp->typeTablep()->addTypesp(arrp); + + AstPin* const pinp = new AstPin{ + oldvarp->fileline(), 0, varp->name(), + new AstVarRef{varp->fileline(), varp, + oldvarp->isWritable() ? VAccess::WRITE : VAccess::READ}}; + pinp->modVarp(oldvarp); + cellp->addPinsp(pinp); + } + } + } + } } } } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 43ade69e9..cfeb3d873 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -281,7 +281,7 @@ private: nodep->valuep()->unlinkFrBack())); } } - if (nodep->isIfaceRef() && !nodep->isIfaceParent()) { + if (nodep->isIfaceRef() && !nodep->isIfaceParent() && !v3Global.opt.topIfacesSupported()) { // Only AstIfaceRefDType's at this point correspond to ports; // haven't made additional ones for interconnect yet, so assert is simple // What breaks later is we don't have a Scope/Cell representing diff --git a/src/V3Options.h b/src/V3Options.h index 782987d46..69870a701 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -490,6 +490,7 @@ public: bool vpi() const { return m_vpi; } bool xInitialEdge() const { return m_xInitialEdge; } bool xmlOnly() const { return m_xmlOnly; } + bool topIfacesSupported() const { return lintOnly() && !hierarchical(); } int buildJobs() const { return m_buildJobs; } int convergeLimit() const { return m_convergeLimit; } diff --git a/test_regress/t/t_interface_top_bad.pl b/test_regress/t/t_interface_top_bad.pl index 07964a1b5..8eda3a219 100755 --- a/test_regress/t/t_interface_top_bad.pl +++ b/test_regress/t/t_interface_top_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -lint( +compile( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_lint_iface_array_topmodule1.pl b/test_regress/t/t_lint_iface_array_topmodule1.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule1.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_array_topmodule1.v b/test_regress/t/t_lint_iface_array_topmodule1.v new file mode 100644 index 000000000..de19c13a2 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule1.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if; + + logic valid; + logic [7:0] data ; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + +endinterface + +module t + ( + input wire clk, + my_if.slave_mp in_if [2], + my_if.master_mp out_if [2] + ); + + my_if my_i [2] (); + + always @(posedge clk) + begin + my_i[0].valid <= in_if[0].valid; + my_i[0].data <= in_if[0].data; + + my_i[1].valid <= in_if[1].valid; + my_i[1].data <= in_if[1].data; + end + + assign out_if[0].valid = my_i[0].valid; + assign out_if[0].data = my_i[0].data; + + assign out_if[1].valid = my_i[1].valid; + assign out_if[1].data = my_i[1].data; + +endmodule diff --git a/test_regress/t/t_lint_iface_array_topmodule2.pl b/test_regress/t/t_lint_iface_array_topmodule2.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule2.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_array_topmodule2.v b/test_regress/t/t_lint_iface_array_topmodule2.v new file mode 100644 index 000000000..078fb4495 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule2.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if #( + parameter DW = 8 + ) (); + + logic valid; + logic [DW-1:0] data ; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + +endinterface + +module t + ( + input wire clk, + my_if.slave_mp in_if [2], + my_if.master_mp out_if [2] + ); + + assign out_if[0].valid = in_if[0].valid; + assign out_if[0].data = in_if[0].data; + + assign out_if[1].valid = in_if[1].valid; + assign out_if[1].data = in_if[1].data; + +endmodule diff --git a/test_regress/t/t_lint_iface_array_topmodule3.pl b/test_regress/t/t_lint_iface_array_topmodule3.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule3.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_array_topmodule3.v b/test_regress/t/t_lint_iface_array_topmodule3.v new file mode 100644 index 000000000..50dae10f2 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule3.v @@ -0,0 +1,77 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if #( parameter integer DW = 8 ) (input clk); + + localparam DW_LOCAL = DW; + + logic valid; + logic [DW-1:0] data; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + + function automatic integer width(); + return $bits(data); + endfunction + + generate + if (DW < 4) + begin: dw_lt_4_G + function automatic integer min_width(); + return 4; + endfunction + end + else + begin: dw_ge_4_G + function automatic integer min_width(); + return 8; + endfunction + end + endgenerate + +endinterface + +module t + ( + input wire clk, + my_if in_if [2], + my_if out_if [2] + ); + + assign out_if[0].valid = in_if[0].valid; + assign out_if[0].data = in_if[0].data; + + assign out_if[1].valid = in_if[1].valid; + assign out_if[1].data = in_if[1].data; + + my_if my_i (.clk(clk)); + + initial + begin + $display(in_if[0].DW_LOCAL); + $display(in_if[0].width()); + $display(in_if[0].dw_ge_4_G.min_width()); + $display(out_if[0].DW_LOCAL); + $display(out_if[0].width()); + $display(out_if[0].dw_ge_4_G.min_width()); + + $display(in_if[1].DW_LOCAL); + $display(in_if[1].width()); + $display(in_if[1].dw_ge_4_G.min_width()); + $display(out_if[1].DW_LOCAL); + $display(out_if[1].width()); + $display(out_if[1].dw_ge_4_G.min_width()); + end + +endmodule diff --git a/test_regress/t/t_lint_iface_array_topmodule_bad.out b/test_regress/t/t_lint_iface_array_topmodule_bad.out new file mode 100644 index 000000000..6c0980c74 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_lint_iface_array_topmodule_bad.v:8:24: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'DW' + : ... In instance t + 8 | parameter integer DW + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_iface_array_topmodule_bad.pl b/test_regress/t/t_lint_iface_array_topmodule_bad.pl new file mode 100755 index 000000000..a82cf66cb --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_array_topmodule_bad.v b/test_regress/t/t_lint_iface_array_topmodule_bad.v new file mode 100644 index 000000000..55b060591 --- /dev/null +++ b/test_regress/t/t_lint_iface_array_topmodule_bad.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if #( + parameter integer DW + ) (); + + logic valid; + logic [7:0] data ; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + +endinterface + +module t + ( + input wire clk, + my_if.slave_mp in_if [2], + my_if.master_mp out_if [2] + ); + + my_if my_i [2] (); + + always @(posedge clk) + begin + my_i[0].valid <= in_if[0].valid; + my_i[0].data <= in_if[0].data; + + my_i[1].valid <= in_if[1].valid; + my_i[1].data <= in_if[1].data; + end + + assign out_if[0].valid = my_i[0].valid; + assign out_if[0].data = my_i[0].data; + + assign out_if[1].valid = my_i[1].valid; + assign out_if[1].data = my_i[1].data; + +endmodule diff --git a/test_regress/t/t_lint_iface_topmodule1.pl b/test_regress/t/t_lint_iface_topmodule1.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule1.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_topmodule1.v b/test_regress/t/t_lint_iface_topmodule1.v new file mode 100644 index 000000000..4c4fa5b1f --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule1.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if; + + logic valid; + logic [7:0] data ; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + +endinterface + +module t + ( + input wire clk, + my_if.slave_mp in_if, + my_if.master_mp out_if + ); + + my_if my_i (); + + always @(posedge clk) + begin + my_i.valid <= in_if.valid; + my_i.data <= in_if.data; + end + + assign out_if.valid = my_i.valid; + assign out_if.data = my_i.data; + +endmodule diff --git a/test_regress/t/t_lint_iface_topmodule2.pl b/test_regress/t/t_lint_iface_topmodule2.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule2.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_topmodule2.v b/test_regress/t/t_lint_iface_topmodule2.v new file mode 100644 index 000000000..ec836205a --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule2.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if #( + parameter integer DW = 8 + ) (); + logic valid; + logic [DW-1:0] data; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + +endinterface + +module t + ( + input wire clk, + my_if.slave_mp in_if, + my_if.master_mp out_if + ); + + assign out_if.valid = in_if.valid; + assign out_if.data = in_if.data; + +endmodule diff --git a/test_regress/t/t_lint_iface_topmodule3.pl b/test_regress/t/t_lint_iface_topmodule3.pl new file mode 100755 index 000000000..7918d5f13 --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule3.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_topmodule3.v b/test_regress/t/t_lint_iface_topmodule3.v new file mode 100644 index 000000000..a6084207b --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule3.v @@ -0,0 +1,67 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if #( parameter integer DW = 8 ) (input clk); + + localparam DW_LOCAL = DW; + + logic valid; + logic [DW-1:0] data; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + + function automatic integer width(); + return $bits(data); + endfunction + + generate + if (DW < 4) + begin: dw_lt_4_G + function automatic integer min_width(); + return 4; + endfunction + end + else + begin: dw_ge_4_G + function automatic integer min_width(); + return 8; + endfunction + end + endgenerate + +endinterface + +module t + ( + input wire clk, + my_if in_if, + my_if out_if + ); + + assign out_if.valid = in_if.valid; + assign out_if.data = in_if.data; + + my_if my_i (.clk(clk)); + + initial + begin + $display(in_if.DW_LOCAL); + $display(in_if.width()); + $display(in_if.dw_ge_4_G.min_width()); + $display(out_if.DW_LOCAL); + $display(out_if.width()); + $display(out_if.dw_ge_4_G.min_width()); + end + +endmodule diff --git a/test_regress/t/t_lint_iface_topmodule_bad.out b/test_regress/t/t_lint_iface_topmodule_bad.out new file mode 100644 index 000000000..b5263bb79 --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_lint_iface_topmodule_bad.v:8:23: Parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'DW' + : ... In instance t + 8 | parameter integer DW + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_iface_topmodule_bad.pl b/test_regress/t/t_lint_iface_topmodule_bad.pl new file mode 100755 index 000000000..a82cf66cb --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2008 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. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_iface_topmodule_bad.v b/test_regress/t/t_lint_iface_topmodule_bad.v new file mode 100644 index 000000000..04e51f7c3 --- /dev/null +++ b/test_regress/t/t_lint_iface_topmodule_bad.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2017 by Josh Redford. +// SPDX-License-Identifier: CC0-1.0 + +interface my_if #( + parameter integer DW + ) (); + + logic valid; + logic [DW-1:0] data ; + + modport slave_mp ( + input valid, + input data + ); + + modport master_mp ( + output valid, + output data + ); + +endinterface + +module t + ( + input wire clk, + my_if.slave_mp in_if, + my_if.master_mp out_if + ); + + my_if my_i (); + + always @(posedge clk) + begin + my_i.valid <= in_if.valid; + my_i.data <= in_if.data; + end + + assign out_if.valid = my_i.valid; + assign out_if.data = my_i.data; + +endmodule