3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-17 12:45:44 +00:00

Merge pull request #209 from Silimate/opt_ffa_pt2

opt_first_fit_alloc updates + tests + some nice refactoring
This commit is contained in:
Akash Levy 2026-07-09 00:04:39 -07:00 committed by GitHub
commit 6e80c5348d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1758 additions and 148 deletions

View file

@ -857,3 +857,356 @@ 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
# HillisSteele fallback (emit_scan_exclusive_bin / emit_sat_add) instead of
# the thermometer scan used by I1I8.
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