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