From 76029b9bc1242a9292905cae6f71e080955ceaf2 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Mon, 22 Jun 2026 00:50:26 +0300 Subject: add simple round-robin arbiter + Should check how well it synthesises with OpenROAD or something, Vivado seemed to kind of choke on it and it was way slower/bigger than I was expecting. --- src/arb.sv | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 src/arb.sv (limited to 'src') diff --git a/src/arb.sv b/src/arb.sv new file mode 100644 index 0000000..15d89b3 --- /dev/null +++ b/src/arb.sv @@ -0,0 +1,101 @@ +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, + output[WIDTH-1:0] selected +); + +localparam W2 = 1 << $clog2(WIDTH); +localparam DEPTH = W2 == 1 ? 1 : $clog2(W2); + +logic[W2-1:0] w2_cand, w2_selected, mask, next_mask, rot_selected; + +/* 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; + +first_set #( + .WIDTH(W2) +) first_set_i ( + .cand (w2_cand), + .selected(w2_selected) +); + +assign selected = w2_selected; + +assign rot_selected = { + w2_selected[0 +: W2-1], + w2_selected[W2-1] +}; + +assign next_mask = ~(rot_selected - 1) | rot_selected; + +always_ff @(posedge clk or negedge rstx) +if (!rstx) begin + mask <= ~0; +end else begin + if (selected != 0 && mask != next_mask) + mask <= next_mask; + else + mask <= mask; +end + +endmodule // arb -- cgit v1.3