From 530817191e88adbafe5152e85621abedd136399a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 25 May 2022 00:50:50 -0400 Subject: [PATCH] Support non-ANSI interface port declarations (#3439). --- Changes | 1 + src/V3LinkDot.cpp | 6 ++-- src/verilog.y | 44 ++++++++++++++++++++--------- test_regress/t/t_interface_nansi.pl | 21 ++++++++++++++ test_regress/t/t_interface_nansi.v | 37 ++++++++++++++++++++++++ 5 files changed, 92 insertions(+), 17 deletions(-) create mode 100755 test_regress/t/t_interface_nansi.pl create mode 100644 test_regress/t/t_interface_nansi.v diff --git a/Changes b/Changes index 390606387..d6067565d 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 4.223 devel * Support compile time trace signal selection with tracing_on/off (#3323). [Shunyao CAD] * Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick] * Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD] +* Support non-ANSI interface port declarations (#3439). [Geza Lore, Shunyao CAD] * Fix hang with large case statement optimization (#3405). [Mike Urbach] * Fix 'with' operator with type casting (#3387). [xiak95] * Fix incorrect conditional merging (#3409). [Raynard Qiao] diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 22f4d97ca..63a4eb301 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1478,11 +1478,11 @@ private: // Need to set pin numbers after varnames are created // But before we do the final resolution based on names VSymEnt* const foundp = m_statep->getNodeSym(m_modp)->findIdFlat(nodep->name()); - AstVar* const refp = foundp ? VN_AS(foundp->nodep(), Var) : nullptr; - if (!refp) { + AstVar* const refp = foundp ? VN_CAST(foundp->nodep(), Var) : nullptr; + if (!foundp) { nodep->v3error( "Input/output/inout declaration not found for port: " << nodep->prettyNameQ()); - } else if (!refp->isIO() && !refp->isIfaceRef()) { + } else if (!refp || (!refp->isIO() && !refp->isIfaceRef())) { nodep->v3error("Pin is not an in/out/inout/interface: " << nodep->prettyNameQ()); } else { if (refp->user4()) { diff --git a/src/verilog.y b/src/verilog.y index a31704545..af2b427d3 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -104,6 +104,27 @@ public: string newtext = deQuote(fileline, text); return new AstText(fileline, newtext); } + AstNode* createCellOrIfaceRef(FileLine* fileline, const string& name, AstPin* pinlistp, AstNodeRange* rangelistp) { + // Must clone m_instParamp as may be comma'ed list of instances + VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(name); + if (foundp && VN_IS(foundp->nodep(), Port)) { + // It's a non-ANSI interface, not a cell declaration + m_varAttrp = nullptr; + m_varDecl = VVarType::IFACEREF; + m_varIO = VDirection::NONE; + m_varLifetime = VLifetime::NONE; + setDType(new AstIfaceRefDType{fileline, "", GRAMMARP->m_instModule}); + m_varDeclTyped = true; + AstVar* const nodep = createVariable(fileline, name, rangelistp, nullptr); + return nodep; + } + AstCell* const nodep = new AstCell{fileline, GRAMMARP->m_instModuleFl, + name, GRAMMARP->m_instModule, pinlistp, + AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), + GRAMMARP->scrubRange(rangelistp)}; + nodep->trace(GRAMMARP->allTracingOn(fileline)); + return nodep; + } AstDisplay* createDisplayError(FileLine* fileline) { AstDisplay* nodep = new AstDisplay(fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr); nodep->addNext(new AstStop(fileline, true)); @@ -1418,8 +1439,10 @@ port_declNetE: // IEEE: part of port_declaration, optional net ; portSig: - id/*port*/ { $$ = new AstPort($1,PINNUMINC(),*$1); } - | idSVKwd { $$ = new AstPort($1,PINNUMINC(),*$1); } + id/*port*/ + { $$ = new AstPort{$1, PINNUMINC(), *$1}; SYMP->reinsert($$); } + | idSVKwd + { $$ = new AstPort{$1, PINNUMINC(), *$1}; SYMP->reinsert($$); } ; //********************************************************************** @@ -2869,18 +2892,11 @@ instnameList: | instnameList ',' instnameParen { $$ = $1->addNext($3); } ; -instnameParen: - // // Must clone m_instParamp as may be comma'ed list of instances - id instRangeListE '(' cellpinList ')' { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, - *$1, GRAMMARP->m_instModule, $4, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), - GRAMMARP->scrubRange($2)); - $$->trace(GRAMMARP->allTracingOn($1)); } - | id instRangeListE { $$ = new AstCell($1, GRAMMARP->m_instModuleFl, - *$1, GRAMMARP->m_instModule, nullptr, - AstPin::cloneTreeNull(GRAMMARP->m_instParamp, true), - GRAMMARP->scrubRange($2)); - $$->trace(GRAMMARP->allTracingOn($1)); } +instnameParen: + id instRangeListE '(' cellpinList ')' + { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, $4, $2); } + | id instRangeListE + { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, nullptr, $2); } //UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP // // Adding above and switching to the Verilog-Perl syntax // // causes a shift conflict due to use of idClassSel inside exprScope. diff --git a/test_regress/t/t_interface_nansi.pl b/test_regress/t/t_interface_nansi.pl new file mode 100755 index 000000000..f60fd309f --- /dev/null +++ b/test_regress/t/t_interface_nansi.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_nansi.v b/test_regress/t/t_interface_nansi.v new file mode 100644 index 000000000..ef9d2d418 --- /dev/null +++ b/test_regress/t/t_interface_nansi.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +interface iface(input logic clk); + logic [31:0] d = 0; + logic [31:0] q = 0; +endinterface + +module mod(a); + iface a; // This is not a CELL, it is a port declaration + always @(posedge a.clk) a.q <= a.d; +endmodule + +module t(clk); + input clk; + + iface iface_inst(clk); + mod mod_inst(iface_inst); + + int cyc = 0; + + always @(posedge clk) begin + iface_inst.d <= cyc; + if (cyc > 1 && iface_inst.q != cyc - 2) $stop; + end + + always @(posedge clk) begin + cyc <= cyc + 1; + if (cyc == 100) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule