summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2026-07-22 20:56:59 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2026-07-22 20:56:59 +0300
commitbc5941a1fcfd0a607a6aef51f7659c3f233b65dc (patch)
tree89fb6166a698b7a1f2a71276432218ad1a364994
parent0c9c1538996c4e5120a9d409edd6b1cd5c07d22f (diff)
downloadttarv32-bc5941a1fcfd0a607a6aef51f7659c3f233b65dc.tar.gz
ttarv32-bc5941a1fcfd0a607a6aef51f7659c3f233b65dc.zip
simplift arbHEADmaster
+ Had a higher fMax and smaller area compared to previous attempt, at least when synthesized with OpenROAD
-rw-r--r--src/arb.sv99
-rw-r--r--tb/arb_tb.sv12
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)