From b6a400ee9b6b0966d04696787f649cfe3974153c Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Jan 2025 17:10:04 -0500 Subject: [PATCH] Support generated classes (#5665). --- Changes | 1 + src/V3Begin.cpp | 12 +++++++ test_regress/t/t_EXAMPLE.v | 3 +- test_regress/t/t_gen_class.py | 18 ++++++++++ test_regress/t/t_gen_class.v | 67 +++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_gen_class.py create mode 100644 test_regress/t/t_gen_class.v diff --git a/Changes b/Changes index fc1016325..aac6d50ff 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.033 devel **Minor:** +* Support generated classes (#5665). [Shou-Li Hsu] * Fix error message when call task as a function (#3089). [Matthew Ballance] * Fix V3Simulate constant reuse (#5709). [Geza Lore] * Fix man pages what-is section (#5710). [Ahmed El-Mahmoudy] diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 4817bd0f1..f07de3594 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -148,6 +148,18 @@ class BeginVisitor final : public VNVisitor { void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); m_modp = nodep; + // Rename it (e.g. class under a generate) + if (m_unnamedScope != "") { + nodep->name(dot(m_unnamedScope, nodep->name())); + UINFO(8, " rename to " << nodep->name() << endl); + m_statep->userMarkChanged(nodep); + } + VL_RESTORER(m_displayScope); + VL_RESTORER(m_namedScope); + VL_RESTORER(m_unnamedScope); + m_displayScope = ""; + m_namedScope = ""; + m_unnamedScope = ""; iterateChildren(nodep); } void visit(AstNodeFTask* nodep) override { diff --git a/test_regress/t/t_EXAMPLE.v b/test_regress/t/t_EXAMPLE.v index 3dcd65512..b00361778 100644 --- a/test_regress/t/t_EXAMPLE.v +++ b/test_regress/t/t_EXAMPLE.v @@ -17,7 +17,8 @@ // SPDX-License-Identifier: CC0-1.0 `define stop $stop -`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); module t(/*AUTOARG*/ // Inputs diff --git a/test_regress/t/t_gen_class.py b/test_regress/t/t_gen_class.py new file mode 100755 index 000000000..bd059b0f2 --- /dev/null +++ b/test_regress/t/t_gen_class.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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(verilator_flags2=['--binary']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_gen_class.v b/test_regress/t/t_gen_class.v new file mode 100644 index 000000000..58628ba58 --- /dev/null +++ b/test_regress/t/t_gen_class.v @@ -0,0 +1,67 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 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=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +module Child; + int ch_value; +endmodule + +module Parent; + for (genvar i = 0; i < 10; i++) begin : gen_child + Child child(); + end +endmodule + +module t; + Parent parent(); + + virtual class ChildAgentBase; + pure virtual task preload(int value); + pure virtual function string name(); + endclass + + ChildAgentBase child_agents[10]; + + for (genvar i = 0; i < 10; i++) begin : gfor + class ChildAgent extends ChildAgentBase; + task automatic preload(int value); + parent.gen_child[i].child.ch_value = value; + endtask + function string name(); + return $sformatf("%m"); + endfunction + endclass + + ChildAgent agent = new(); + + initial child_agents[i] = agent; + end + + task automatic preload_children; + for (int i = 0; i < 10; i++) begin + child_agents[i].preload(i); + end + endtask + + string s; + + initial begin + #1; // Ensure all class instances are initialized + preload_children(); + `checkh(parent.gen_child[3].child.ch_value, 3); + `checkh(parent.gen_child[8].child.ch_value, 8); +`ifdef VERILATOR + // Some legal examples "t.gfor[4].\ChildAgent::name", "t.gfor[4].ChildAgent.name" + `checks(child_agents[4].name(), "t.gfor[4].ChildAgent.name"); +`endif + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule