../src/lowrisc_tlul_socket_m1_0.1/rtl/tlul_socket_m1.sv Cov: 90.1%
1: // 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: // TL-UL socket M:1 module
6: //
7: // Verilog parameters
8: // M: Number of host ports.
9: // HReqPass: M bit array to allow requests to pass through the host i
10: // FIFO with no clock delay if the request FIFO is empty. If
11: // 1'b0, at least one clock cycle of latency is created.
12: // Default is 1'b1.
13: // HRspPass: Same as HReqPass but for host response FIFO.
14: // HReqDepth: Mx4 bit array. bit[i*4+:4] is depth of host i request FIFO.
15: // Depth of zero is allowed if ReqPass is true. A maximum value
16: // of 16 is allowed, default is 2.
17: // HRspDepth: Same as HReqDepth but for host response FIFO.
18: // DReqPass: Same as HReqPass but for device request FIFO.
19: // DRspPass: Same as HReqPass but for device response FIFO.
20: // DReqDepth: Same as HReqDepth but for device request FIFO.
21: // DRspDepth: Same as HReqDepth but for device response FIFO.
22:
23: `include "prim_assert.sv"
24:
25: module tlul_socket_m1 #(
26: parameter int unsigned M = 4,
27: parameter bit [M-1:0] HReqPass = {M{1'b1}},
28: parameter bit [M-1:0] HRspPass = {M{1'b1}},
29: parameter bit [M*4-1:0] HReqDepth = {M{4'h2}},
30: parameter bit [M*4-1:0] HRspDepth = {M{4'h2}},
31: parameter bit DReqPass = 1'b1,
32: parameter bit DRspPass = 1'b1,
33: parameter bit [3:0] DReqDepth = 4'h2,
34: parameter bit [3:0] DRspDepth = 4'h2
35: ) (
36: input clk_i,
37: input rst_ni,
38:
39: input tlul_pkg::tl_h2d_t tl_h_i [M],
40: output tlul_pkg::tl_d2h_t tl_h_o [M],
41:
42: output tlul_pkg::tl_h2d_t tl_d_o,
43: input tlul_pkg::tl_d2h_t tl_d_i
44: );
45:
46: `ASSERT_INIT(maxM, M < 16)
47:
48:
49: // Signals
50: //
51: // tl_h_i/o[0] | tl_h_i/o[1] | ... | tl_h_i/o[M-1]
52: // | | |
53: // u_hostfifo[0] u_hostfifo[1] u_hostfifo[M-1]
54: // | | |
55: // hreq_fifo_o(i) / hrsp_fifo_i(i)
56: // ---------------------------------------
57: // | request/grant/req_data |
58: // | |
59: // | PRIM_ARBITER |
60: // | |
61: // | arb_valid / arb_ready / arb_data |
62: // ---------------------------------------
63: // |
64: // dreq_fifo_i / drsp_fifo_o
65: // |
66: // u_devicefifo
67: // |
68: // tl_d_o/i
69: //
70: // Required ID width to distinguish between host ports
71: // Used in response steering
72: localparam int unsigned IDW = top_pkg::TL_AIW;
73: localparam int unsigned STIDW = $clog2(M);
74:
75: tlul_pkg::tl_h2d_t hreq_fifo_o [M];
76: tlul_pkg::tl_d2h_t hrsp_fifo_i [M];
77:
78: logic [M-1:0] hrequest;
79: logic [M-1:0] hgrant;
80:
81: tlul_pkg::tl_h2d_t dreq_fifo_i;
82: tlul_pkg::tl_d2h_t drsp_fifo_o;
83:
84: logic arb_valid;
85: logic arb_ready;
86: tlul_pkg::tl_h2d_t arb_data;
87:
88: // Host Req/Rsp FIFO
89: for (genvar i = 0 ; i < M ; i++) begin : gen_host_fifo
90: tlul_pkg::tl_h2d_t hreq_fifo_i;
91:
92: // ID Shifting
93: logic [STIDW-1:0] reqid_sub;
94: logic [IDW-1:0] shifted_id;
95: assign reqid_sub = i; // can cause conversion error?
96: assign shifted_id = {
97: tl_h_i[i].a_source[0+:(IDW-STIDW)],
98: reqid_sub
99: };
100:
101: `ASSERT(idInRange, tl_h_i[i].a_valid |-> tl_h_i[i].a_source[IDW-1 -:STIDW] == '0)
102:
103: // assign not connected bits to nc_* signal to make lint happy
104: logic [IDW-1 : IDW-STIDW] unused_tl_h_source;
105: assign unused_tl_h_source = tl_h_i[i].a_source[IDW-1 -: STIDW];
106:
107: // Put shifted ID
108: assign hreq_fifo_i = '{
109: a_valid: tl_h_i[i].a_valid,
110: a_opcode: tl_h_i[i].a_opcode,
111: a_param: tl_h_i[i].a_param,
112: a_size: tl_h_i[i].a_size,
113: a_source: shifted_id,
114: a_address: tl_h_i[i].a_address,
115: a_mask: tl_h_i[i].a_mask,
116: a_data: tl_h_i[i].a_data,
117: a_user: tl_h_i[i].a_user,
118: d_ready: tl_h_i[i].d_ready
119: };
120:
121: tlul_fifo_sync #(
122: .ReqPass (HReqPass[i]),
123: .RspPass (HRspPass[i]),
124: .ReqDepth (HReqDepth[i*4+:4]),
125: .RspDepth (HRspDepth[i*4+:4]),
126: .SpareReqW (1)
127: ) u_hostfifo (
128: .clk_i,
129: .rst_ni,
130: .tl_h_i (hreq_fifo_i),
131: .tl_h_o (tl_h_o[i]),
132: .tl_d_o (hreq_fifo_o[i]),
133: .tl_d_i (hrsp_fifo_i[i]),
134: .spare_req_i (1'b0),
135: .spare_req_o (),
136: .spare_rsp_i (1'b0),
137: .spare_rsp_o ()
138: );
139: end
140:
141: // Device Req/Rsp FIFO
142: tlul_fifo_sync #(
143: .ReqPass (DReqPass),
144: .RspPass (DRspPass),
145: .ReqDepth (DReqDepth),
146: .RspDepth (DRspDepth),
147: .SpareReqW (1)
148: ) u_devicefifo (
149: .clk_i,
150: .rst_ni,
151: .tl_h_i (dreq_fifo_i),
152: .tl_h_o (drsp_fifo_o),
153: .tl_d_o (tl_d_o),
154: .tl_d_i (tl_d_i),
155: .spare_req_i (1'b0),
156: .spare_req_o (),
157: .spare_rsp_i (1'b0),
158: .spare_rsp_o ()
159: );
160:
161: // Request Arbiter
162: for (genvar i = 0 ; i < M ; i++) begin : gen_arbreqgnt
163: assign hrequest[i] = hreq_fifo_o[i].a_valid;
164: end
165:
166: assign arb_ready = drsp_fifo_o.a_ready;
167:
168: if (tlul_pkg::ArbiterImpl == "PPC") begin : gen_arb_ppc
169: prim_arbiter_ppc #(
170: .N (M),
171: .DW ($bits(tlul_pkg::tl_h2d_t))
172: ) u_reqarb (
173: .clk_i,
174: .rst_ni,
175: .req_i ( hrequest ),
176: .data_i ( hreq_fifo_o ),
177: .gnt_o ( hgrant ),
178: .idx_o ( ),
179: .valid_o ( arb_valid ),
180: .data_o ( arb_data ),
181: .ready_i ( arb_ready )
182: );
183: end else if (tlul_pkg::ArbiterImpl == "BINTREE") begin : gen_tree_arb
184: prim_arbiter_tree #(
185: .N (M),
186: .DW ($bits(tlul_pkg::tl_h2d_t))
187: ) u_reqarb (
188: .clk_i,
189: .rst_ni,
190: .req_i ( hrequest ),
191: .data_i ( hreq_fifo_o ),
192: .gnt_o ( hgrant ),
193: .idx_o ( ),
194: .valid_o ( arb_valid ),
195: .data_o ( arb_data ),
196: .ready_i ( arb_ready )
197: );
198: end else begin : gen_unknown
199: `ASSERT_INIT(UnknownArbImpl_A, 0)
200: end
201:
202: logic [ M-1:0] hfifo_rspvalid;
203: logic [ M-1:0] dfifo_rspready;
204: logic [IDW-1:0] hfifo_rspid;
205: logic dfifo_rspready_merged;
206:
207: // arb_data --> dreq_fifo_i
208: // dreq_fifo_i.hd_rspready <= dfifo_rspready
209:
210: assign dfifo_rspready_merged = |dfifo_rspready;
211: assign dreq_fifo_i = '{
212: a_valid: arb_valid,
213: a_opcode: arb_data.a_opcode,
214: a_param: arb_data.a_param,
215: a_size: arb_data.a_size,
216: a_source: arb_data.a_source,
217: a_address: arb_data.a_address,
218: a_mask: arb_data.a_mask,
219: a_data: arb_data.a_data,
220: a_user: arb_data.a_user,
221:
222: d_ready: dfifo_rspready_merged
223: };
224:
225: // Response ID steering
226: // drsp_fifo_o --> hrsp_fifo_i[i]
227:
228: // Response ID shifting before put into host fifo
229: assign hfifo_rspid = {
230: {STIDW{1'b0}},
231: drsp_fifo_o.d_source[IDW-1:STIDW]
232: };
233: for (genvar i = 0 ; i < M ; i++) begin : gen_idrouting
234: assign hfifo_rspvalid[i] = drsp_fifo_o.d_valid &
235: (drsp_fifo_o.d_source[0+:STIDW] == i);
236: assign dfifo_rspready[i] = hreq_fifo_o[i].d_ready &
237: (drsp_fifo_o.d_source[0+:STIDW] == i) &
238: drsp_fifo_o.d_valid;
239:
240: assign hrsp_fifo_i[i] = '{
241: d_valid: hfifo_rspvalid[i],
242: d_opcode: drsp_fifo_o.d_opcode,
243: d_param: drsp_fifo_o.d_param,
244: d_size: drsp_fifo_o.d_size,
245: d_source: hfifo_rspid,
246: d_sink: drsp_fifo_o.d_sink,
247: d_data: drsp_fifo_o.d_data,
248: d_user: drsp_fifo_o.d_user,
249: d_error: drsp_fifo_o.d_error,
250: a_ready: hgrant[i]
251: };
252: end
253:
254: // this assertion fails when rspid[0+:STIDW] not in [0..M-1]
255: `ASSERT(rspIdInRange, drsp_fifo_o.d_valid |->
256: drsp_fifo_o.d_source[0+:STIDW] >= 0 && drsp_fifo_o.d_source[0+:STIDW] < M)
257:
258: endmodule
259: