46
46
// / If it is `1'b1` two `lzc`, a masking logic stage and a two input multiplexer are instantiated.
47
47
// / However these are small in respect of the data multiplexers needed, as the width of the `req_i`
48
48
// / signal is usually less as than `DataWidth`.
49
+
50
+ `include " redundancy_cells/voters.svh"
51
+
49
52
module rr_arb_tree_lock # (
50
53
// / Number of inputs to be arbitrated.
51
54
parameter int unsigned NumIn = 64 ,
@@ -67,13 +70,6 @@ module rr_arb_tree_lock #(
67
70
// /
68
71
// / Set to `1'b1` to treat req/gnt as vld/rdy.
69
72
parameter bit AxiVldRdy = 1'b0 ,
70
- // / The `LockIn` option prevents the arbiter from changing the arbitration
71
- // / decision when the arbiter is disabled. I.e., the index of the first request
72
- // / that wins the arbitration will be locked in case the destination is not
73
- // / able to grant the request in the same cycle.
74
- // /
75
- // / Set to `1'b1` to enable.
76
- parameter bit LockIn = 1'b0 ,
77
73
// / When set, ensures that throughput gets distributed evenly between all inputs.
78
74
// /
79
75
// / Set to `1'b0` to disable.
@@ -83,18 +79,25 @@ module rr_arb_tree_lock #(
83
79
parameter int unsigned IdxWidth = (NumIn > 32'd1 ) ? unsigned '($clog2(NumIn)) : 32'd1 ,
84
80
// / Dependent parameter, do **not** overwrite.
85
81
// / Type for defining the arbitration priority and arbitrated index signal.
86
- parameter type idx_t = logic [IdxWidth- 1 : 0 ]
82
+ parameter type idx_t = logic [IdxWidth- 1 : 0 ],
83
+ // Determines if the internal state machines should
84
+ // be parallely redundant, meaning errors inside this module
85
+ // can also not cause errors in the output
86
+ // The external output is never protected!
87
+ parameter bit InternalRedundancy = 0 ,
88
+ // Do not modify
89
+ localparam int REP = InternalRedundancy ? 3 : 1
87
90
) (
88
91
// / Clock, positive edge triggered.
89
92
input logic clk_i,
90
93
// / Asynchronous reset, active low.
91
94
input logic rst_ni,
92
95
// / Clears the arbiter state. Only used if `ExtPrio` is `1'b0` or `LockIn` is `1'b1`.
93
- input logic flush_i,
96
+ input logic [ REP - 1 : 0 ] flush_i,
94
97
// / External round-robin priority.
95
98
input idx_t rr_i,
96
99
// / lock idx signal, only used if `ExtPrio` is `1'b0.`
97
- input logic lock_rr_i,
100
+ input logic [ REP - 1 : 0 ] lock_rr_i,
98
101
// / Input requests arbitration.
99
102
input logic [NumIn- 1 : 0 ] req_i,
100
103
/* verilator lint_off UNOPTFLAT */
@@ -117,7 +120,7 @@ module rr_arb_tree_lock #(
117
120
`ifndef VERILATOR
118
121
`ifndef XSIM
119
122
// Default SVA reset
120
- default disable iff (! rst_ni || flush_i);
123
+ default disable iff (! rst_ni || flush_i[ 0 ] );
121
124
`endif
122
125
`endif
123
126
// pragma translate_on
@@ -133,86 +136,39 @@ module rr_arb_tree_lock #(
133
136
localparam int unsigned NumLevels = unsigned '($clog2 (NumIn));
134
137
135
138
/* verilator lint_off UNOPTFLAT */
136
- idx_t [2 ** NumLevels- 2 : 0 ] index_nodes; // used to propagate the indices
139
+ idx_t [2 ** NumLevels- 2 : 0 ][ REP - 1 : 0 ] index_nodes; // used to propagate the indices
137
140
DataType [2 ** NumLevels- 2 : 0 ] data_nodes; // used to propagate the data
138
141
logic [2 ** NumLevels- 2 : 0 ] gnt_nodes; // used to propagate the grant to masters
139
142
logic [2 ** NumLevels- 2 : 0 ] req_nodes; // used to propagate the requests to slave
140
143
/* lint_off */
141
- idx_t rr_q;
144
+ idx_t [ REP - 1 : 0 ] rr_q;
142
145
logic [NumIn- 1 : 0 ] req_d;
143
146
144
147
// the final arbitration decision can be taken from the root of the tree
145
148
assign req_o = req_nodes[0 ];
146
149
assign data_o = data_nodes[0 ];
147
- assign idx_o = index_nodes[0 ];
150
+ assign idx_o = index_nodes[0 ][0 ];
151
+
148
152
149
153
if (ExtPrio) begin : gen_ext_rr
150
- assign rr_q = rr_i;
154
+ assign rr_q[ 0 ] = rr_i;
151
155
assign req_d = req_i;
152
156
end else begin : gen_int_rr
153
- idx_t rr_d;
154
-
155
- // lock arbiter decision in case we got at least one req and no acknowledge
156
- if (LockIn) begin : gen_lock
157
- logic lock_d, lock_q;
158
- logic [NumIn- 1 : 0 ] req_q;
159
-
160
- assign lock_d = req_o & ~ gnt_i;
161
- assign req_d = (lock_q) ? req_q : req_i;
162
-
163
- always_ff @ (posedge clk_i or negedge rst_ni) begin : p_lock_reg
164
- if (! rst_ni) begin
165
- lock_q <= '0 ;
166
- end else begin
167
- if (flush_i) begin
168
- lock_q <= '0 ;
169
- end else begin
170
- lock_q <= lock_d;
171
- end
172
- end
173
- end
157
+ idx_t [REP - 1 : 0 ] rr_d;
174
158
175
- // pragma translate_off
176
- `ifndef VERILATOR
177
- lock : assert property (
178
- @ (posedge clk_i) LockIn | - > req_o && ! gnt_i | => idx_o == $past (idx_o)) else
179
- $error (1 , " Lock implies same arbiter decision in next cycle if output is not \
180
- ready." );
181
-
182
- logic [NumIn- 1 : 0 ] req_tmp;
183
- assign req_tmp = req_q & req_i;
184
- lock_req: assume property (
185
- @ (posedge clk_i) LockIn | - > lock_d | => req_tmp == req_q) else
186
- $error (1 , " It is disallowed to deassert unserved request signals when LockIn is \
187
- enabled." );
188
- `endif
189
- // pragma translate_on
190
-
191
- always_ff @ (posedge clk_i or negedge rst_ni) begin : p_req_regs
192
- if (! rst_ni) begin
193
- req_q <= '0 ;
194
- end else begin
195
- if (flush_i) begin
196
- req_q <= '0 ;
197
- end else begin
198
- req_q <= req_d;
199
- end
200
- end
201
- end
202
- end else begin : gen_no_lock
203
- assign req_d = req_i;
204
- end
159
+ assign req_d = req_i;
205
160
206
161
idx_t next_idx;
207
162
208
163
if (FairArb) begin : gen_fair_arb
164
+
209
165
logic [NumIn- 1 : 0 ] upper_mask, lower_mask;
210
166
idx_t upper_idx, lower_idx;
211
167
logic upper_empty, lower_empty;
212
168
213
169
for (genvar i = 0 ; i < NumIn; i++ ) begin : gen_mask
214
- assign upper_mask[i] = (i > rr_q) ? req_d[i] : 1'b0 ;
215
- assign lower_mask[i] = (i <= rr_q) ? req_d[i] : 1'b0 ;
170
+ assign upper_mask[i] = (i > rr_q[ 0 ] ) ? req_d[i] : 1'b0 ;
171
+ assign lower_mask[i] = (i <= rr_q[ 0 ] ) ? req_d[i] : 1'b0 ;
216
172
end
217
173
218
174
lzc # (
@@ -235,45 +191,52 @@ module rr_arb_tree_lock #(
235
191
236
192
assign next_idx = upper_empty ? lower_idx : upper_idx;
237
193
end else begin : gen_unfair_arb
238
- assign next_idx = ((rr_q == idx_t ' (NumIn- 1 )) ? '0 : rr_q + 1'b1 );
194
+ assign next_idx = ((rr_q[ 0 ] == idx_t ' (NumIn- 1 )) ? '0 : rr_q[ 0 ] + 1'b1 );
239
195
end
240
196
241
- always_comb begin
242
- if (lock_rr_i) begin
243
- rr_d = idx_o;
244
- end else begin
245
- if (gnt_i && req_o) begin
246
- rr_d = next_idx;
197
+ idx_t [REP - 1 : 0 ] voted_idx, voted_rr_q;
198
+ `VOTEXX (REP , index_nodes[0 ], voted_idx);
199
+ `VOTEXX (REP , rr_q, voted_rr_q);
200
+
201
+ for (genvar r = 0 ; r < REP ; r++ ) begin : gen_rr
202
+ always_comb begin
203
+ if (lock_rr_i[r]) begin
204
+ rr_d[r] = voted_idx[r];
247
205
end else begin
248
- rr_d = rr_q;
206
+ if (gnt_i && req_o) begin
207
+ rr_d[r] = next_idx;
208
+ end else begin
209
+ rr_d[r] = voted_rr_q[r];
210
+ end
249
211
end
250
212
end
251
- end
252
213
253
- // this holds the highest priority
254
- always_ff @ (posedge clk_i or negedge rst_ni) begin : p_rr_regs
255
- if (! rst_ni) begin
256
- rr_q <= '0 ;
257
- end else begin
258
- if (flush_i) begin
259
- rr_q <= '0 ;
214
+ // this holds the highest priority
215
+ always_ff @ (posedge clk_i or negedge rst_ni) begin : p_rr_regs
216
+ if (! rst_ni) begin
217
+ rr_q[r] <= '0 ;
260
218
end else begin
261
- rr_q <= rr_d;
219
+ if (flush_i[r]) begin
220
+ rr_q[r] <= '0 ;
221
+ end else begin
222
+ rr_q[r] <= rr_d[r];
223
+ end
262
224
end
263
225
end
264
226
end
265
-
266
227
end
267
228
268
- logic lock_rr_q;
269
- always_ff @ (posedge clk_i or negedge rst_ni) begin : p_lock_reg
270
- if (! rst_ni) begin
271
- lock_rr_q <= '1 ;
272
- end else begin
273
- if (flush_i) begin
274
- lock_rr_q <= '0 ;
229
+ logic [REP - 1 : 0 ] lock_rr_q;
230
+ for (genvar r = 0 ; r < REP ; r++ ) begin : gen_lock_q
231
+ always_ff @ (posedge clk_i or negedge rst_ni) begin : p_lock_reg
232
+ if (! rst_ni) begin
233
+ lock_rr_q[r] <= '1 ;
275
234
end else begin
276
- lock_rr_q <= lock_rr_i;
235
+ if (flush_i[r]) begin
236
+ lock_rr_q[r] <= '0 ;
237
+ end else begin
238
+ lock_rr_q[r] <= lock_rr_i[r];
239
+ end
277
240
end
278
241
end
279
242
end
@@ -284,7 +247,7 @@ module rr_arb_tree_lock #(
284
247
for (genvar level = 0 ; unsigned '(level) < NumLevels; level++ ) begin : gen_levels
285
248
for (genvar l = 0 ; l < 2 ** level; l++ ) begin : gen_level
286
249
// local select signal
287
- logic sel;
250
+ logic [ REP - 1 : 0 ] sel;
288
251
// index calcs
289
252
localparam int unsigned Idx0 = 2 ** level- 1 + l;// current node
290
253
localparam int unsigned Idx1 = 2 ** (level+ 1 )- 1 + l* 2 ;
@@ -294,55 +257,59 @@ module rr_arb_tree_lock #(
294
257
// if two successive indices are still in the vector...
295
258
if (unsigned '(l) * 2 < NumIn- 1 ) begin : gen_reduce
296
259
297
- // arbitration: round robin
298
- always_comb begin
299
- if (lock_rr_q) begin
300
- sel = rr_q[NumLevels- 1 - level];
301
- end else begin
302
- sel = ~ req_d[l* 2 ] | req_d[l* 2 + 1 ] & rr_q[NumLevels- 1 - level];
260
+ for (genvar r = 0 ; r < REP ; r++ ) begin : gen_select
261
+ // arbitration: round robin
262
+ always_comb begin
263
+ if (lock_rr_q[r]) begin
264
+ sel[r] = rr_q[r][NumLevels- 1 - level];
265
+ end else begin
266
+ sel[r] = ~ req_d[l* 2 ] | req_d[l* 2 + 1 ] & rr_q[0 ][NumLevels- 1 - level];
267
+ end
303
268
end
269
+ assign index_nodes[Idx0][r] = idx_t ' (sel[r]);
304
270
end
305
271
306
- assign index_nodes[Idx0] = idx_t ' (sel);
307
- assign req_nodes[Idx0] = (sel) ? req_d[l* 2 + 1 ] : req_d[l* 2 ] ;
308
- assign data_nodes[Idx0] = (sel) ? data_i[l* 2 + 1 ] : data_i[l* 2 ];
309
- assign gnt_o[l* 2 ] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l* 2 ]) & ~ sel;
310
- assign gnt_o[l* 2 + 1 ] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l* 2 + 1 ]) & sel;
272
+ assign req_nodes[Idx0] = (sel[0 ]) ? req_d[l* 2 + 1 ] : req_d[l* 2 ] ;
273
+ assign data_nodes[Idx0] = (sel[0 ]) ? data_i[l* 2 + 1 ] : data_i[l* 2 ];
274
+ assign gnt_o[l* 2 ] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l* 2 ]) & ~ sel[0 ];
275
+ assign gnt_o[l* 2 + 1 ] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l* 2 + 1 ]) & sel[0 ];
311
276
end
312
277
// if only the first index is still in the vector...
313
278
if (unsigned '(l) * 2 == NumIn- 1 ) begin : gen_first
314
279
assign req_nodes[Idx0] = req_d[l* 2 ];
315
- assign index_nodes[Idx0] = '0 ;// always zero in this case
280
+ assign index_nodes[Idx0] = '0 ;
316
281
assign data_nodes[Idx0] = data_i[l* 2 ];
317
282
assign gnt_o[l* 2 ] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l* 2 ]);
318
283
end
319
284
// if index is out of range, fill up with zeros (will get pruned)
320
285
if (unsigned '(l) * 2 > NumIn- 1 ) begin : gen_out_of_range
321
286
assign req_nodes[Idx0] = 1'b0 ;
322
- assign index_nodes[Idx0] = idx_t ' ( '0 ) ;
287
+ assign index_nodes[Idx0] = '0 ;
323
288
assign data_nodes[Idx0] = DataType ' ('0 );
324
289
end
325
290
// ////////////////////////////////////////////////////////////
326
291
// general case for other levels within the tree
327
292
end else begin : gen_other_levels
328
293
329
294
// arbitration: round robin
330
- always_comb begin
331
- if (lock_rr_q) begin
332
- sel = rr_q[NumLevels- 1 - level];
333
- end else begin
334
- sel = ~ req_nodes[Idx1] | req_nodes[Idx1+ 1 ] & rr_q[NumLevels- 1 - level];
295
+ for (genvar r = 0 ; r < REP ; r++ ) begin : gen_select
296
+ always_comb begin
297
+ if (lock_rr_q[r]) begin
298
+ sel[r] = rr_q[r][NumLevels- 1 - level];
299
+ end else begin
300
+ sel[r] = ~ req_nodes[Idx1] | req_nodes[Idx1+ 1 ] & rr_q[0 ][NumLevels- 1 - level];
301
+ end
335
302
end
336
- end
337
303
338
- assign index_nodes[Idx0] = (sel) ?
339
- idx_t ' ({ 1'b1 , index_nodes[Idx1+ 1 ][NumLevels- unsigned '(level)- 2 : 0 ]} ) :
340
- idx_t ' ({ 1'b0 , index_nodes[Idx1][NumLevels- unsigned '(level)- 2 : 0 ]} );
304
+ assign index_nodes[Idx0][r] = (sel[r]) ?
305
+ idx_t ' ({ 1'b1 , index_nodes[Idx1+ 1 ][r][NumLevels- unsigned '(level)- 2 : 0 ]} ) :
306
+ idx_t ' ({ 1'b0 , index_nodes[Idx1][r][NumLevels- unsigned '(level)- 2 : 0 ]} );
307
+ end
341
308
342
- assign req_nodes[Idx0] = (sel) ? req_nodes[Idx1+ 1 ] : req_nodes[Idx1];
343
- assign data_nodes[Idx0] = (sel) ? data_nodes[Idx1+ 1 ] : data_nodes[Idx1];
344
- assign gnt_nodes[Idx1] = gnt_nodes[Idx0] & ~ sel;
345
- assign gnt_nodes[Idx1+ 1 ] = gnt_nodes[Idx0] & sel;
309
+ assign req_nodes[Idx0] = (sel[ 0 ] ) ? req_nodes[Idx1+ 1 ] : req_nodes[Idx1];
310
+ assign data_nodes[Idx0] = (sel[ 0 ] ) ? data_nodes[Idx1+ 1 ] : data_nodes[Idx1];
311
+ assign gnt_nodes[Idx1] = gnt_nodes[Idx0] & ~ sel[ 0 ] ;
312
+ assign gnt_nodes[Idx1+ 1 ] = gnt_nodes[Idx0] & sel[ 0 ] ;
346
313
end
347
314
// ////////////////////////////////////////////////////////////
348
315
end
@@ -354,8 +321,8 @@ module rr_arb_tree_lock #(
354
321
initial begin : p_assert
355
322
assert (NumIn)
356
323
else $error (1 , " Input must be at least one element wide." );
357
- assert (! (LockIn && ExtPrio ))
358
- else $error (1 ," Cannot use LockIn feature together with external ExtPrio. " );
324
+ assert (! (ExtPrio && ( REP > 1 ) ))
325
+ else $error (1 , " There is no reason to use REP > 1 with ExtPrio! " );
359
326
end
360
327
361
328
hot_one : assert property (
@@ -379,7 +346,7 @@ module rr_arb_tree_lock #(
379
346
else $error (1 , " Req out implies req in." );
380
347
381
348
lock2 : assert property (
382
- @ (posedge clk_i) disable iff (! rst_ni) lock_rr_q | - > idx_o == $past (idx_o))
349
+ @ (posedge clk_i) disable iff (! rst_ni) lock_rr_q[ 0 ] | - > idx_o == $past (idx_o))
383
350
else $error (1 , " Lock means idx_o does not change." );
384
351
`endif
385
352
`endif
0 commit comments