descend into dots in typedefs
This commit is contained in:
parent
f18aaeea83
commit
04eabc62fe
|
|
@ -21,7 +21,7 @@ interface SubIface #(
|
||||||
logic [IW-1:0] data;
|
logic [IW-1:0] data;
|
||||||
endinterface
|
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.
|
// cell pin is fully constified.
|
||||||
module Consumer (
|
module Consumer (
|
||||||
SubIface si
|
SubIface si
|
||||||
|
|
@ -50,7 +50,7 @@ module t;
|
||||||
SubIface #(b8_alias) i_chain ();
|
SubIface #(b8_alias) i_chain ();
|
||||||
// Iface pin = expression mixing deferred lparams
|
// Iface pin = expression mixing deferred lparams
|
||||||
SubIface #(b8 + b13) i_expr ();
|
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));
|
Consumer cons (.si(i_bare));
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@
|
||||||
//
|
//
|
||||||
// Typedefs and class type parameters that resolve through a
|
// Typedefs and class type parameters that resolve through a
|
||||||
// class-scope-resolved localparam (typedef alias of a parameterized
|
// 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 packed range bound in a typedef
|
||||||
// - Deferred lparam used as a value argument to a parameterized class
|
// - Deferred lparam used as a value argument to a parameterized class
|
||||||
// - Class-scope-resolved typedef that itself depends on the param
|
// - 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.
|
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
// 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)
|
`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
|
// 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;
|
module t;
|
||||||
virtual class C #(
|
virtual class C #(
|
||||||
parameter int a
|
parameter int a
|
||||||
);
|
);
|
||||||
localparam int b = a;
|
localparam int b = a;
|
||||||
typedef logic [a-1:0] inner_t;
|
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.
|
// resolveDotToTypedef must constify this when reached via CFG::width.
|
||||||
localparam int width = $bits(inner_t);
|
localparam int width = $bits(inner_t);
|
||||||
endclass
|
endclass
|
||||||
|
|
@ -46,6 +80,9 @@ module t;
|
||||||
// Wire whose range comes from a deferred lparam
|
// Wire whose range comes from a deferred lparam
|
||||||
logic [b8-1:0] wide_bus;
|
logic [b8-1:0] wide_bus;
|
||||||
|
|
||||||
|
// (4) parameterized wrapper with a typedef range using class Dots directly
|
||||||
|
Sub #(.W(8)) u_sub ();
|
||||||
|
|
||||||
initial begin
|
initial begin
|
||||||
`checkh(b8, 32'd8);
|
`checkh(b8, 32'd8);
|
||||||
`checkh(from_def_b, 32'd8);
|
`checkh(from_def_b, 32'd8);
|
||||||
|
|
@ -54,6 +91,8 @@ module t;
|
||||||
`checkh(data_value, 8'hff);
|
`checkh(data_value, 8'hff);
|
||||||
wide_bus = '1;
|
wide_bus = '1;
|
||||||
`checkh(wide_bus, 8'hff);
|
`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");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue