Fix interface derived types passed as parameters to generate loop module instantiation (#7273)

This commit is contained in:
em2machine 2026-03-18 09:26:55 -04:00 committed by GitHub
parent 4b34bfffcb
commit a2154e9119
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 580 additions and 57 deletions

View File

@ -853,7 +853,8 @@ class ParamProcessor final {
// Phase A: path-based fixup using ledger entries
std::set<AstRefDType*> ledgerFixed;
{
const string cloneCP = VN_CAST(ifErrorp, Cell) ? VN_AS(ifErrorp, Cell)->name() : "";
// Must match the cloneCellPath used by propagateClone (newname).
const string cloneCP = newModp->name();
const string srcName = srcModp->name();
UINFO(9, "iface capture FIXUP-A: srcName=" << srcName << " cloneCP='" << cloneCP << "'"
<< endl);
@ -991,7 +992,8 @@ class ParamProcessor final {
}
// Register clone entry in ledger (no AST mutation).
if (AstRefDType* const clonedRefp = entry.refp->clonep()) {
const string cloneCP = cloneCellp ? cloneCellp->name() : string{};
// Use newname (unique specialized module name) as cloneCellPath.
const string cloneCP = newname;
const V3LinkDotIfaceCapture::TemplateKey tkey{
entry.ownerModp ? entry.ownerModp->name() : "", entry.refp->name(),
entry.cellPath};
@ -1791,10 +1793,13 @@ public:
V3LinkDotIfaceCapture::forEach([&](const V3LinkDotIfaceCapture::CapturedEntry& entry) {
if (!entry.refp || entry.cloneCellPath.empty()) return;
if (entry.cellPath != cellName) return;
// Identity check: only retarget REFDTYPEs that actually live
// inside parentModp. Multiple clones share origName so name
// matching alone would let one clone overwrite another's refs.
if (V3LinkDotIfaceCapture::findOwnerModule(entry.refp) != parentModp) return;
AstNodeModule* const ownerp = V3LinkDotIfaceCapture::findOwnerModule(entry.refp);
// Only retarget REFDTYPEs owned by parentModp.
// Null owner (type-table dtypes) falls back to cloneCellPath match.
if (ownerp != parentModp
&& !(ownerp == nullptr && entry.cloneCellPath == parentModp->name())) {
return;
}
if (retargetRefToModule(entry, correctModp)) {
UINFO(9, "retargetIfaceRefs: " << entry.refp << " -> "
<< correctModp->prettyNameQ() << endl);
@ -2102,6 +2107,12 @@ class ParamVisitor final : public VNVisitor {
// Add to the hierarchy registry
m_state.m_parentps[newModp].insert(modp);
// Eagerly specialize nested iface cells so their types
// have correct widths before sibling module cells run.
if (VN_IS(newModp, Iface) && newModp != srcModp) {
specializeNestedIfaceCells(newModp);
}
}
}
}
@ -2227,6 +2238,36 @@ class ParamVisitor final : public VNVisitor {
});
}
// Deparameterize and constify nested interface cells within ifaceModp.
void specializeNestedIfaceCells(AstNodeModule* ifaceModp) {
for (AstNode* stmtp = ifaceModp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
AstCell* const nestedCellp = VN_CAST(stmtp, Cell);
if (!nestedCellp) continue;
if (!VN_IS(nestedCellp->modp(), Iface)) continue;
if (!nestedCellp->paramsp()) continue;
AstNodeModule* const nestedSrcModp = nestedCellp->modp();
if (AstNodeModule* const nestedNewModp = m_processor.nodeDeparam(
nestedCellp, nestedSrcModp, ifaceModp, ifaceModp->someInstanceName())) {
if (nestedNewModp != nestedSrcModp) {
// Constify the nested clone's params so its types have correct widths.
for (AstNode* sp = nestedNewModp->stmtsp(); sp; sp = sp->nextp()) {
if (AstVar* const varp = VN_CAST(sp, Var)) {
if (varp->isParam() && varp->valuep()) {
V3Const::constifyParamsEdit(varp);
}
}
}
// Retarget REFDTYPEs in the outer clone to the nested clone's types.
if (V3LinkDotIfaceCapture::enabled()) {
m_processor.retargetIfaceRefs(ifaceModp, nestedCellp->name());
}
specializeNestedIfaceCells(nestedNewModp);
}
}
}
}
// Check if cell parameters reference interface ports or local interface instances
bool cellParamsReferenceIfacePorts(AstCell* cellp) {
if (!cellp->paramsp()) return false;
@ -2247,51 +2288,25 @@ class ParamVisitor final : public VNVisitor {
return false;
}
// Recursively specialize nested interface cells within a specialized interface.
// This handles parameter passthrough for nested interface hierarchies.
void specializeNestedIfaceCells(AstNodeModule* ifaceModp) {
for (AstNode* stmtp = ifaceModp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
AstCell* const nestedCellp = VN_CAST(stmtp, Cell);
if (!nestedCellp) continue;
if (!VN_IS(nestedCellp->modp(), Iface)) continue;
if (!nestedCellp->paramsp()) continue;
if (cellParamsReferenceIfacePorts(nestedCellp)) continue;
AstNodeModule* const nestedSrcModp = nestedCellp->modp();
if (AstNodeModule* const nestedNewModp = m_processor.nodeDeparam(
nestedCellp, nestedSrcModp, ifaceModp, ifaceModp->someInstanceName())) {
// Recursively process nested interfaces within this nested interface
if (nestedNewModp != nestedSrcModp) specializeNestedIfaceCells(nestedNewModp);
}
}
}
// A generic visitor for cells and class refs
void visitCellOrClassRef(AstNode* nodep, bool isIface) {
// Must do ifaces first, so push to list and do in proper order
m_strings.emplace_back(m_generateHierName);
nodep->user2p(&m_strings.back());
// For interface cells with parameters, specialize first before processing children
// Only do early specialization if parameters don't reference interface ports
// Deparameterize iface cells early so types are available for lparams.
if (isIface && VN_CAST(nodep, Cell) && VN_CAST(nodep, Cell)->paramsp()) {
AstCell* const cellp = VN_CAST(nodep, Cell);
if (!cellParamsReferenceIfacePorts(cellp)) {
AstNodeModule* const srcModp = cellp->modp();
// DISABLED: specializeNestedIfaceCells causes early nested
// iface specialization where PARAMTYPEDTYPE child REFDTYPEs
// point to template structs instead of clone structs,
// destructively widthing the template with default (zero)
// values. See t_interface_nested_struct_param.v.
m_processor.nodeDeparam(cellp, srcModp, m_modp, m_modp->someInstanceName());
// After the interface cell is rewired to its clone,
// retarget REFDTYPEs in the parent module that still
// reference the template interface's types. This ensures
// $bits(iface_typedef) evaluates correctly when
// widthParamsEdit runs on subsequent lparams.
AstNodeModule* const newModp
= m_processor.nodeDeparam(cellp, srcModp, m_modp, m_modp->someInstanceName());
// Retarget template REFDTYPEs to the clone's types.
if (V3LinkDotIfaceCapture::enabled() && cellp->modp() != srcModp) {
m_processor.retargetIfaceRefs(m_modp, cellp->name());
}
// Specialize nested iface cells so their types are correct.
if (newModp && newModp != srcModp) { specializeNestedIfaceCells(newModp); }
}
}

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,275 @@
// 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
//
// Test: nested parameterized interface inside a types interface causes
// $bits() to evaluate with wrong struct width.
//
package cfg3_pkg;
typedef struct packed {
int unsigned Capacity;
int unsigned Slices;
int unsigned NumThreads;
int unsigned NumIds;
} cfg_t;
endpackage
// Inner types interface (mirrors xyz_types_if).
// Provides types derived from cfg that the outer interface imports.
interface inner_types_if #(
parameter cfg3_pkg::cfg_t cfg = '0
) ();
typedef logic [$clog2(cfg.NumIds)-1:0] trans_id_t;
typedef logic [$clog2(cfg.NumThreads)-1:0] tl_index_t;
endinterface
// Outer types interface (mirrors smem_types_if).
// Instantiates inner_types_if, imports types from it, and builds
// compound struct typedefs that include those imported types.
interface outer_types_if #(
parameter cfg3_pkg::cfg_t cfg = '0
) ();
localparam int NUM_ROWS = (cfg.Capacity / cfg.Slices) / 8;
typedef logic [$clog2(NUM_ROWS)-1:0] row_addr_t;
// Nested interface - this is the trigger.
inner_types_if #(cfg) inner_types();
typedef inner_types.trans_id_t trans_id_t;
typedef inner_types.tl_index_t tl_index_t;
typedef logic [$clog2(cfg.NumThreads)-1:0] pkt_nid_t;
typedef struct packed {
pkt_nid_t src_nid;
pkt_nid_t dst_nid;
} pkt_hdr_t;
typedef union packed {
logic [$bits(row_addr_t)+$bits(tl_index_t)+6-1:0] raw;
struct packed {
row_addr_t row_index;
tl_index_t tl_index;
logic [5:0] bit_index;
} fld;
} addr_t;
typedef struct packed {
logic en;
trans_id_t tag;
tl_index_t tl;
logic is_read;
logic needs_resp;
} meta_t;
typedef struct packed {
meta_t meta;
addr_t addr;
logic [63:0] data;
} rq_t;
// Compound packet type (mirrors iq_pkt_t)
typedef struct packed {
pkt_hdr_t hdr;
rq_t payload;
} pkt_t;
endinterface
// Width-parameterized FIFO (mirrors ring_fifo).
module fifo3 #(
parameter int p_width = 1,
parameter int p_depth = 2
) (
input logic clk,
input logic rst_n,
input logic [p_width-1:0] push_dat_i,
input logic push_vld_i,
output logic [p_width-1:0] front_dat_o,
output logic not_empty_o
);
logic [p_width-1:0] mem [p_depth];
logic [$clog2(p_depth)-1:0] wptr, rptr;
logic [p_depth:0] count;
assign not_empty_o = (count != 0);
assign front_dat_o = mem[rptr];
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
wptr <= '0;
rptr <= '0;
count <= '0;
end else if (push_vld_i) begin
mem[wptr] <= push_dat_i;
wptr <= wptr + 1;
count <= count + 1;
end
end
endmodule
// Slice module (mirrors smem_slice).
// Receives iq_pkt_t as a TYPE PARAMETER from wrapper3, then uses
// $bits(iq_pkt_t) as a value parameter to fifo3.
// This forces $bits() evaluation during widthParamsEdit of the slice3
// cell (in wrapper3's cell loop), before outer_types_if__Az1's nested
// inner_types_if is deparameterized.
module slice3 #(
parameter cfg3_pkg::cfg_t cfg = '0,
parameter int SLICE_IDX = 0,
parameter type iq_pkt_t = logic,
parameter type oq_pkt_t = logic
) (
input logic clk,
input logic rst_n,
input logic in_vld,
output logic out_vld,
output iq_pkt_t fe_ot_pkt_o
);
// Local outer_types_if for other local types
outer_types_if #(cfg) types();
typedef types.pkt_nid_t pkt_nid_t;
iq_pkt_t rqq_in, rqq_ot;
logic rqq_ot_vld;
assign rqq_in.hdr.src_nid = pkt_nid_t'(SLICE_IDX);
assign rqq_in.hdr.dst_nid = '0;
assign rqq_in.payload.meta.en = in_vld;
assign rqq_in.payload.meta.tag = '0;
assign rqq_in.payload.meta.tl = '0;
assign rqq_in.payload.meta.is_read = 1'b1;
assign rqq_in.payload.meta.needs_resp = 1'b0;
assign rqq_in.payload.addr = '0;
assign rqq_in.payload.data = 64'hCAFE_BABE;
// $bits(iq_pkt_t) as value parameter - the bug trigger.
// iq_pkt_t is a type parameter whose PARAMTYPEDTYPE child REFDTYPE
// points into the outer_types_if clone's STRUCTDTYPE. When
// widthParamsEdit evaluates this during wrapper3's cell loop,
// the nested inner_types_if inside outer_types_if__Az1 hasn't
// been deparameterized, so trans_id_t/tl_index_t have wrong widths.
fifo3 #(
.p_width($bits(iq_pkt_t)),
.p_depth(4)
) rqq (
.clk(clk),
.rst_n(rst_n),
.push_dat_i(rqq_in),
.push_vld_i(in_vld),
.front_dat_o(rqq_ot),
.not_empty_o(rqq_ot_vld)
);
assign fe_ot_pkt_o = rqq_ot;
assign out_vld = rqq_ot_vld;
endmodule
// Wrapper module (mirrors smem_top).
// Creates outer_types_if, imports pkt_t, and passes it as a type
// parameter to slice3 instances in a generate loop.
module wrapper3 #(
parameter cfg3_pkg::cfg_t cfg = '0
) (
input logic clk,
input logic rst_n
);
outer_types_if #(cfg) types();
typedef types.pkt_t iq_pkt_t;
typedef types.rq_t oq_pkt_t;
// Capture $bits of the type parameter for external checking.
// If the nested inner_types_if hasn't been deparameterized before
// this is evaluated, the width will be wrong (e.g. 90 instead of 92).
localparam int PKT_WIDTH = $bits(iq_pkt_t);
logic [cfg.NumThreads-1:0] out_vld;
generate
for (genvar i = 0; i < cfg.NumThreads; i++) begin : gen_slices
iq_pkt_t fe_pkt;
slice3 #(
.cfg(cfg),
.SLICE_IDX(i),
.iq_pkt_t(iq_pkt_t),
.oq_pkt_t(oq_pkt_t)
) u_slice (
.clk(clk),
.rst_n(rst_n),
.in_vld(1'b1),
.out_vld(out_vld[i]),
.fe_ot_pkt_o(fe_pkt)
);
end
endgenerate
endmodule
module t;
logic clk = 0;
always #5 clk = ~clk;
logic rst_n = 0;
int cyc = 0;
localparam cfg3_pkg::cfg_t MY_CFG = '{
Capacity: 8192,
Slices: 8,
NumThreads: 4,
NumIds: 16
};
// Expected widths:
// trans_id_t = $clog2(16) = 4 bits
// tl_index_t = $clog2(4) = 2 bits
// row_addr_t = $clog2((8192/8)/8) = $clog2(128) = 7 bits
// pkt_nid_t = $clog2(4) = 2 bits
// pkt_hdr_t = 2+2 = 4 bits
// addr_t = 7+2+6 = 15 bits
// meta_t = 1+4+2+1+1 = 9 bits
// rq_t = 9+15+64 = 88 bits
// pkt_t = 4+88 = 92 bits
// Compute expected pkt_t width from first principles.
// These computations happen in the testbench module context where
// the cfg parameter values are known constants, not through the
// nested interface PARAMTYPEDTYPE chain.
localparam int EXP_TRANS_ID_W = $clog2(MY_CFG.NumIds); // 4
localparam int EXP_TL_INDEX_W = $clog2(MY_CFG.NumThreads); // 2
localparam int EXP_ROW_ADDR_W = $clog2((MY_CFG.Capacity / MY_CFG.Slices) / 8); // 7
localparam int EXP_PKT_NID_W = $clog2(MY_CFG.NumThreads); // 2
localparam int EXP_PKT_HDR_W = 2 * EXP_PKT_NID_W; // 4
localparam int EXP_ADDR_W = EXP_ROW_ADDR_W + EXP_TL_INDEX_W + 6; // 15
localparam int EXP_META_W = 1 + EXP_TRANS_ID_W + EXP_TL_INDEX_W + 1 + 1; // 9
localparam int EXP_RQ_W = EXP_META_W + EXP_ADDR_W + 64; // 88
localparam int EXP_PKT_W = EXP_PKT_HDR_W + EXP_RQ_W; // 92
wrapper3 #(.cfg(MY_CFG)) u_wrapper (
.clk(clk),
.rst_n(rst_n)
);
// Self-check: verify that $bits(pkt_t) as seen through the nested
// interface type parameter chain matches the expected width.
// If the bug is present, u_wrapper.PKT_WIDTH will be < EXP_PKT_W
// because trans_id_t was evaluated with the template default
// cfg.NumIds=0 instead of the actual value 16.
initial begin
if (u_wrapper.PKT_WIDTH != EXP_PKT_W) begin
$display("%%Error: t_iface_nested_width3.v: $bits(pkt_t) = %0d, expected %0d", u_wrapper.PKT_WIDTH, EXP_PKT_W);
$stop;
end
end
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 2) rst_n <= 1;
if (cyc > 5) begin
if (u_wrapper.out_vld !== {MY_CFG.NumThreads{1'b1}}) begin
$display("FAIL cyc=%0d: out_vld=%b", cyc, u_wrapper.out_vld);
$stop;
end
end
if (cyc == 20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

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,203 @@
// 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
//
// Test: struct typedef from parameterized interface with derived
// localparam used as type parameter to a sub-module cell.
//
package cfg_pkg;
typedef struct packed {
int unsigned Capacity;
int unsigned Slices;
int unsigned NumThreads;
} cfg_t;
endpackage
// Types interface: derives localparam from cfg, uses in typedef range,
// builds union/struct containing that typedef.
// On the template default (cfg='0), Capacity/Slices = 0/0 = X.
interface types_if #(
parameter cfg_pkg::cfg_t cfg = '0
) ();
localparam int NUM_ROWS = (cfg.Capacity / cfg.Slices) / 8;
typedef logic [$clog2(NUM_ROWS)-1:0] row_addr_t;
typedef logic [$clog2(cfg.NumThreads)-1:0] tl_addr_t;
typedef union packed {
logic [$bits(row_addr_t)+$bits(tl_addr_t)+6-1:0] raw;
struct packed {
row_addr_t row_index;
tl_addr_t tl_index;
logic [5:0] bit_index;
} fld;
} addr_t;
typedef struct packed {
logic en;
logic [3:0] tag;
logic is_read;
} meta_t;
// Compound packet type (mirrors iq_pkt_t)
typedef struct packed {
meta_t meta;
addr_t addr;
logic [63:0] data;
} pkt_t;
endinterface
// Generic type-parameterized register (mirrors tflop_nr)
module tflop_nr #(parameter type T = logic) (
input logic clk,
input logic rst_n,
output T q_o,
input T d_i
);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) q_o <= '0;
else q_o <= d_i;
end
endmodule
// Slice module: receives pkt_t as type param from wrapper, also
// instantiates types_if locally, builds local struct from local types,
// passes that struct as type param to tflop_nr.
// (mirrors smem_slice)
module slice #(
parameter cfg_pkg::cfg_t cfg = '0,
parameter int SLICE_IDX = 0,
parameter type pkt_t = logic
) (
input logic clk,
input logic rst_n,
input logic in_vld,
input pkt_t in_pkt,
output logic out_vld,
output pkt_t out_pkt
);
// Local types_if instantiation - same cfg as wrapper's
types_if #(cfg) types();
typedef types.addr_t addr_t;
typedef types.meta_t meta_t;
// Local struct containing locally-imported interface types
typedef struct packed {
meta_t meta;
addr_t addr;
} rq_t;
rq_t rq_d, rq_q;
always_comb begin
rq_d = rq_q;
if (in_vld) begin
rq_d.meta = in_pkt.meta;
rq_d.addr = in_pkt.addr;
end
end
// Pass local struct as type param to tflop_nr - this is the trigger
tflop_nr #(.T(rq_t)) rq_reg (
.clk(clk),
.rst_n(rst_n),
.q_o(rq_q),
.d_i(rq_d)
);
assign out_vld = rq_q.meta.en;
assign out_pkt.meta = rq_q.meta;
assign out_pkt.addr = rq_q.addr;
assign out_pkt.data = in_pkt.data;
endmodule
// Wrapper module: instantiates types_if, imports pkt_t, passes it as
// type param to slice instances in a generate loop.
// (mirrors smem_top)
module wrapper #(
parameter cfg_pkg::cfg_t cfg = '0
) (
input logic clk,
input logic rst_n
);
types_if #(cfg) types();
typedef types.pkt_t pkt_t;
typedef types.meta_t meta_t;
pkt_t in_pkt;
logic in_vld;
assign in_vld = 1'b1;
assign in_pkt.meta.en = 1'b1;
assign in_pkt.meta.tag = 4'd5;
assign in_pkt.meta.is_read = 1'b0;
assign in_pkt.addr = '0;
assign in_pkt.data = 64'hDEAD_BEEF;
// Generate loop with slices (mirrors gen_slices in smem_top)
logic [cfg.NumThreads-1:0] out_vld;
pkt_t [cfg.NumThreads-1:0] out_pkt;
generate
for (genvar i = 0; i < 2; i++) begin : gen_slices
slice #(
.cfg(cfg),
.SLICE_IDX(i),
.pkt_t(pkt_t)
) u_slice (
.clk(clk),
.rst_n(rst_n),
.in_vld(in_vld),
.in_pkt(in_pkt),
.out_vld(out_vld[i]),
.out_pkt(out_pkt[i])
);
end
endgenerate
endmodule
module t;
logic clk = 0;
always #5 clk = ~clk;
logic rst_n = 0;
int cyc = 0;
localparam cfg_pkg::cfg_t MY_CFG = '{
Capacity: 8192,
Slices: 8,
NumThreads: 32
};
// Expected: NUM_ROWS = (8192/8)/8 = 128
// row_addr_t = logic [6:0] (7 bits)
// tl_addr_t = logic [4:0] (5 bits)
// addr_t.raw = logic [17:0] (7+5+6 = 18 bits)
wrapper #(.cfg(MY_CFG)) u_wrapper (
.clk(clk),
.rst_n(rst_n)
);
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 2) rst_n <= 1;
if (cyc > 5) begin
if (u_wrapper.out_vld[0] !== 1'b1) begin
$display("FAIL cyc=%0d: out_vld[0]=%b expected 1", cyc, u_wrapper.out_vld[0]);
$stop;
end
if (u_wrapper.out_pkt[0].meta.tag !== 4'd5) begin
$display("FAIL cyc=%0d: tag=%0d expected 5", cyc, u_wrapper.out_pkt[0].meta.tag);
$stop;
end
end
if (cyc == 20) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -7,17 +7,11 @@
# SPDX-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
# Verifies that skipWidthForTemplateStruct fires in V3Param::cellPinCleanup
# when struct typedefs from a nested parameterized interface are passed as
# type parameters through two levels of interface nesting.
import vltest_bootstrap
test.scenarios('vlt')
test.compile(v_flags2=["--binary --stats"])
test.file_grep(test.stats, r'Param, Template struct width skips\s+(\d+)', 2)
test.compile(v_flags2=["--binary"])
test.execute()

View File

@ -21,9 +21,9 @@ test.compile(v_flags2=["--binary --stats"])
test.file_grep(test.stats, r'IfaceCapture, Entries total\s+(\d+)', 18)
test.file_grep(test.stats, r'IfaceCapture, Entries template\s+(\d+)', 8)
test.file_grep(test.stats, r'IfaceCapture, Entries cloned\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Ledger fixups in V3Param\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Ledger fixups in V3Param\s+(\d+)', 8)
test.file_grep(test.stats, r'IfaceCapture, Wrong-clone refs fixed\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Dead refs fixed in modules\s+(\d+)', 6)
test.file_grep(test.stats, r'IfaceCapture, Dead refs fixed in modules\s+(\d+)', 2)
test.execute()

View File

@ -18,12 +18,12 @@ test.top_filename = "t/t_paramgraph_iface_template_nested.v"
test.compile(v_flags2=["--binary --stats"])
test.file_grep(test.stats, r'IfaceCapture, Entries total\s+(\d+)', 21)
test.file_grep(test.stats, r'IfaceCapture, Entries total\s+(\d+)', 25)
test.file_grep(test.stats, r'IfaceCapture, Entries template\s+(\d+)', 11)
test.file_grep(test.stats, r'IfaceCapture, Entries cloned\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Ledger fixups in V3Param\s+(\d+)', 7)
test.file_grep(test.stats, r'IfaceCapture, Wrong-clone refs fixed\s+(\d+)', 8)
test.file_grep(test.stats, r'IfaceCapture, Dead refs fixed in modules\s+(\d+)', 4)
test.file_grep(test.stats, r'IfaceCapture, Entries cloned\s+(\d+)', 14)
test.file_grep(test.stats, r'IfaceCapture, Ledger fixups in V3Param\s+(\d+)', 5)
test.file_grep(test.stats, r'IfaceCapture, Wrong-clone refs fixed\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Dead refs fixed in modules\s+(\d+)', 2)
test.execute()

View File

@ -18,12 +18,12 @@ test.top_filename = "t/t_paramgraph_nested_iface_typedef.v"
test.compile(v_flags2=["--binary --stats"])
test.file_grep(test.stats, r'IfaceCapture, Entries total\s+(\d+)', 18)
test.file_grep(test.stats, r'IfaceCapture, Entries total\s+(\d+)', 20)
test.file_grep(test.stats, r'IfaceCapture, Entries template\s+(\d+)', 8)
test.file_grep(test.stats, r'IfaceCapture, Entries cloned\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Ledger fixups in V3Param\s+(\d+)', 12)
test.file_grep(test.stats, r'IfaceCapture, Wrong-clone refs fixed\s+(\d+)', 12)
test.file_grep(test.stats, r'IfaceCapture, Dead refs fixed in modules\s+(\d+)', 10)
test.file_grep(test.stats, r'IfaceCapture, Entries cloned\s+(\d+)', 12)
test.file_grep(test.stats, r'IfaceCapture, Ledger fixups in V3Param\s+(\d+)', 8)
test.file_grep(test.stats, r'IfaceCapture, Wrong-clone refs fixed\s+(\d+)', 14)
test.file_grep(test.stats, r'IfaceCapture, Dead refs fixed in modules\s+(\d+)', 4)
test.execute()