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: