From 04eabc62feaf7fd502cb09e31de819cf877547e7 Mon Sep 17 00:00:00 2001 From: Edmund Lam Date: Tue, 9 Jun 2026 13:07:17 -0400 Subject: [PATCH] descend into dots in typedefs --- test_regress/t/t_class_lparam_iface_chain.v | 4 +- test_regress/t/t_class_lparam_typedef_chain.v | 43 ++++++++++++++++++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/test_regress/t/t_class_lparam_iface_chain.v b/test_regress/t/t_class_lparam_iface_chain.v index 39444fbf5..5395f3bf9 100644 --- a/test_regress/t/t_class_lparam_iface_chain.v +++ b/test_regress/t/t_class_lparam_iface_chain.v @@ -21,7 +21,7 @@ interface SubIface #( logic [IW-1:0] data; endinterface -// Module that takes an interface port — must elaborate after the iface +// Module that takes an interface port - must elaborate after the iface // cell pin is fully constified. module Consumer ( SubIface si @@ -50,7 +50,7 @@ module t; SubIface #(b8_alias) i_chain (); // Iface pin = expression mixing deferred lparams SubIface #(b8 + b13) i_expr (); - // Iface used as a module port — exercises the iface-cell-first path + // Iface used as a module port - exercises the iface-cell-first path Consumer cons (.si(i_bare)); initial begin diff --git a/test_regress/t/t_class_lparam_typedef_chain.v b/test_regress/t/t_class_lparam_typedef_chain.v index c8ec879f8..aa4039514 100644 --- a/test_regress/t/t_class_lparam_typedef_chain.v +++ b/test_regress/t/t_class_lparam_typedef_chain.v @@ -2,10 +2,13 @@ // // Typedefs and class type parameters that resolve through a // class-scope-resolved localparam (typedef alias of a parameterized -// class, e.g. inst::b). Exercises three sub-cases: +// class, e.g. inst::b). Exercises four sub-cases: // - Deferred lparam used as a packed range bound in a typedef // - Deferred lparam used as a value argument to a parameterized class // - Class-scope-resolved typedef that itself depends on the param +// - Class-scope Dot used DIRECTLY (no intermediate lparam) in a typedef +// range inside a parameterized module, consumed by `$bits` on a child +// cell pin // // This file ONLY is placed under the Creative Commons Public Domain. // SPDX-FileCopyrightText: 2026 Wilson Snyder @@ -16,13 +19,44 @@ `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) // verilog_format: on +// Sink for sub-case (4): the BITS pin consumes $bits of a typedef whose +// packed range uses class-scope Dots. V3Param must descend into the typedef's +// subDType and resolve those Dots, otherwise V3Width emits "dotted expressions +// in parameters". +module Sink #( + parameter int BITS = 1 +) (); + logic [BITS-1:0] data; +endmodule + +// Parameterized wrapper so the class specialization is deferred until V3Param +// processes the cell instance. +module Sub #( + parameter int W = 8 +) (); + // Inner class — same shape as `t`'s C, repeated here to keep sub-case (4) + // self-contained inside Sub. + virtual class CInner #( + parameter int a + ); + localparam int b = a; + endclass + + typedef CInner#(W) CFG; + + // (4) typedef packed range uses class-scope Dots directly + typedef logic [(CFG::b + CFG::b - 1):0] dot_range_t; + + Sink #(.BITS($bits(dot_range_t))) u_sink (); +endmodule + module t; virtual class C #( parameter int a ); localparam int b = a; typedef logic [a-1:0] inner_t; - // localparam derived from a typedef inside the same class — + // localparam derived from a typedef inside the same class - // resolveDotToTypedef must constify this when reached via CFG::width. localparam int width = $bits(inner_t); endclass @@ -46,6 +80,9 @@ module t; // Wire whose range comes from a deferred lparam logic [b8-1:0] wide_bus; + // (4) parameterized wrapper with a typedef range using class Dots directly + Sub #(.W(8)) u_sub (); + initial begin `checkh(b8, 32'd8); `checkh(from_def_b, 32'd8); @@ -54,6 +91,8 @@ module t; `checkh(data_value, 8'hff); wide_bus = '1; `checkh(wide_bus, 8'hff); + // sub-case (4): $bits(dot_range_t) = CFG::b + CFG::b = 8 + 8 = 16 + `checkh($bits(u_sub.u_sink.data), 32'd16); $write("*-* All Finished *-*\n"); $finish; end