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