1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
|