../src/lowrisc_tlul_socket_1n_0.1/rtl/tlul_socket_1n.sv Cov: 100%

   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 1:N module
   6: //
   7: // configuration settings
   8: //   device_count: 4
   9: //
  10: // Verilog parameters
  11: //   HReqPass:      if 1 then host requests can pass through on empty fifo,
  12: //                  default 1
  13: //   HRspPass:      if 1 then host responses can pass through on empty fifo,
  14: //                  default 1
  15: //   DReqPass:      (one per device_count) if 1 then device i requests can
  16: //                  pass through on empty fifo, default 1
  17: //   DRspPass:      (one per device_count) if 1 then device i responses can
  18: //                  pass through on empty fifo, default 1
  19: //   HReqDepth:     Depth of host request FIFO, default 2
  20: //   HRspDepth:     Depth of host response FIFO, default 2
  21: //   DReqDepth:     (one per device_count) Depth of device i request FIFO,
  22: //                  default 2
  23: //   DRspDepth:     (one per device_count) Depth of device i response FIFO,
  24: //                  default 2
  25: //
  26: // Requests must stall to one slave until all responses from other slaves
  27: // have returned.  Need to keep a counter of all outstanding requests and
  28: // wait until that counter is zero before switching slaves.
  29: //
  30: // This module will return a request error if the input value of 'dev_select'
  31: // is not within the range 0..N-1. Thus the instantiator of the socket
  32: // can indicate error by any illegal value of dev_select. 4'b1111 is
  33: // recommended for visibility
  34: //
  35: // The maximum value of N is 15
  36: 
  37: `include "prim_assert.sv"
  38: 
  39: module tlul_socket_1n #(
  40:   parameter int unsigned  N         = 4,
  41:   parameter bit           HReqPass  = 1'b1,
  42:   parameter bit           HRspPass  = 1'b1,
  43:   parameter bit [N-1:0]   DReqPass  = {N{1'b1}},
  44:   parameter bit [N-1:0]   DRspPass  = {N{1'b1}},
  45:   parameter bit [3:0]     HReqDepth = 4'h2,
  46:   parameter bit [3:0]     HRspDepth = 4'h2,
  47:   parameter bit [N*4-1:0] DReqDepth = {N{4'h2}},
  48:   parameter bit [N*4-1:0] DRspDepth = {N{4'h2}},
  49:   localparam int unsigned NWD       = $clog2(N+1) // derived parameter
  50: ) (
  51:   input                     clk_i,
  52:   input                     rst_ni,
  53:   input  tlul_pkg::tl_h2d_t tl_h_i,
  54:   output tlul_pkg::tl_d2h_t tl_h_o,
  55:   output tlul_pkg::tl_h2d_t tl_d_o    [N],
  56:   input  tlul_pkg::tl_d2h_t tl_d_i    [N],
  57:   input  [NWD-1:0]          dev_select
  58: );
  59: 
  60:   `ASSERT_INIT(maxN, N < 16)
  61: 
  62:   // Since our steering is done after potential FIFOing, we need to
  63:   // shove our device select bits into spare bits of reqfifo
  64: 
  65:   // instantiate the host fifo, create intermediate bus 't'
  66: 
  67:   // FIFO'd version of device select
  68:   logic [NWD-1:0] dev_select_t;
  69: 
  70:   tlul_pkg::tl_h2d_t   tl_t_o;
  71:   tlul_pkg::tl_d2h_t   tl_t_i;
  72: 
  73:   tlul_fifo_sync #(
  74:     .ReqPass(HReqPass),
  75:     .RspPass(HRspPass),
  76:     .ReqDepth(HReqDepth),
  77:     .RspDepth(HRspDepth),
  78:     .SpareReqW(NWD)
  79:   ) fifo_h (
  80:     .clk_i,
  81:     .rst_ni,
  82:     .tl_h_i,
  83:     .tl_h_o,
  84:     .tl_d_o     (tl_t_o),
  85:     .tl_d_i     (tl_t_i),
  86:     .spare_req_i (dev_select),
  87:     .spare_req_o (dev_select_t),
  88:     .spare_rsp_i (1'b0),
  89:     .spare_rsp_o ());
  90: 
  91: 
  92:   // We need to keep track of how many requests are outstanding,
  93:   // and to which device. New requests are compared to this and
  94:   // stall until that number is zero.
  95: 
  96:   logic [7:0]     num_req_outstanding;
  97:   logic [NWD-1:0] dev_select_outstanding;
  98:   logic           hold_all_requests;
  99:   logic           accept_t_req, accept_t_rsp;
 100: 
 101:   assign  accept_t_req = tl_t_o.a_valid & tl_t_i.a_ready;
 102:   assign  accept_t_rsp = tl_t_i.d_valid & tl_t_o.d_ready;
 103: 
 104:   always_ff @(posedge clk_i or negedge rst_ni) begin
 105:     if (!rst_ni) begin
 106:       num_req_outstanding <= 8'h0;
 107:       dev_select_outstanding <= '0;
 108:     end else if (accept_t_req) begin
 109:       if (!accept_t_rsp) begin
 110:         `ASSERT_I(NotOverflowed_A, num_req_outstanding != '1)
 111:         num_req_outstanding <= num_req_outstanding + 8'h1;
 112:       end
 113:       dev_select_outstanding <= dev_select_t;
 114:     end else if (accept_t_rsp) begin
 115:       num_req_outstanding <= num_req_outstanding - 8'h1;
 116:     end
 117:   end
 118: 
 119:   assign hold_all_requests =
 120:       (num_req_outstanding != 8'h0) &
 121:       (dev_select_t != dev_select_outstanding);
 122: 
 123:   // Make N copies of 't' request side with modified reqvalid, call
 124:   // them 'u[0]' .. 'u[n-1]'.
 125: 
 126:   tlul_pkg::tl_h2d_t   tl_u_o [N+1];
 127:   tlul_pkg::tl_d2h_t   tl_u_i [N+1];
 128: 
 129:   for (genvar i = 0 ; i < N ; i++) begin : gen_u_o
 130:     assign tl_u_o[i].a_valid   = tl_t_o.a_valid &
 131:                                  (dev_select_t == NWD'(i)) &
 132:                                  ~hold_all_requests;
 133:     assign tl_u_o[i].a_opcode  = tl_t_o.a_opcode;
 134:     assign tl_u_o[i].a_param   = tl_t_o.a_param;
 135:     assign tl_u_o[i].a_size    = tl_t_o.a_size;
 136:     assign tl_u_o[i].a_source  = tl_t_o.a_source;
 137:     assign tl_u_o[i].a_address = tl_t_o.a_address;
 138:     assign tl_u_o[i].a_mask    = tl_t_o.a_mask;
 139:     assign tl_u_o[i].a_data    = tl_t_o.a_data;
 140:     assign tl_u_o[i].a_user    = tl_t_o.a_user;
 141:   end
 142: 
 143:   tlul_pkg::tl_d2h_t tl_t_p ;
 144: 
 145:   // for the returning reqready, only look at the slave we're addressing
 146:   logic hfifo_reqready;
 147:   always_comb begin
 148:     hfifo_reqready = tl_u_i[N].a_ready; // default to error
 149:     for (int idx = 0 ; idx < N ; idx++) begin
 150:       //if (dev_select_outstanding == NWD'(idx)) hfifo_reqready = tl_u_i[idx].a_ready;
 151:       if (dev_select_t == NWD'(idx)) hfifo_reqready = tl_u_i[idx].a_ready;
 152:     end
 153:     if (hold_all_requests) hfifo_reqready = 1'b0;
 154:   end
 155:   // Adding a_valid as a qualifier. This prevents the a_ready from having unknown value
 156:   // when the address is unknown and the Host TL-UL FIFO is bypass mode.
 157:   assign tl_t_i.a_ready = tl_t_o.a_valid & hfifo_reqready;
 158: 
 159:   always_comb begin
 160:     tl_t_p = tl_u_i[N];
 161:     for (int idx = 0 ; idx < N ; idx++) begin
 162:       if (dev_select_outstanding == NWD'(idx)) tl_t_p = tl_u_i[idx];
 163:     end
 164:   end
 165:   assign tl_t_i.d_valid  = tl_t_p.d_valid ;
 166:   assign tl_t_i.d_opcode = tl_t_p.d_opcode;
 167:   assign tl_t_i.d_param  = tl_t_p.d_param ;
 168:   assign tl_t_i.d_size   = tl_t_p.d_size  ;
 169:   assign tl_t_i.d_source = tl_t_p.d_source;
 170:   assign tl_t_i.d_sink   = tl_t_p.d_sink  ;
 171:   assign tl_t_i.d_data   = tl_t_p.d_data  ;
 172:   assign tl_t_i.d_user   = tl_t_p.d_user  ;
 173:   assign tl_t_i.d_error  = tl_t_p.d_error ;
 174: 
 175: 
 176:   // accept responses from devices when selected if upstream is accepting
 177:   for (genvar i = 0 ; i < N+1 ; i++) begin : gen_u_o_d_ready
 178:     assign tl_u_o[i].d_ready = tl_t_o.d_ready;
 179:   end
 180: 
 181:   // finally instantiate all device FIFOs and the error responder
 182:   for (genvar i = 0 ; i < N ; i++) begin : gen_dfifo
 183:     tlul_fifo_sync #(
 184:       .ReqPass(DReqPass[i]),
 185:       .RspPass(DRspPass[i]),
 186:       .ReqDepth(DReqDepth[i*4+:4]),
 187:       .RspDepth(DRspDepth[i*4+:4])
 188:     ) fifo_d (
 189:       .clk_i,
 190:       .rst_ni,
 191:       .tl_h_i      (tl_u_o[i]),
 192:       .tl_h_o      (tl_u_i[i]),
 193:       .tl_d_o      (tl_d_o[i]),
 194:       .tl_d_i      (tl_d_i[i]),
 195:       .spare_req_i (1'b0),
 196:       .spare_req_o (),
 197:       .spare_rsp_i (1'b0),
 198:       .spare_rsp_o ());
 199:   end
 200: 
 201:   assign tl_u_o[N].a_valid     = tl_t_o.a_valid &
 202:                                  (dev_select_t == NWD'(N)) &
 203:                                  ~hold_all_requests;
 204:   assign tl_u_o[N].a_opcode    = tl_t_o.a_opcode;
 205:   assign tl_u_o[N].a_param     = tl_t_o.a_param;
 206:   assign tl_u_o[N].a_size      = tl_t_o.a_size;
 207:   assign tl_u_o[N].a_source    = tl_t_o.a_source;
 208:   assign tl_u_o[N].a_address   = tl_t_o.a_address;
 209:   assign tl_u_o[N].a_mask      = tl_t_o.a_mask;
 210:   assign tl_u_o[N].a_data      = tl_t_o.a_data;
 211:   assign tl_u_o[N].a_user      = tl_t_o.a_user;
 212:   tlul_err_resp err_resp (
 213:     .clk_i,
 214:     .rst_ni,
 215:     .tl_h_i     (tl_u_o[N]),
 216:     .tl_h_o     (tl_u_i[N]));
 217: 
 218: endmodule
 219: