Skip to content

Commit 77372c0

Browse files
author
Maurus Item
committed
Added internal redundancy option to lockable RR-Arbiter
1 parent 898ac27 commit 77372c0

File tree

5 files changed

+109
-136
lines changed

5 files changed

+109
-136
lines changed

rtl/time_redundancy/rr_arb_tree_lock.sv

+91-124
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
/// If it is `1'b1` two `lzc`, a masking logic stage and a two input multiplexer are instantiated.
4747
/// However these are small in respect of the data multiplexers needed, as the width of the `req_i`
4848
/// signal is usually less as than `DataWidth`.
49+
50+
`include "redundancy_cells/voters.svh"
51+
4952
module rr_arb_tree_lock #(
5053
/// Number of inputs to be arbitrated.
5154
parameter int unsigned NumIn = 64,
@@ -67,13 +70,6 @@ module rr_arb_tree_lock #(
6770
///
6871
/// Set to `1'b1` to treat req/gnt as vld/rdy.
6972
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,
7773
/// When set, ensures that throughput gets distributed evenly between all inputs.
7874
///
7975
/// Set to `1'b0` to disable.
@@ -83,18 +79,25 @@ module rr_arb_tree_lock #(
8379
parameter int unsigned IdxWidth = (NumIn > 32'd1) ? unsigned'($clog2(NumIn)) : 32'd1,
8480
/// Dependent parameter, do **not** overwrite.
8581
/// 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
8790
) (
8891
/// Clock, positive edge triggered.
8992
input logic clk_i,
9093
/// Asynchronous reset, active low.
9194
input logic rst_ni,
9295
/// 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,
9497
/// External round-robin priority.
9598
input idx_t rr_i,
9699
/// 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,
98101
/// Input requests arbitration.
99102
input logic [NumIn-1:0] req_i,
100103
/* verilator lint_off UNOPTFLAT */
@@ -117,7 +120,7 @@ module rr_arb_tree_lock #(
117120
`ifndef VERILATOR
118121
`ifndef XSIM
119122
// Default SVA reset
120-
default disable iff (!rst_ni || flush_i);
123+
default disable iff (!rst_ni || flush_i[0]);
121124
`endif
122125
`endif
123126
// pragma translate_on
@@ -133,86 +136,39 @@ module rr_arb_tree_lock #(
133136
localparam int unsigned NumLevels = unsigned'($clog2(NumIn));
134137

135138
/* 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
137140
DataType [2**NumLevels-2:0] data_nodes; // used to propagate the data
138141
logic [2**NumLevels-2:0] gnt_nodes; // used to propagate the grant to masters
139142
logic [2**NumLevels-2:0] req_nodes; // used to propagate the requests to slave
140143
/* lint_off */
141-
idx_t rr_q;
144+
idx_t [REP-1:0] rr_q;
142145
logic [NumIn-1:0] req_d;
143146

144147
// the final arbitration decision can be taken from the root of the tree
145148
assign req_o = req_nodes[0];
146149
assign data_o = data_nodes[0];
147-
assign idx_o = index_nodes[0];
150+
assign idx_o = index_nodes[0][0];
151+
148152

149153
if (ExtPrio) begin : gen_ext_rr
150-
assign rr_q = rr_i;
154+
assign rr_q[0] = rr_i;
151155
assign req_d = req_i;
152156
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;
174158

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;
205160

206161
idx_t next_idx;
207162

208163
if (FairArb) begin : gen_fair_arb
164+
209165
logic [NumIn-1:0] upper_mask, lower_mask;
210166
idx_t upper_idx, lower_idx;
211167
logic upper_empty, lower_empty;
212168

213169
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;
216172
end
217173

218174
lzc #(
@@ -235,45 +191,52 @@ module rr_arb_tree_lock #(
235191

236192
assign next_idx = upper_empty ? lower_idx : upper_idx;
237193
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);
239195
end
240196

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];
247205
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
249211
end
250212
end
251-
end
252213

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;
260218
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
262224
end
263225
end
264226
end
265-
266227
end
267228

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;
275234
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
277240
end
278241
end
279242
end
@@ -284,7 +247,7 @@ module rr_arb_tree_lock #(
284247
for (genvar level = 0; unsigned'(level) < NumLevels; level++) begin : gen_levels
285248
for (genvar l = 0; l < 2**level; l++) begin : gen_level
286249
// local select signal
287-
logic sel;
250+
logic [REP-1:0] sel;
288251
// index calcs
289252
localparam int unsigned Idx0 = 2**level-1+l;// current node
290253
localparam int unsigned Idx1 = 2**(level+1)-1+l*2;
@@ -294,55 +257,59 @@ module rr_arb_tree_lock #(
294257
// if two successive indices are still in the vector...
295258
if (unsigned'(l) * 2 < NumIn-1) begin : gen_reduce
296259

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
303268
end
269+
assign index_nodes[Idx0][r] = idx_t'(sel[r]);
304270
end
305271

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];
311276
end
312277
// if only the first index is still in the vector...
313278
if (unsigned'(l) * 2 == NumIn-1) begin : gen_first
314279
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;
316281
assign data_nodes[Idx0] = data_i[l*2];
317282
assign gnt_o[l*2] = gnt_nodes[Idx0] & (AxiVldRdy | req_d[l*2]);
318283
end
319284
// if index is out of range, fill up with zeros (will get pruned)
320285
if (unsigned'(l) * 2 > NumIn-1) begin : gen_out_of_range
321286
assign req_nodes[Idx0] = 1'b0;
322-
assign index_nodes[Idx0] = idx_t'('0);
287+
assign index_nodes[Idx0] = '0;
323288
assign data_nodes[Idx0] = DataType'('0);
324289
end
325290
//////////////////////////////////////////////////////////////
326291
// general case for other levels within the tree
327292
end else begin : gen_other_levels
328293

329294
// 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
335302
end
336-
end
337303

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
341308

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];
346313
end
347314
//////////////////////////////////////////////////////////////
348315
end
@@ -354,8 +321,8 @@ module rr_arb_tree_lock #(
354321
initial begin : p_assert
355322
assert(NumIn)
356323
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!");
359326
end
360327

361328
hot_one : assert property(
@@ -379,7 +346,7 @@ module rr_arb_tree_lock #(
379346
else $error (1, "Req out implies req in.");
380347

381348
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))
383350
else $error (1, "Lock means idx_o does not change.");
384351
`endif
385352
`endif

rtl/time_redundancy/time_DMR_end.sv

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ module time_DMR_end # (
7474
output logic ready_o,
7575

7676
// Signal for working with upstream Lockable RR Arbiter
77-
output logic lock_o,
77+
output logic [REP-1:0] lock_o,
7878

7979
// Downstream connection
8080
output DataType data_o,
@@ -270,7 +270,7 @@ module time_DMR_end # (
270270
`VOTEXX(REP, lock_v, lock_d);
271271
`VOTEXX(REP, counter_v, counter_d);
272272

273-
assign lock_o = lock_d[0];
273+
assign lock_o = lock_d;
274274

275275
// Default state
276276
for (genvar r = 0; r < REP; r++) begin: gen_lock_default_state

rtl/time_redundancy/time_TMR_end.sv

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ module time_TMR_end # (
7575
input logic ready_i,
7676

7777
// Signal for working with Lockable RR Arbiter
78-
output logic lock_o,
78+
output logic [REP-1:0] lock_o,
7979

8080
// Flag for External Error Counter
8181
output logic fault_detected_o
@@ -459,7 +459,7 @@ module time_TMR_end # (
459459
`VOTEXX(REP, lock_v, lock_d);
460460
`VOTEXX(REP, counter_v, counter_d);
461461

462-
assign lock_o = lock_d[0];
462+
assign lock_o = lock_d;
463463

464464
// Default state
465465
for (genvar r = 0; r < REP; r++) begin: gen_lock_default_state

0 commit comments

Comments
 (0)