mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-15 03:35:40 +00:00
ASLR-dependent ConstEval seeding let E4 miss OOR counterexamples; use a deterministic seed and force OOR key collisions. Add I9 (NB=12) for the thermometer fallback path Greptile flagged. Co-authored-by: Cursor <cursoragent@cursor.com>
1212 lines
36 KiB
Text
1212 lines
36 KiB
Text
# Tests for opt_first_fit_alloc
|
||
#
|
||
# The pass detects greedy first-fit "running-rank" resource allocators (the
|
||
# serial taken[]/done[] loop) and replaces the loop-carried cone with a
|
||
# log-depth priority-encode + all-pairs category-equality + prefix-sum + gather
|
||
# network. Where a per-slot field table (an "xbar") is driven from the same
|
||
# allocation, it is rewritten from the shared scan.
|
||
#
|
||
# Each group exercises a specific facet:
|
||
# A: basic detection + formal equivalence across allocator shapes (N=8).
|
||
# B: depth / cell-count bounds after rewrite (the actual QoR win).
|
||
# C: the customer slice (dsel + xbar) at N=8 (equiv) and N=16 (structural).
|
||
# D: variant detection (bc on/off, LSB/MSB-first scan).
|
||
# E: negative / no-op cases (no false rewrites).
|
||
# F: extra fanout / input reuse.
|
||
#
|
||
# Convention: every object the pass emits is named with an `ffa_` suffix, so
|
||
# `select w:*ffa_*` is a reliable "did the rewrite fire" probe.
|
||
|
||
# ============================================================================
|
||
# Group A: basic shapes (equiv_opt -assert)
|
||
# ============================================================================
|
||
|
||
# A1: dsel-only first-fit allocator, N=8 NB=4 (W=2) C=2, LSB-first, with bc.
|
||
log -header "A1: dsel-only allocator N=8 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
# Confirm the rewrite actually fired.
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# A2: dsel + xbar (per-slot field gather) allocator, N=8.
|
||
log -header "A2: dsel + xbar allocator N=8 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
input logic [N-1:0] sw,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [NB*4*5-1:0] xbar_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [4:0] xbar [0:NB*4-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
for (int i=0;i<NB*4;i++) xbar[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int l=0;l<4;l++)
|
||
xbar[(j*4)+l] = (5'(({3'b0,cat_flat[i*C +: C]}*4)+l)) ^ {3'b0, sw[i], 1'b0};
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
for (genvar g=0;g<NB*4;g++) assign xbar_flat[g*5 +: 5] = xbar[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
memory -nomap -norom -nordff
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# A3: dsel-only, no broadcast lanes (bc absent), N=8.
|
||
log -header "A3: dsel-only allocator without bc, N=8 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if ((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group B: depth / cell-count bounds (the QoR win)
|
||
# ============================================================================
|
||
|
||
# B1: N=8 allocator. The serial taken[]/done[] scan lowers to ~1000 $mux cells
|
||
# (a deep loop-carried chain). After the rewrite the rank gather is a log-depth
|
||
# network: the long mux chain is gone, replaced by all-pairs $eq + prefix-sum
|
||
# $add. Bounding the surviving $mux count is a robust proxy for the depth win.
|
||
log -header "B1: N=8 allocator structural bounds"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
# Serial baseline: hundreds of muxes in the loop-carried chain.
|
||
select -assert-min 200 t:$mux
|
||
opt_first_fit_alloc
|
||
opt_clean
|
||
# The deep mux chain is replaced by the log-depth scan (measured ~17 muxes).
|
||
select -assert-max 60 t:$mux
|
||
# All-pairs category equality and the prefix-sum cascade are present.
|
||
select -assert-min 1 t:$eq
|
||
select -assert-min 1 t:$add
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group C: the customer slice (dsel + xbar) and scaling
|
||
# ============================================================================
|
||
|
||
# C1: N=16 dsel-only allocator -- structural (full equiv at N=16 is SAT-hard,
|
||
# matching the serial-vs-parallel allocator equivalence cost; covered formally
|
||
# at N=8 in group A and by the in-pass fingerprint here).
|
||
log -header "C1: N=16 allocator structural"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=16, NB=8, C=3, W=3) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
select -assert-min 1000 t:$mux
|
||
opt_first_fit_alloc
|
||
opt_clean
|
||
select -assert-max 120 t:$mux
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# C2: N=16 dsel + xbar -- both deep cones must collapse from the shared scan.
|
||
log -header "C2: N=16 dsel + xbar structural"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=16, NB=8, C=3, W=3) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
input logic [N-1:0] sw,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [NB*4*5-1:0] xbar_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [4:0] xbar [0:NB*4-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
for (int i=0;i<NB*4;i++) xbar[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int l=0;l<4;l++)
|
||
xbar[(j*4)+l] = (5'(({2'b0,cat_flat[i*C +: C]}*4)+l)) ^ {3'b0, sw[i], 1'b0};
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
for (genvar g=0;g<NB*4;g++) assign xbar_flat[g*5 +: 5] = xbar[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
memory -nomap -norom -nordff
|
||
opt
|
||
select -assert-min 1000 t:$mux
|
||
opt_first_fit_alloc
|
||
opt_clean
|
||
# Both the dsel and the xbar field gather were rewritten from one scan: the
|
||
# deep mux chains collapse (measured ~41 muxes) and the xbar per-slot field
|
||
# gather emits $bmux table-lookups (only the xbar path emits $bmux).
|
||
select -assert-min 1 w:*ffa_*
|
||
select -assert-max 120 t:$mux
|
||
select -assert-min 1 t:$bmux
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group D: variant detection (scan direction, category width)
|
||
# ============================================================================
|
||
|
||
# D1: MSB-first scan -- lanes processed from the high index down. The pass must
|
||
# detect the reversed priority and stay equivalent.
|
||
log -header "D1: MSB-first allocator (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=N-1;i>=0;i--)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# D2: a wider category (C=3, up to 8 distinct categories) with NB=8 slots.
|
||
log -header "D2: wider category C=3, NB=8 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=8, C=3, W=3) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if ((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group E: negative / no-op cases (no false rewrites)
|
||
# ============================================================================
|
||
|
||
# E1: a per-lane passthrough (dsel[i] = cat[i]) -- no allocation, no taken[]
|
||
# scan. There is no enable bus and the function is not a running rank.
|
||
log -header "E1: per-lane passthrough -> no rewrite"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, C=2, W=2) (
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
always_comb
|
||
for (int i=0;i<N;i++) dsel[i] = W'(cat_flat[i*C +: C]);
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
opt_first_fit_alloc
|
||
select -assert-count 0 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# E2: a "last-fit" allocator (scans free slots from NB-1 down to 0) -- the same
|
||
# loop shape as first-fit but the OPPOSITE slot choice. The fingerprint must
|
||
# reject it as it is not the first-fit running rank.
|
||
log -header "E2: last-fit allocator near-miss -> no rewrite"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=NB-1;j>=0;j--)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if ((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
opt_first_fit_alloc
|
||
select -assert-count 0 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# E3: input width below min (N=2 < default min-width 4) -> no candidate root.
|
||
log -header "E3: width below min-width -> no rewrite"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=2, NB=2, C=1, W=1) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
opt_first_fit_alloc
|
||
select -assert-count 0 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# E4: a plain unrelated mux feeding a small output -- nothing allocator-shaped.
|
||
log -header "E4: unrelated logic -> no rewrite"
|
||
log -push
|
||
design -reset
|
||
read_verilog <<EOF
|
||
module top(input wire sel, input wire [7:0] a, b, output wire [7:0] y);
|
||
assign y = sel ? a : b;
|
||
endmodule
|
||
EOF
|
||
proc
|
||
opt
|
||
opt_first_fit_alloc
|
||
select -assert-count 0 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group F: extra fanout / shared inputs
|
||
# ============================================================================
|
||
|
||
# F1: the request and category inputs also feed unrelated outputs. The pass
|
||
# must still rewrite the allocator and stay equivalent (inputs are just wires).
|
||
log -header "F1: shared inputs / extra fanout (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
input logic [N-1:0] oob,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [N-1:0] req_dbg,
|
||
output logic [N*C-1:0] cat_dbg
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [N-1:0] bc = oob & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (((k!=i) && en[k] && (cat_flat[k*C +: C]==cat_flat[i*C +: C])) || bc[k]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
assign req_dbg = ~req;
|
||
assign cat_dbg = cat_flat ^ {(N*C){mode}};
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group G: coalesce-matrix variant (precomputed same_cat[i][k], raw-input en)
|
||
# ============================================================================
|
||
#
|
||
# Some RTL precomputes a per-leader "same_cat[i][k]" mask (gated ONLY on the
|
||
# leader's enable) and forward-coalesces the leader's slot into lane k without
|
||
# re-checking en[k]. Disabled lanes after a same-category leader therefore
|
||
# inherit that leader's slot (rather than 0). The pass detects this as the
|
||
# enable-independent forward-coalescing variant. These modules also drive the
|
||
# scan straight from a top-level request port (lane_en), exercising the
|
||
# primary-input enable/broadcast candidate path.
|
||
|
||
# G1: coalesce-matrix dsel-only, raw-input enable, N=8 (equiv).
|
||
log -header "G1: coalesce-matrix allocator, raw-input enable, N=8 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] same_cat [0:N-1];
|
||
always_comb begin
|
||
for (int a=0;a<N;a++) begin
|
||
same_cat[a] = '0;
|
||
if (lane_en[a])
|
||
for (int b=a;b<N;b++)
|
||
if (cat_flat[a*C +: C]==cat_flat[b*C +: C]) same_cat[a][b] = 1'b1;
|
||
end
|
||
end
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (same_cat[i][k]) begin dsel[k] = W'(j); done[k] = 1'b1; end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
# The coalesce variant fired (log shows "coalesce").
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# G2: coalesce-matrix dsel + xbar, N=16 -- structural. Both deep cones must
|
||
# collapse from the shared scan (dsel via the coalesce gather, xbar via the
|
||
# per-slot field gather); full equiv at N=16 is SAT-hard (see group C).
|
||
log -header "G2: coalesce-matrix dsel + xbar, N=16 structural"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=16, NB=8, C=3, W=3, A=5) (
|
||
input logic [N-1:0] lane_en,
|
||
input logic [N*C-1:0] cat_flat,
|
||
input logic [N-1:0] swap_bit,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [32*A-1:0] xbar_flat
|
||
);
|
||
logic [N-1:0] same_cat [0:N-1];
|
||
always_comb begin
|
||
for (int a=0;a<N;a++) begin
|
||
same_cat[a] = '0;
|
||
if (lane_en[a])
|
||
for (int b=a;b<N;b++)
|
||
if (cat_flat[a*C +: C]==cat_flat[b*C +: C]) same_cat[a][b] = 1'b1;
|
||
end
|
||
end
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [A-1:0] xbar [0:31];
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
for (int i=0;i<32;i++) xbar[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int l=0;l<4;l++)
|
||
xbar[(j*4)+l] = (A'(({2'b0,cat_flat[i*C +: C]}*4)+l)) ^ {3'b0, swap_bit[i], 1'b0};
|
||
for (int k=0;k<N;k++)
|
||
if (same_cat[i][k]) begin dsel[k] = W'(j); done[k] = 1'b1; end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
for (genvar g=0;g<32;g++) assign xbar_flat[g*A +: A] = xbar[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
memory -nomap -norom -nordff
|
||
opt
|
||
select -assert-min 1000 t:$mux
|
||
opt_first_fit_alloc
|
||
opt_clean
|
||
select -assert-min 1 w:*ffa_*
|
||
# The deep mux chains collapse and the xbar emits $bmux table-lookups.
|
||
select -assert-max 200 t:$mux
|
||
select -assert-min 1 t:$bmux
|
||
design -reset
|
||
log -pop
|
||
|
||
# G3: coalesce-matrix but LAST-fit slot choice (scans free slots NB-1..0). The
|
||
# same_cat coalescing is present but the slot assignment is not first-fit, so
|
||
# neither the standard nor the coalesce fingerprint may match.
|
||
log -header "G3: coalesce-matrix last-fit near-miss -> no rewrite"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] same_cat [0:N-1];
|
||
always_comb begin
|
||
for (int a=0;a<N;a++) begin
|
||
same_cat[a] = '0;
|
||
if (lane_en[a])
|
||
for (int b=a;b<N;b++)
|
||
if (cat_flat[a*C +: C]==cat_flat[b*C +: C]) same_cat[a][b] = 1'b1;
|
||
end
|
||
end
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=NB-1;j>=0;j--)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (same_cat[i][k]) begin dsel[k] = W'(j); done[k] = 1'b1; end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
opt_first_fit_alloc
|
||
select -assert-count 0 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group H: coalesce generalization (spelling + shape variants)
|
||
# ============================================================================
|
||
#
|
||
# The coalesce variant is detected by functional fingerprinting of the dsel
|
||
# cone, so it should not depend on the exact way the same-category forwarding
|
||
# is written or on the specific N/NB/C shape. These cases vary both.
|
||
|
||
# H1: coalesce with the same-category forwarding written INLINE (no precomputed
|
||
# same_cat[i][k] matrix) -- the leader compares categories directly in its
|
||
# forward loop. Functionally identical to G1's matrix form; must still detect
|
||
# the enable-independent coalescing variant and prove equivalent.
|
||
log -header "H1: coalesce inline-compare spelling, N=8 (equiv + fires)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, C=2, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=i;k<N;k++)
|
||
if (cat_flat[k*C +: C]==cat_flat[i*C +: C]) begin
|
||
dsel[k] = W'(j); done[k] = 1'b1;
|
||
end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# H2: coalesce at a different shape -- N=8 lanes but NB=8 slots (twice G1's
|
||
# slot count, wider dsel W=3). Confirms the coalesce fingerprint generalizes
|
||
# across slot/field widths, not just the N=8/NB=4 shape of G1.
|
||
log -header "H2: coalesce shape N=8 NB=8 W=3 (equiv + fires)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=8, C=2, W=3) (
|
||
input logic [N-1:0] lane_en,
|
||
input logic [N*C-1:0] cat_flat,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] same_cat [0:N-1];
|
||
always_comb begin
|
||
for (int a=0;a<N;a++) begin
|
||
same_cat[a] = '0;
|
||
if (lane_en[a])
|
||
for (int b=a;b<N;b++)
|
||
if (cat_flat[a*C +: C]==cat_flat[b*C +: C]) same_cat[a][b] = 1'b1;
|
||
end
|
||
end
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
for (int k=0;k<N;k++)
|
||
if (same_cat[i][k]) begin dsel[k] = W'(j); done[k] = 1'b1; end
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# ============================================================================
|
||
# Group I: exclusive saturating first-fit (no category / broadcast)
|
||
# ============================================================================
|
||
#
|
||
# Plain taken[]/done[] scan without same-cat coalescing: each enabled lane
|
||
# takes the next free slot until NB slots are exhausted. Later requesters get
|
||
# rank 0 / not done. This is the qor_vmw_slot_lane shape.
|
||
|
||
# I1: exclusive dsel-only, N=8 NB=4 (equiv + fires).
|
||
log -header "I1: exclusive saturating allocator N=8 NB=4 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, W=2) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I2: exclusive with raw-input enable + sibling done bus, N=16 NB=4.
|
||
log -header "I2: exclusive N=16 NB=4 raw-input en + done (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=16, NB=4, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [N-1:0] done_o
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
assign done_o = done;
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I3: exclusive with non-power-of-two slot budget (NB=3, W=2) -- learn nb=3.
|
||
log -header "I3: exclusive NB=3 (non-power-of-two) N=8 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=3, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I4: exclusive last-fit near-miss (scan slots NB-1..0) -> no rewrite.
|
||
log -header "I4: exclusive last-fit near-miss -> no rewrite"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=NB-1;j>=0;j--)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
opt_first_fit_alloc
|
||
select -assert-count 0 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I5: exclusive MSB-first scan (lanes N-1..0), N=8 NB=4 (equiv).
|
||
log -header "I5: exclusive MSB-first scan N=8 NB=4 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, W=2) (
|
||
input logic [N-1:0] lane_en,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=N-1;i>=0;i--)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I6: exclusive + identity gather of wide lane payloads into NB slots
|
||
# (qor_vmw_slot_lane shape: slot_data[j] = data[leader at j]).
|
||
# DW != N so per-lane data buses are not mistaken for width-N enables.
|
||
log -header "I6: exclusive + identity gather N=8 NB=4 DW=16 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, W=2, DW=16) (
|
||
input logic [N-1:0] lane_en,
|
||
input logic [N*DW-1:0] data_flat,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [NB*DW-1:0] slot_flat
|
||
);
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [DW-1:0] data [0:N-1];
|
||
logic [DW-1:0] slot_data [0:NB-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
for (genvar g=0;g<N;g++) assign data[g] = data_flat[g*DW +: DW];
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
for (int j=0;j<NB;j++) slot_data[j] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (lane_en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
slot_data[j] = data[i];
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
for (genvar g=0;g<NB;g++) assign slot_flat[g*DW +: DW] = slot_data[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I7: exclusive and2 enable (req = a & b), with sibling done — the
|
||
# qor_vmw_slot_lane enable shape after opt folds the named `req` wire.
|
||
# Equiv covers the and2 fingerprint path; I6 already covers identity gather.
|
||
log -header "I7: exclusive and2 enable + done N=16 NB=4 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=16, NB=4, W=2) (
|
||
input logic [N-1:0] a,
|
||
input logic [N-1:0] b,
|
||
output logic [N*W-1:0] dsel_flat,
|
||
output logic [N-1:0] done_o
|
||
);
|
||
logic [N-1:0] en = a & b;
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
assign done_o = done;
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I8: exclusive and2 enable without a global `opt` — launch flop stays a
|
||
# plain $dff (sync reset) so leaf runs are data_q halves. Covers the pre-opt
|
||
# and2 path; $aldff sequential handling is exercised by qor_vmw_slot_lane.
|
||
log -header "I8: exclusive and2 enable pre-opt N=8 NB=4 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=8, NB=4, W=2) (
|
||
input logic clk,
|
||
input logic [2*N-1:0] wdata,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [2*N-1:0] data_q;
|
||
always_ff @(posedge clk)
|
||
data_q <= wdata;
|
||
wire [N-1:0] req = data_q[N-1:0] & data_q[2*N-1:N];
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0;
|
||
done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (req[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
# Intentionally no `opt`.
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|
||
|
||
# I9: exclusive with NB > max_therm_nb (8) — forces the binary saturating
|
||
# Hillis–Steele fallback (emit_scan_exclusive_bin / emit_sat_add) instead of
|
||
# the thermometer scan used by I1–I8.
|
||
log -header "I9: exclusive binary-scan fallback N=16 NB=12 (equiv)"
|
||
log -push
|
||
design -reset
|
||
read_verilog -sv <<EOF
|
||
module top #(parameter N=16, NB=12, W=4) (
|
||
input logic mode,
|
||
input logic [N-1:0] req,
|
||
output logic [N*W-1:0] dsel_flat
|
||
);
|
||
logic [N-1:0] en = req & {N{mode}};
|
||
logic [W-1:0] dsel [0:N-1];
|
||
logic [NB-1:0] taken;
|
||
logic [N-1:0] done;
|
||
always_comb begin
|
||
for (int i=0;i<N;i++) dsel[i] = '0;
|
||
taken = '0; done = '0;
|
||
for (int i=0;i<N;i++)
|
||
if (en[i])
|
||
for (int j=0;j<NB;j++)
|
||
if (!taken[j] && !done[i]) begin
|
||
dsel[i] = W'(j); done[i] = 1'b1; taken[j] = 1'b1;
|
||
end
|
||
end
|
||
for (genvar g=0;g<N;g++) assign dsel_flat[g*W +: W] = dsel[g];
|
||
endmodule
|
||
EOF
|
||
hierarchy -top top
|
||
proc
|
||
opt
|
||
check -assert
|
||
equiv_opt -assert opt_first_fit_alloc
|
||
design -load postopt
|
||
select -assert-min 1 w:*ffa_*
|
||
design -reset
|
||
log -pop
|