-
Notifications
You must be signed in to change notification settings - Fork 81
/
soc_interconnect.sv
347 lines (320 loc) · 17.9 KB
/
soc_interconnect.sv
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
//-----------------------------------------------------------------------------
// Title : soc_interconnect
//-----------------------------------------------------------------------------
// File : soc_interconnect.sv
// Author : Manuel Eggimann <meggimann@iis.ee.ethz.ch>
// Created : 29.10.2020
//-----------------------------------------------------------------------------
// Description :
//
//-----------------------------------------------------------------------------
// Copyright (C) 2013-2020 ETH Zurich, University of Bologna
// Copyright and related rights are licensed under the Solderpad Hardware
// License, Version 0.51 (the "License"); you may not use this file except in
// compliance with the License. You may obtain a copy of the License at
// http://solderpad.org/licenses/SHL-0.51. Unless required by applicable law
// or agreed to in writing, software, hardware and materials distributed under
// this License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//-----------------------------------------------------------------------------
`include "tcdm_macros.svh"
`include "axi/typedef.svh"
`include "axi/assign.svh"
module soc_interconnect
import pkg_soc_interconnect::addr_map_rule_t;
import axi_pkg::xbar_cfg_t;
#(
// TCDM Bus Master Config
parameter int unsigned NR_MASTER_PORTS, // Master Ports to the SoC interconnect with access to all memory regions
parameter int unsigned NR_MASTER_PORTS_INTERLEAVED_ONLY, // Master ports with access restricted to only the interleaved
// ports (no axes to APB, AXI, or contiguous slaves) TCDM Bus
// Slave Config
// L2 Demux Addr rules
parameter int unsigned NR_ADDR_RULES_L2_DEMUX,
// Interleaved TCDM slave
parameter int unsigned NR_SLAVE_PORTS_INTERLEAVED,
parameter int unsigned NR_ADDR_RULES_SLAVE_PORTS_INTLVD,
// Contiguous TCDM slave
parameter int unsigned NR_SLAVE_PORTS_CONTIG,
parameter int unsigned NR_ADDR_RULES_SLAVE_PORTS_CONTIG,
// AXI Master ID Width
parameter int unsigned AXI_MASTER_ID_WIDTH = 1, // Not really used since we only connect TCDM masters to the
// axi_xbar with protocol converters. However, the value must not be zero.
// AXI Slaves
parameter int unsigned NR_AXI_SLAVE_PORTS,
parameter int unsigned NR_ADDR_RULES_AXI_SLAVE_PORTS,
localparam int unsigned AXI_SLAVE_ID_WIDTH = AXI_MASTER_ID_WIDTH + $clog2(NR_MASTER_PORTS), // The actual ID
// width of the AXI slaves is clog2(NR_AXI_MASTERS) larger than the master id width since the
// axi_mux in the XBAR will append an identificatoin tag to the outgoing transactions
// towards the axi slaves so it can backroute the responses
parameter int unsigned AXI_USER_WIDTH
)
(
input logic clk_i,
input logic rst_ni,
input logic test_en_i, // 0 Normal operation, 1 put sub-IPs into testmode (bypass clock gates)
XBAR_TCDM_BUS.Slave master_ports[NR_MASTER_PORTS],
XBAR_TCDM_BUS.Slave master_ports_interleaved_only[NR_MASTER_PORTS_INTERLEAVED_ONLY],
input addr_map_rule_t[NR_ADDR_RULES_L2_DEMUX-1:0] addr_space_l2_demux,
//Interleaved Slave
input addr_map_rule_t[NR_ADDR_RULES_SLAVE_PORTS_INTLVD-1:0] addr_space_interleaved,
XBAR_TCDM_BUS.Master interleaved_slaves[NR_SLAVE_PORTS_INTERLEAVED],
//Contiguous Slave
input addr_map_rule_t[NR_ADDR_RULES_SLAVE_PORTS_CONTIG-1:0] addr_space_contiguous,
XBAR_TCDM_BUS.Master contiguous_slaves[NR_SLAVE_PORTS_CONTIG],
//AXI Slave
input addr_map_rule_t [NR_ADDR_RULES_AXI_SLAVE_PORTS-1:0] addr_space_axi,
AXI_BUS.Master axi_slaves[NR_AXI_SLAVE_PORTS] // AXI_ID width must be
// at least clog2(NR_AXI_SLAVES)
);
// Internal Parameters
// Do **NOT** change
localparam int unsigned BUS_DATA_WIDTH = 32;
localparam int unsigned BUS_ADDR_WIDTH = 32;
// Internal Wiring Signals
XBAR_TCDM_BUS l2_demux_2_interleaved_xbar[NR_MASTER_PORTS]();
XBAR_TCDM_BUS l2_demux_2_contiguous_xbar[NR_MASTER_PORTS]();
XBAR_TCDM_BUS l2_demux_2_axi_bridge[NR_MASTER_PORTS]();
//////////////////////
// L2 Demultiplexer //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is the first stage of the interconnect. For every master, transactions are multiplexed between three //
// different target slaves. The first slave port routes to the axi crossbar, the second slave port routes //
// to the contiguous crossbar and the third slave port connects to the interleaved crossbar. //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
XBAR_TCDM_BUS l2_demux_slaves[NR_MASTER_PORTS*3]();
for (genvar i = 0; i < NR_MASTER_PORTS; i++) begin : gen_l2_demux
`TCDM_ASSIGN_INTF(l2_demux_2_axi_bridge[i], l2_demux_slaves[3*i + 0]);
`TCDM_ASSIGN_INTF(l2_demux_2_contiguous_xbar[i], l2_demux_slaves[3*i + 1]);
`TCDM_ASSIGN_INTF(l2_demux_2_interleaved_xbar[i], l2_demux_slaves[3*i + 2]);
tcdm_demux #(
.NR_OUTPUTS ( 3 ),
.NR_ADDR_MAP_RULES ( NR_ADDR_RULES_L2_DEMUX )
) i_l2_demux(
.clk_i,
.rst_ni,
.test_en_i,
.addr_map_rules ( addr_space_l2_demux ),
.master_port ( master_ports[i] ),
.slave_ports ( l2_demux_slaves[3*i:3*(i+1)-1] )
);
end
///////////////////////////////////////
// Interleaved only address checkers //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The following code checks, that no interleaved-only master is trying to access address space outside the //
// interleaved memory region. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
XBAR_TCDM_BUS master_ports_interleaved_only_checked[NR_MASTER_PORTS_INTERLEAVED_ONLY]();
XBAR_TCDM_BUS err_demux_slaves[NR_MASTER_PORTS_INTERLEAVED_ONLY*2]();
for (genvar i = 0; i < NR_MASTER_PORTS_INTERLEAVED_ONLY; i++) begin : gen_interleaved_only_err_checkers
`TCDM_ASSIGN_INTF(master_ports_interleaved_only_checked[i], err_demux_slaves[2*i + 1]);
// Workaround for genus (doesn't seem to like references interface
// arrays in port connections so we assign it to a scalar interface instance)
XBAR_TCDM_BUS err_slave();
`TCDM_ASSIGN_INTF(err_slave, err_demux_slaves[2*i + 0]);
//The tcdm demux will route all transaction that do not match any addr rule to port 0 (which we connect to an
//error slave)
tcdm_demux #(
.NR_OUTPUTS ( 2 ),
.NR_ADDR_MAP_RULES ( NR_ADDR_RULES_SLAVE_PORTS_INTLVD )
) i_err_demux(
.clk_i,
.rst_ni,
.test_en_i,
.addr_map_rules ( addr_space_interleaved ),
.master_port ( master_ports_interleaved_only[i] ),
.slave_ports ( err_demux_slaves[2*i:2*(i+1)-1] )
);
tcdm_error_slave #(
.ERROR_RESPONSE ( 32'hBADACCE5 )
) i_error_slave_interleaved (
.clk_i,
.rst_ni,
.slave ( err_slave )
);
end
//////////////////////////
// Interleaved Crossbar //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is a fully connected crossbar with combinational arbitration (logarithmic Inteconnect). It arbitrates //
// from the master ports from the L2 demultiplexer and the interleaved-only master ports (ports that do not have //
// access to the other address spaces) to the TCDM slaves with address interleaving. That is, the least //
// significant **word address** bits are used to select the slave port. This results in a more equal load on the //
// SRAM banks when the master access memory regions in a sequential manner. EVERY SLAVE IS EXPECTED TO HAVE //
// CONSTANT LATENCY OF 1 CYCLE. Slaves that cannot respond within a single cycle must appropriately delay the //
// assertion of the gnt (grant) signal. Asserting grant without asserting r_valid in the next cycle results in //
// undefined behavior. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Concatenate the l2 demux master port array and the interleaved only port array
XBAR_TCDM_BUS interleaved_masters[NR_MASTER_PORTS+NR_MASTER_PORTS_INTERLEAVED_ONLY]();
//Synopsys 2019.3 has a bug; It doesn't handle expressions for array indices on the left-hand side of assignments.
// E.g. assign a[param+i] = b[i] doesn't work, but assign a[i] = b[i-param] does.
// This is a verbose workaround for it. The next couple of ugly macro magic unpacks each interface into individual
// signal arrays, performs the assignments to the interface and packs the signal back to an array of interfaces.
`TCDM_EXPLODE_ARRAY_DECLARE(interleaved_masters, NR_MASTER_PORTS+NR_MASTER_PORTS_INTERLEAVED_ONLY)
for (genvar i = 0; i < NR_MASTER_PORTS + NR_MASTER_PORTS_INTERLEAVED_ONLY; i++) begin
`TCDM_SLAVE_EXPLODE(interleaved_masters[i], interleaved_masters, [i])
end
`TCDM_EXPLODE_ARRAY_DECLARE(l2_demux_2_interleaved_xbar, NR_MASTER_PORTS)
for (genvar i = 0; i < NR_MASTER_PORTS; i++) begin
`TCDM_MASTER_EXPLODE(l2_demux_2_interleaved_xbar[i], l2_demux_2_interleaved_xbar, [i])
`TCDM_ASSIGN(interleaved_masters, [i], l2_demux_2_interleaved_xbar, [i])
end
`TCDM_EXPLODE_ARRAY_DECLARE(master_ports_interleaved_only_checked, NR_MASTER_PORTS_INTERLEAVED_ONLY)
for (genvar i = 0; i < NR_MASTER_PORTS_INTERLEAVED_ONLY; i++) begin
`TCDM_MASTER_EXPLODE(master_ports_interleaved_only_checked[i], master_ports_interleaved_only_checked, [i])
`TCDM_ASSIGN(interleaved_masters, [NR_MASTER_PORTS + i], master_ports_interleaved_only_checked, [i])
end
interleaved_crossbar #(
.NR_MASTER_PORTS ( NR_MASTER_PORTS+NR_MASTER_PORTS_INTERLEAVED_ONLY ),
.NR_SLAVE_PORTS ( NR_SLAVE_PORTS_INTERLEAVED )
) i_interleaved_xbar(
// Interfaces
.master_ports ( interleaved_masters ),
.slave_ports ( interleaved_slaves ),
// Inputs
.clk_i,
.rst_ni,
.test_en_i
);
/////////////////////////
// Contiguous Crossbar //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This is a fully connected crossbar with combinational arbitration (logarithmic Inteconnect). Internally, there //
// is an address decoder that matches each master_port address against a number of address range to output port //
// mapping rules. Addresses not matching any of the address mapping rules will end up on a default port that //
// always grants the request, raises the opc line for one cycle and in the case of a read acces, responds with //
// the word 0xBADACCE5. EVERY SLAVE IS EXPECTED TO HAVE CONSTANT LATENCY OF 1 CYCLE. Slaves that cannot respond //
// within a single cycle must appropriately delay the assertion of the gnt (grant) signal. Asserting grant //
// without asserting r_valid in the next cycle results in undefined behavior. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
XBAR_TCDM_BUS error_slave();
contiguous_crossbar #(
.NR_MASTER_PORTS ( NR_MASTER_PORTS ),
.NR_SLAVE_PORTS ( NR_SLAVE_PORTS_CONTIG ),
.NR_ADDR_RULES ( NR_ADDR_RULES_SLAVE_PORTS_CONTIG )
) i_contiguous_xbar(
// Interfaces
.master_ports ( l2_demux_2_contiguous_xbar ),
.slave_ports ( contiguous_slaves ),
.error_port ( error_slave ),
.addr_rules ( addr_space_contiguous ),
// Inputs
.clk_i,
.rst_ni,
.test_en_i
);
//Error Slave
// This dummy slave is responsible to generate the buserror described above
tcdm_error_slave #(
.ERROR_RESPONSE(32'hBADACCE5)
) i_error_slave_contig_xbar (
.clk_i,
.rst_ni,
.slave(error_slave)
);
////////////////////////
// TCDM to AXI Bridge //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Instantiate a TCDM to AXI protocol converter for each master port from the L2 demultiplexer. The converter //
// converts one 32-bit TCDM port to one 32-bit AXI port. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
AXI_BUS #(
.AXI_ADDR_WIDTH ( 32 ),
.AXI_DATA_WIDTH ( 32 ),
.AXI_ID_WIDTH ( AXI_MASTER_ID_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) axi_bridge_2_axi_xbar[NR_MASTER_PORTS]();
`AXI_TYPEDEF_ALL(axi_mgr, logic[31:0], logic[AXI_MASTER_ID_WIDTH-1:0], logic[31:0], logic[3:0], logic[AXI_USER_WIDTH-1:0])
axi_mgr_req_t [NR_MASTER_PORTS-1:0] axi_bridge_2_axi_xbar_reqs;
axi_mgr_resp_t [NR_MASTER_PORTS-1:0] axi_bridge_2_axi_xbar_resps;
for (genvar i = 0; i < NR_MASTER_PORTS; i++) begin : gen_tcdm_2_axi_bridge
axi_from_mem #(
.MemAddrWidth ( 32 ),
.AxiAddrWidth ( 32 ),
.DataWidth ( 32 ),
.MaxRequests ( 2 ),
.AxiProt ( 3'b0 ),
.axi_req_t ( axi_mgr_req_t ),
.axi_rsp_t ( axi_mgr_resp_t )
) i_lint2axi_bridge (
.clk_i,
.rst_ni,
.mem_req_i ( l2_demux_2_axi_bridge[i].req ),
.mem_addr_i ( l2_demux_2_axi_bridge[i].add ),
.mem_we_i ( ~l2_demux_2_axi_bridge[i].wen ),
.mem_wdata_i ( l2_demux_2_axi_bridge[i].wdata ),
.mem_be_i ( l2_demux_2_axi_bridge[i].be ),
.mem_gnt_o ( l2_demux_2_axi_bridge[i].gnt ),
.mem_rsp_valid_o ( l2_demux_2_axi_bridge[i].r_valid ),
.mem_rsp_rdata_o ( l2_demux_2_axi_bridge[i].r_rdata ),
.mem_rsp_error_o ( l2_demux_2_axi_bridge[i].r_opc ),
.slv_aw_cache_i ( '0 ),
.slv_ar_cache_i ( '0 ),
.axi_req_o ( axi_bridge_2_axi_xbar_reqs[i] ),
.axi_rsp_i ( axi_bridge_2_axi_xbar_resps[i] )
);
`AXI_ASSIGN_FROM_REQ(axi_bridge_2_axi_xbar[i], axi_bridge_2_axi_xbar_reqs[i])
`AXI_ASSIGN_TO_RESP(axi_bridge_2_axi_xbar_resps[i], axi_bridge_2_axi_xbar[i])
end
///////////////////
// AXI4 Crossbar //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// The AXI crossbar accepts a set of address to slave port mapping rules (addr_map_i) and decodes the transaction //
// address accordingly. Illegal addresses that do not map to any defined address space are anaswered with a //
// decode error and Read Responses contain the data 0xBADCAB1E. Check the axi_xbar documentation for more //
// information. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
localparam xbar_cfg_t AXI_XBAR_CFG = '{
NoSlvPorts: NR_MASTER_PORTS,
NoMstPorts: NR_AXI_SLAVE_PORTS,
MaxMstTrans: 1, //The TCDM ports do not support
//outstanding transactiions anyways
MaxSlvTrans: 4, //Allow up to 4 in-flight transactions
//per slave port
FallThrough: 1, //Use the reccomended default config
LatencyMode: axi_pkg::MuxAw | axi_pkg::MuxAr | axi_pkg::MuxW,
PipelineStages: 0,
AxiIdWidthSlvPorts: AXI_MASTER_ID_WIDTH,
AxiIdUsedSlvPorts: AXI_MASTER_ID_WIDTH,
UniqueIds: 0,
AxiAddrWidth: BUS_ADDR_WIDTH,
AxiDataWidth: BUS_DATA_WIDTH,
NoAddrRules: NR_ADDR_RULES_AXI_SLAVE_PORTS
};
//Reverse interface array ordering since axi_xbar uses big-endian ordering of the arrays
AXI_BUS #(
.AXI_ADDR_WIDTH (32 ),
.AXI_DATA_WIDTH (32 ),
.AXI_ID_WIDTH (AXI_MASTER_ID_WIDTH ),
.AXI_USER_WIDTH (AXI_USER_WIDTH )
) axi_bridge_2_axi_xbar_reversed[NR_MASTER_PORTS-1:0]();
AXI_BUS #(
.AXI_ADDR_WIDTH ( 32 ),
.AXI_DATA_WIDTH ( 32 ),
.AXI_ID_WIDTH ( AXI_SLAVE_ID_WIDTH ),
.AXI_USER_WIDTH ( AXI_USER_WIDTH )
) axi_slaves_reversed[NR_AXI_SLAVE_PORTS-1:0]();
for (genvar i = 0; i < NR_MASTER_PORTS; i++) begin
`AXI_ASSIGN(axi_bridge_2_axi_xbar_reversed[i], axi_bridge_2_axi_xbar[i])
end
for (genvar i = 0; i < NR_AXI_SLAVE_PORTS; i++) begin
`AXI_ASSIGN(axi_slaves[i], axi_slaves_reversed[i])
end
axi_xbar_intf # (
.AXI_USER_WIDTH ( AXI_USER_WIDTH ),
.Cfg ( AXI_XBAR_CFG ),
.rule_t ( addr_map_rule_t )
) i_axi_xbar (
.clk_i,
.rst_ni,
.test_i ( test_en_i ),
.slv_ports ( axi_bridge_2_axi_xbar_reversed ),
.mst_ports ( axi_slaves_reversed ),
.addr_map_i ( addr_space_axi ),
.en_default_mst_port_i ( '0 ),
.default_mst_port_i ( '0 )
);
endmodule : soc_interconnect