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