diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index f3913b510..76cca1e81 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -65,6 +65,7 @@ Gijs Burghoorn Glen Gibb Gökçe Aydos Graham Rushton +Greg Davill Guokai Chen Gus Smith Gustav Svensk diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index a883caa2f..27a8457ac 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1728,11 +1728,12 @@ public: class AstPatMember final : public AstNodeExpr { // Verilog '{a} or '{a{b}} // Parents: AstPattern - // Children: expression, AstPattern, replication count + // Children: expression, AstPattern, replication count, decoded nodep if TEXT // Expression to assign or another AstPattern (list if replicated) // @astgen op1 := lhssp : List[AstNodeExpr] // @astgen op2 := keyp : Optional[AstNode] // @astgen op3 := repp : Optional[AstNodeExpr] // replication count, or nullptr for count 1 + // @astgen op4 := varrefp : Optional[AstNodeExpr] // Decoded variable if TEXT bool m_default = false; public: diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 1c6aaf93e..722bf54f8 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2744,6 +2744,24 @@ class LinkDotResolveVisitor final : public VNVisitor { m_inSens = true; iterateChildren(nodep); } + void visit(AstPatMember* nodep) override { + LINKDOT_VISIT_START(); + if (nodep->varrefp()) return; // only do this mapping once + // If we have a TEXT token as our key, lookup if it's a LPARAM + if (AstText* const textp = VN_CAST(nodep->keyp(), Text)) { + UINFO(9, indent() << "visit " << nodep << endl); + UINFO(9, indent() << " " << textp << endl); + // Lookup + if (VSymEnt* const foundp = m_curSymp->findIdFallback(textp->text())) { + if (AstVar* const varp = VN_CAST(foundp->nodep(), Var)) { + // Attach found Text reference to PatMember + nodep->varrefp(new AstVarRef{nodep->fileline(), varp, VAccess::READ}); + UINFO(9, indent() << " new " << nodep->varrefp() << endl); + } + } + } + iterateChildren(nodep); + } void visit(AstParseRef* nodep) override { if (nodep->user3SetOnce()) return; LINKDOT_VISIT_START(); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d302ac4c7..23d77fae6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -7824,8 +7824,11 @@ class WidthVisitor final : public VNVisitor { for (AstPatMember* patp = VN_AS(nodep->itemsp(), PatMember); patp; patp = VN_AS(patp->nextp(), PatMember)) { if (patp->keyp()) { + if (patp->varrefp()) V3Const::constifyParamsEdit(patp->varrefp()); if (const AstConst* const constp = VN_CAST(patp->keyp(), Const)) { element = constp->toSInt(); + } else if (const AstConst* const constp = VN_CAST(patp->varrefp(), Const)) { + element = constp->toSInt(); } else { patp->keyp()->v3error("Assignment pattern key not supported/understood: " << patp->keyp()->prettyTypeName()); diff --git a/test_regress/t/t_lparam_pattern_init.py b/test_regress/t/t_lparam_pattern_init.py new file mode 100755 index 000000000..d4f986441 --- /dev/null +++ b/test_regress/t/t_lparam_pattern_init.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_lparam_pattern_init.v b/test_regress/t/t_lparam_pattern_init.v new file mode 100644 index 000000000..8abd72fc4 --- /dev/null +++ b/test_regress/t/t_lparam_pattern_init.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2010 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module t (/*AUTOARG*/); + + localparam int unsigned SPI_INDEX = 0; + localparam int unsigned I2C_INDEX = 1; + localparam int unsigned TMR_INDEX = 4; + + localparam logic [31:0] AHB_ADDR[6] = '{ + SPI_INDEX: 32'h80001000, + I2C_INDEX: 32'h80002000, + TMR_INDEX: 32'h80003000, + default: '0}; + + initial begin + `checkh(AHB_ADDR[0], 32'h80001000); + `checkh(AHB_ADDR[1], 32'h80002000); + `checkh(AHB_ADDR[2], 32'h0); + `checkh(AHB_ADDR[3], 32'h0); + `checkh(AHB_ADDR[4], 32'h80003000); + `checkh(AHB_ADDR[5], 32'h0); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule