summaryrefslogtreecommitdiff
path: root/src/arb.sv
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2026-06-22 00:50:26 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2026-06-22 00:53:51 +0300
commit76029b9bc1242a9292905cae6f71e080955ceaf2 (patch)
treebbfa5f78edf0516ec59eb1c8545ee8795a270c40 /src/arb.sv
parentb1ee83cd1ea325a5d353365ac35790a7c1d47845 (diff)
downloadttarv32-76029b9bc1242a9292905cae6f71e080955ceaf2.tar.gz
ttarv32-76029b9bc1242a9292905cae6f71e080955ceaf2.zip
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.
Diffstat (limited to 'src/arb.sv')
-rw-r--r--src/arb.sv101
1 files changed, 101 insertions, 0 deletions
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