add struct field test

This commit is contained in:
Edmund Lam 2026-07-08 11:53:36 -04:00
parent 6de7966115
commit bb2ea625cf
2 changed files with 83 additions and 0 deletions

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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-FileCopyrightText: 2026 Wilson Snyder
# 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()

View File

@ -0,0 +1,65 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Struct localparam field access via a class-scope Dot used in a cell
// parameter pin (e.g. `CFG::cfg.jt.cam_type`), where CFG is a typedef
// alias of a parameterized class. V3LinkDot defers the `CFG::cfg` Dot
// until post-V3Param; when the cell is deparameterized, resolveDotToTypedef
// folds the class localparam to a Const and must then walk up the outer
// `.field[.field...]` Dot chain, accumulating the packed-struct bit offset,
// and replace the topmost Dot with a Sel(const, lsb, width) matching
// V3Width::memberSelStruct. Without this, the struct-field select on the
// deferred class localparam cannot be constified for the cell pin.
//
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Wilson Snyder
// SPDX-License-Identifier: CC0-1.0
// verilog_format: off
`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)
// verilog_format: on
typedef struct packed {
logic [7:0] cam_type;
logic [7:0] depth;
} inner_t;
typedef struct packed {
inner_t jt;
logic [7:0] tag;
} cfg_t;
class C #(parameter int W = 1);
// Struct localparam whose fields derive from the class parameter.
localparam cfg_t cfg = '{jt: '{cam_type: W[7:0], depth: W[7:0] + 8'd1},
tag: W[7:0] + 8'd2};
endclass
module Sub #(parameter int WIDTH = 0) ();
endmodule
// Parameterized wrapper so the class specialization is deferred until
// V3Param processes the cell instance.
module Mid #(parameter int W = 8) ();
typedef C#(W) CFG;
// (1) single-level struct field access -> one loop iteration
Sub #(int'(CFG::cfg.tag)) u_tag ();
// (2) nested struct field access -> two loop iterations, lsb accumulation
Sub #(int'(CFG::cfg.jt.cam_type)) u_cam ();
Sub #(int'(CFG::cfg.jt.depth)) u_depth ();
endmodule
module t;
Mid #(.W(8)) u ();
initial begin
// cfg.tag = W + 2 = 10 (offset above the 16-bit jt struct)
`checkh(u.u_tag.WIDTH, 32'd10);
// cfg.jt.cam_type = W = 8 (nested, lsb 0)
`checkh(u.u_cam.WIDTH, 32'd8);
// cfg.jt.depth = W + 1 = 9 (nested, lsb 8)
`checkh(u.u_depth.WIDTH, 32'd9);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule