blob: 8ed2a7c20dc09bcc3da524d75b43fe9254cc15fe [file] [log] [blame]
Timothy Chen79a99a02022-04-21 16:07:02 -07001// Copyright lowRISC contributors.
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4//
5// This is a wrapper module that instantiates two prim_aribter_tree modules.
6// The reason for two is similar to modules such as prim_count/prim_lfsr where
7// we use spatial redundancy to ensure the arbitration results are not altered.
8//
9// Note there are limits to this check, as the inputs to the duplicated arbiter
10// is still a single lane. So an upstream attack can defeat this module. The
11// duplication merely protects against attacks directly on the arbiter.
12
13`include "prim_assert.sv"
14
15module prim_arbiter_tree_dup #(
16 parameter int N = 8,
17 parameter int DW = 32,
18
19 // Configurations
20 // EnDataPort: {0, 1}, if 0, input data will be ignored
21 parameter bit EnDataPort = 1,
22
Timothy Chenf749e432022-05-04 14:16:49 -070023 // if arbiter has fixed priority
24 parameter bit FixedArb = 0,
25
Timothy Chen79a99a02022-04-21 16:07:02 -070026 // Derived parameters
27 localparam int IdxW = $clog2(N)
28) (
29 input clk_i,
30 input rst_ni,
31
32 input req_chk_i, // Used for gating assertions. Drive to 1 during normal
33 // operation.
34 input [ N-1:0] req_i,
35 input [DW-1:0] data_i [N],
36 output logic [ N-1:0] gnt_o,
37 output logic [IdxW-1:0] idx_o,
38
39 output logic valid_o,
40 output logic [DW-1:0] data_o,
41 input ready_i,
42 output logic err_o
43);
44
45 localparam int ArbInstances = 2;
46
47 //typedef struct packed {
48 // logic [N-1:0] req;
49 // logic [N-1:0][DW-1:0] data;
50 //} arb_inputs_t;
51
52 typedef struct packed {
53 logic valid;
54 logic [N-1:0] gnt;
55 logic [IdxW-1:0] idx;
56 logic [DW-1:0] data;
57 } arb_outputs_t;
58
59 // buffer up the inputs separately for each instance
60 //arb_inputs_t arb_in;
61 //arb_inputs_t [ArbInstances-1:0] arb_input_buf;
62 arb_outputs_t [ArbInstances-1:0] arb_output_buf;
63
64 for (genvar i = 0; i < ArbInstances; i++) begin : gen_input_bufs
65 logic [N-1:0] req_buf;
66 prim_buf #(
67 .Width(N)
68 ) u_req_buf (
69 .in_i(req_i),
70 .out_o(req_buf)
71 );
72
73 logic [DW-1:0] data_buf [N];
74 for (genvar j = 0; j < N; j++) begin : gen_data_bufs
75 prim_buf #(
76 .Width(DW)
77 ) u_dat_buf (
78 .in_i(data_i[j]),
79 .out_o(data_buf[j])
80 );
81 end
82
Timothy Chenf749e432022-05-04 14:16:49 -070083 if (FixedArb) begin : gen_fixed_arbiter
84 prim_arbiter_fixed #(
85 .N(N),
86 .DW(DW),
87 .EnDataPort(EnDataPort)
88 ) u_arb (
89 .clk_i,
90 .rst_ni,
91 .req_i(req_buf),
92 .data_i(data_buf),
93 .gnt_o(arb_output_buf[i].gnt),
94 .idx_o(arb_output_buf[i].idx),
95 .valid_o(arb_output_buf[i].valid),
96 .data_o(arb_output_buf[i].data),
97 .ready_i
98 );
99 logic unused_req_chk;
100 assign unused_req_chk = req_chk_i;
101
102 end else begin : gen_rr_arbiter
103 prim_arbiter_tree #(
104 .N(N),
105 .DW(DW),
106 .EnDataPort(EnDataPort)
107 ) u_arb (
108 .clk_i,
109 .rst_ni,
110 .req_chk_i,
111 .req_i(req_buf),
112 .data_i(data_buf),
113 .gnt_o(arb_output_buf[i].gnt),
114 .idx_o(arb_output_buf[i].idx),
115 .valid_o(arb_output_buf[i].valid),
116 .data_o(arb_output_buf[i].data),
117 .ready_i
118 );
119 end
Timothy Chen79a99a02022-04-21 16:07:02 -0700120 end
121
122 // the last buffered position is sent out
123 assign gnt_o = arb_output_buf[ArbInstances-1].gnt;
124 assign idx_o = arb_output_buf[ArbInstances-1].idx;
125 assign valid_o = arb_output_buf[ArbInstances-1].valid;
126 assign data_o = arb_output_buf[ArbInstances-1].data;
127
128 // Check the last buffer index against all other instances
129 logic [ArbInstances-2:0] output_delta;
130
131 for (genvar i = 0; i < ArbInstances-1; i++) begin : gen_checks
132 assign output_delta[i] = arb_output_buf[ArbInstances-1] != arb_output_buf[i];
133 end
134
135 logic err_d, err_q;
136 // There is an error if anything ever disagrees
137 assign err_d = |output_delta;
138 always_ff @(posedge clk_i or negedge rst_ni) begin
139 if (!rst_ni) begin
140 err_q <= '0;
141 end else begin
142 err_q <= err_d | err_q;
143 end
144 end
145
146 assign err_o = err_q;
147
148endmodule // prim_arbiter_tree