../src/lowrisc_tlul_adapter_host_0.1/rtl/tlul_adapter_host.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: // tlul_adapter (Host adapter) converts basic req/grant/rvalid into TL-UL interface. If
   6: // MAX_REQS == 1 it is purely combinational logic. If MAX_REQS > 1 flops are required.
   7: //
   8: // The host driving the adapter is responsible for ensuring it doesn't have more requests in flight
   9: // than the specified MAX_REQS.
  10: //
  11: // The outgoing address is always word aligned. The access size is always the word size (as
  12: // specified by TL_DW). For write accesses that occupy all lanes the operation is PutFullData,
  13: // otherwise it is PutPartialData, mask is generated from be_i. For reads all lanes are enabled as
  14: // required by TL-UL (every bit in mask set).
  15: //
  16: // When MAX_REQS > 1 tlul_adapter_host does not do anything to order responses from the TL-UL
  17: // interface which could return them out of order. It is the host's responsibility to either only
  18: // have outstanding requests to an address space it knows will return responses in order or to not
  19: // care about out of order responses (note that if read data is returned out of order there is no
  20: // way to determine this).
  21: 
  22: `include "prim_assert.sv"
  23: 
  24: module tlul_adapter_host #(
  25:   parameter int unsigned MAX_REQS = 2
  26: ) (
  27:   input clk_i,
  28:   input rst_ni,
  29: 
  30:   input                              req_i,
  31:   output logic                       gnt_o,
  32:   input  logic [top_pkg::TL_AW-1:0]  addr_i,
  33:   input  logic                       we_i,
  34:   input  logic [top_pkg::TL_DW-1:0]  wdata_i,
  35:   input  logic [top_pkg::TL_DBW-1:0] be_i,
  36: 
  37:   output logic                       valid_o,
  38:   output logic [top_pkg::TL_DW-1:0]  rdata_o,
  39:   output logic                       err_o,
  40: 
  41:   output tlul_pkg::tl_h2d_t          tl_o,
  42:   input  tlul_pkg::tl_d2h_t          tl_i
  43: );
  44:   localparam int WordSize = $clog2(top_pkg::TL_DBW);
  45: 
  46:   logic [top_pkg::TL_AIW-1:0] tl_source;
  47:   logic [top_pkg::TL_DBW-1:0] tl_be;
  48: 
  49:   if (MAX_REQS == 1) begin : g_single_req
  50:     assign tl_source = '0;
  51:   end else begin : g_multiple_reqs
  52:     localparam int ReqNumW  = $clog2(MAX_REQS);
  53: 
  54:     logic [ReqNumW-1:0] source_d;
  55:     logic [ReqNumW-1:0] source_q;
  56: 
  57:     always_ff @(posedge clk_i or negedge rst_ni) begin
  58:       if (!rst_ni) begin
  59:         source_q <= '0;
  60:       end else begin
  61:         source_q <= source_d;
  62:       end
  63:     end
  64: 
  65:     always_comb begin
  66:       source_d = source_q;
  67: 
  68:       if (req_i && gnt_o) begin
  69:         if (source_q == MAX_REQS - 1) begin
  70:           source_d = '0;
  71:         end else  begin
  72:           source_d = source_q + 1;
  73:         end
  74:       end
  75:     end
  76: 
  77:     assign tl_source = top_pkg::TL_AIW'(source_q);
  78:   end
  79: 
  80:   // For TL-UL Get opcode all active bytes must have their mask bit set, so all reads get all tl_be
  81:   // bits set. For writes the supplied be_i is used as the mask.
  82:   assign tl_be = ~we_i ? {top_pkg::TL_DBW{1'b1}} : be_i;
  83: 
  84:   assign tl_o = '{
  85:     a_valid:   req_i,
  86:     a_opcode:  (~we_i) ? tlul_pkg::Get           :
  87:                (&be_i) ? tlul_pkg::PutFullData   :
  88:                          tlul_pkg::PutPartialData,
  89:     a_param:   3'h0,
  90:     a_size:    top_pkg::TL_SZW'(WordSize),
  91:     a_mask:    tl_be,
  92:     a_source:  tl_source,
  93:     a_address: {addr_i[31:WordSize], {WordSize{1'b0}}},
  94:     a_data:    wdata_i,
  95:     a_user:    '{default:'0},
  96: 
  97:     d_ready:   1'b1
  98:   };
  99: 
 100:   assign gnt_o   = tl_i.a_ready;
 101: 
 102:   assign valid_o = tl_i.d_valid;
 103:   assign rdata_o = tl_i.d_data;
 104:   assign err_o   = tl_i.d_error;
 105: 
 106: `ifdef INC_ASSERT
 107:   localparam int OutstandingReqCntW =
 108:     (MAX_REQS == 2 ** $clog2(MAX_REQS)) ? $clog2(MAX_REQS) + 1 : $clog2(MAX_REQS);
 109: 
 110:   logic [OutstandingReqCntW-1:0] outstanding_reqs_q;
 111:   logic [OutstandingReqCntW-1:0] outstanding_reqs_d;
 112: 
 113:   always_comb begin
 114:     outstanding_reqs_d = outstanding_reqs_q;
 115: 
 116:     if ((req_i && gnt_o) && !valid_o) begin
 117:       outstanding_reqs_d = outstanding_reqs_q + 1;
 118:     end else if (!(req_i && gnt_o) && valid_o) begin
 119:       outstanding_reqs_d = outstanding_reqs_q - 1;
 120:     end
 121:   end
 122: 
 123:   always_ff @(posedge clk_i or negedge rst_ni) begin
 124:     if (!rst_ni) begin
 125:       outstanding_reqs_q <= '0;
 126:     end else begin
 127:       outstanding_reqs_q <= outstanding_reqs_d;
 128:     end
 129:   end
 130: 
 131:   `ASSERT(DontExceeedMaxReqs, req_i |-> outstanding_reqs_d <= MAX_REQS);
 132: `endif
 133: endmodule
 134: