../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: