From bc5941a1fcfd0a607a6aef51f7659c3f233b65dc Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 22 Jul 2026 20:56:59 +0300 Subject: simplift arb + Had a higher fMax and smaller area compared to previous attempt, at least when synthesized with OpenROAD --- src/arb.sv | 99 +++++++++++++----------------------------------------------- tb/arb_tb.sv | 12 ++++---- 2 files changed, 27 insertions(+), 84 deletions(-) diff --git a/src/arb.sv b/src/arb.sv index 15d89b3..6dbd6a6 100644 --- a/src/arb.sv +++ b/src/arb.sv @@ -1,99 +1,42 @@ -module first_set #( - parameter WIDTH = 32 -)( - input reg[WIDTH-1 :0] cand, - output reg[WIDTH-1 :0] selected -); - -/* base case */ -if (WIDTH == 1) begin :base - assign selected = cand; -end - -/* recursive case */ -else begin :recursive - localparam SLICE_WIDTH = WIDTH / 2; - logic[SLICE_WIDTH-1:0] left, right; - logic pref_left, pref_right; - logic empty_left, empty_right; - - first_set #( - .WIDTH(SLICE_WIDTH) - ) first_set_left ( - .cand(cand[SLICE_WIDTH +: SLICE_WIDTH]), - .selected (left) - ); - - first_set #( - .WIDTH(SLICE_WIDTH) - ) first_set_right ( - .cand(cand[0 +: SLICE_WIDTH]), - .selected (right) - ); - - assign selected = right != '0 - ? {{SLICE_WIDTH{1'b0}}, right} - : {left, {SLICE_WIDTH{1'b0}}} - ; -end - -always_comb begin - assert ($onehot0(selected)); -end - -`ifdef NOSUCHDEF -/* assertions that verilator don't support, apparently */ -assert property (WIDTH >= 1) -else $error("input width too narrow"); - -assert property (1 << $clog2(WIDTH) == WIDTH) -else $error("width not pow2"); - -`endif - -endmodule // arb_recursive - module arb #( parameter WIDTH = 32 )( input clk, input rstx, - input [WIDTH-1:0] cand, + input [WIDTH-1:0] valid, output[WIDTH-1:0] selected ); -localparam W2 = 1 << $clog2(WIDTH); -localparam DEPTH = W2 == 1 ? 1 : $clog2(W2); +logic found0, found1; +logic [WIDTH-1:0] mask, next_mask0, next_mask1, cand0, cand1; -logic[W2-1:0] w2_cand, w2_selected, mask, next_mask, rot_selected; +always_comb begin + found0 = 0; + found1 = 0; + for (int i = 0; i < WIDTH; ++i) begin + cand0[i] = !found0 & valid[i] & mask[i]; + cand1[i] = !found1 & valid[i]; -/* if there are candidates within the mask of 'above preferred index', use them, - * otherwise invert the mask and use candidates 'below' preferred index. */ -assign w2_cand = ((cand & mask) == '0) ? cand & ~mask : cand & mask; + next_mask0[i] = found0; + next_mask1[i] = found1; -first_set #( - .WIDTH(W2) -) first_set_i ( - .cand (w2_cand), - .selected(w2_selected) -); + if (valid[i] & mask[i]) + found0 = 1; -assign selected = w2_selected; - -assign rot_selected = { - w2_selected[0 +: W2-1], - w2_selected[W2-1] -}; + if (valid[i]) + found1 = 1; + end +end -assign next_mask = ~(rot_selected - 1) | rot_selected; +assign selected = found0 ? cand0 : cand1; always_ff @(posedge clk or negedge rstx) if (!rstx) begin - mask <= ~0; + mask <= '0; end else begin - if (selected != 0 && mask != next_mask) - mask <= next_mask; + if (|valid) + mask <= found0 ? next_mask0 : next_mask1; else mask <= mask; end diff --git a/tb/arb_tb.sv b/tb/arb_tb.sv index 909c5b2..53b9cb2 100644 --- a/tb/arb_tb.sv +++ b/tb/arb_tb.sv @@ -4,7 +4,7 @@ localparam WIDTH = 32; reg clk; reg rstx; -logic[WIDTH-1:0] cand; +logic[WIDTH-1:0] valid; logic[WIDTH-1:0] selected; arb #( @@ -12,7 +12,7 @@ arb #( ) arb_i ( .clk(clk), .rstx(rstx), - .cand(cand), + .valid(valid), .selected(selected) ); @@ -33,12 +33,12 @@ initial begin /* honestly, I'm a bit confused about this, if I try to make this be at * a positive clock edge, the selected == 1 condition disappears because - * cand apparently triggers `selected` to be recalculated first, which + * valid apparently triggers `selected` to be recalculated first, which * then is fed into `mask` which then re-triggers `selected` and causes * it to 'skip' ahead to selected == 2. When looking at the waveforms, * the next @(posedge clk) shows 2 while the assert passes. I guess the * assert is run first in the time step...? */ - cand = ~0; + valid = ~0; @(posedge clk); assert (selected == 1) @@ -54,13 +54,13 @@ initial begin else $error("expected 4, got ", selected); /* skip next index */ - cand = '0; + valid = '0; @(posedge clk); assert (selected == 0) else $error("expected 0, got ", selected); - cand = ~8; + valid = ~8; @(posedge clk); assert (selected == 16) -- cgit v1.3