77// in the event that writes are supported.
88//
99// An instruction port need not support write operations and does not require tag bits.
10+ //
11+ // Tag bits may be supported for only part of the mapped HyperRAM address range, in which case
12+ // case an attempt to set a tag bit at an address that is outside that range will result in a
13+ // TL-UL error being returned and the write will not occur.
14+
1015module hbmc_tl_port import tlul_pkg :: * ; # (
16+ // Width of HyperRAM address, in bits.
1117 parameter int unsigned HyperRAMAddrW = 20 ,
18+ // Address width of the portion that can store capabilities, in bits.
19+ parameter int unsigned HyperRAMTagAddrW = 19 ,
1220 // log2(burst length in bytes)
1321 parameter int unsigned Log2BurstLen = 5 , // 32-byte bursts.
1422 parameter int unsigned NumBufs = 4 ,
1523 parameter int unsigned PortIDWidth = 1 ,
1624 parameter int unsigned Log2MaxBufs = 2 ,
1725 parameter int unsigned SeqWidth = 6 ,
18- //
26+
1927 // Does this port need to support TileLink write operations?
2028 parameter bit SupportWrites = 1 ,
2129 // Coalesce write transfers into burst writes to the HBMC?
@@ -25,57 +33,57 @@ module hbmc_tl_port import tlul_pkg::*; #(
2533 localparam int unsigned ABIT = $clog2 (top_pkg :: TL_DW / 8 ),
2634 localparam int unsigned BBIT = Log2BurstLen
2735) (
28- input clk_i,
29- input rst_ni,
36+ input clk_i,
37+ input rst_ni,
3038
3139 // Constant indicating port number.
32- input [PortIDWidth- 1 : 0 ] portid_i,
40+ input [PortIDWidth- 1 : 0 ] portid_i,
3341
3442 // TL-UL interface.
35- input tl_h2d_t tl_i,
36- output tl_d2h_t tl_o,
43+ input tl_h2d_t tl_i,
44+ output tl_d2h_t tl_o,
3745
3846 // Write notification input.
39- input wr_notify_i,
40- input [HyperRAMAddrW- 1 : ABIT ] wr_notify_addr_i,
41- input [top_pkg :: TL_DBW - 1 : 0 ] wr_notify_mask_i,
42- input [top_pkg :: TL_DW - 1 : 0 ] wr_notify_data_i,
47+ input wr_notify_i,
48+ input [HyperRAMAddrW- 1 : ABIT ] wr_notify_addr_i,
49+ input [top_pkg :: TL_DBW - 1 : 0 ] wr_notify_mask_i,
50+ input [top_pkg :: TL_DW - 1 : 0 ] wr_notify_data_i,
4351
4452 // Write notification output.
45- output logic wr_notify_o,
46- output logic [top_pkg :: TL_DBW - 1 : 0 ] wr_notify_mask_o,
47- output logic [top_pkg :: TL_DW - 1 : 0 ] wr_notify_data_o,
48- output logic [HyperRAMAddrW- 1 : ABIT ] wr_notify_addr_o,
53+ output logic wr_notify_o,
54+ output logic [top_pkg :: TL_DBW - 1 : 0 ] wr_notify_mask_o,
55+ output logic [top_pkg :: TL_DW - 1 : 0 ] wr_notify_data_o,
56+ output logic [HyperRAMAddrW- 1 : ABIT ] wr_notify_addr_o,
4957
5058 // Command data to the HyperRAM controller; command, address and burst length
51- output logic cmd_req_o,
52- input cmd_wready_i,
53- output logic [HyperRAMAddrW- 1 : ABIT ] cmd_mem_addr_o,
54- output logic [Log2BurstLen- ABIT : 0 ] cmd_word_cnt_o,
55- output logic cmd_wr_not_rd_o,
56- output logic cmd_wrap_not_incr_o,
57- output logic [SeqWidth- 1 : 0 ] cmd_seq_o,
58-
59- output logic tag_cmd_req,
60- output logic [HyperRAMAddrW - 1 : ABIT ] tag_cmd_mem_addr,
61- output logic tag_cmd_wr_not_rd,
62- output tag_cmd_wcap,
63-
64- output logic dfifo_wr_ena_o,
65- input dfifo_wr_full_i,
66- output [top_pkg :: TL_DBW - 1 : 0 ] dfifo_wr_strb_o,
67- output [top_pkg :: TL_DW - 1 : 0 ] dfifo_wr_din_o,
59+ output logic cmd_req_o,
60+ input cmd_wready_i,
61+ output logic [HyperRAMAddrW- 1 : ABIT ] cmd_mem_addr_o,
62+ output logic [Log2BurstLen- ABIT : 0 ] cmd_word_cnt_o,
63+ output logic cmd_wr_not_rd_o,
64+ output logic cmd_wrap_not_incr_o,
65+ output logic [SeqWidth- 1 : 0 ] cmd_seq_o,
66+
67+ output logic tag_cmd_req,
68+ output logic [HyperRAMTagAddrW - 1 : ABIT ] tag_cmd_mem_addr,
69+ output logic tag_cmd_wr_not_rd,
70+ output tag_cmd_wcap,
71+
72+ output logic dfifo_wr_ena_o,
73+ input dfifo_wr_full_i,
74+ output [top_pkg :: TL_DBW - 1 : 0 ] dfifo_wr_strb_o,
75+ output [top_pkg :: TL_DW - 1 : 0 ] dfifo_wr_din_o,
6876
6977 // Read data from the HyperRAM
70- output ufifo_rd_ena,
71- input ufifo_rd_empty,
72- input [top_pkg :: TL_DW - 1 : 0 ] ufifo_rd_dout,
73- input [SeqWidth- 1 : 0 ] ufifo_rd_seq,
74- input ufifo_rd_last,
78+ output ufifo_rd_ena,
79+ input ufifo_rd_empty,
80+ input [top_pkg :: TL_DW - 1 : 0 ] ufifo_rd_dout,
81+ input [SeqWidth- 1 : 0 ] ufifo_rd_seq,
82+ input ufifo_rd_last,
7583
7684 // Tag read data interface.
77- output tag_rdata_rready,
78- input tl_tag_bit
85+ output tag_rdata_rready,
86+ input tl_tag_bit
7987);
8088
8189/* ----------------------------------------------------------------------------------------------------------------------------*/
@@ -84,10 +92,15 @@ module hbmc_tl_port import tlul_pkg::*; #(
8492 logic tl_req_fifo_le1;
8593 logic wr_notify_match;
8694 logic dfifo_wr_full;
95+ logic rdbuf_matches; // Address matches within the read buffer.
96+ logic rdbuf_valid; // Valid data is available within the read buffer.
8797 logic cmd_wready;
8898 logic can_accept;
8999 logic rdbuf_hit;
90100 logic rdbuf_re;
101+ logic wr_err;
102+ logic wr_req;
103+ logic rd_req;
91104 logic issue;
92105
93106 // We can accept an incoming TileLink transaction when we've got space in the hyperram, tag
@@ -106,10 +119,22 @@ module hbmc_tl_port import tlul_pkg::*; #(
106119 (tl_i.a_opcode == Get || ~ dfifo_wr_full) &
107120 ~ (wr_notify_i & wr_notify_match);
108121
122+ // Return an error response for any capability write to an address that cannot support tags.
123+ wire untagged_addr = | (tl_i.a_address[HyperRAMAddrW: 0 ] >> HyperRAMTagAddrW) &
124+ tl_i.a_user.capability;
125+
109126/* ----------------------------------------------------------------------------------------------------------------------------*/
110127
111- wire rd_req = tl_i.a_valid & (tl_i.a_opcode == Get);
112- wire wr_req = tl_i.a_valid & (tl_i.a_opcode == PutFullData || tl_i.a_opcode == PutPartialData);
128+ // Valid read request?
129+ assign rd_req = tl_i.a_valid & (tl_i.a_opcode == Get);
130+ // Valid write request?
131+ assign wr_req = tl_i.a_valid & (tl_i.a_opcode == PutFullData || tl_i.a_opcode == PutPartialData) &
132+ (SupportWrites & ! untagged_addr);
133+
134+ /* ----------------------------------------------------------------------------------------------------------------------------*/
135+ // Invalid write request?
136+ assign wr_err = tl_i.a_valid & (tl_i.a_opcode == PutFullData || tl_i.a_opcode == PutPartialData) &
137+ (untagged_addr | ! SupportWrites);
113138
114139/* ----------------------------------------------------------------------------------------------------------------------------*/
115140 if (SupportWrites) begin
@@ -138,10 +163,8 @@ module hbmc_tl_port import tlul_pkg::*; #(
138163
139164/* ----------------------------------------------------------------------------------------------------------------------------*/
140165
141- logic rdbuf_matches; // Address matches within the read buffer.
142- logic rdbuf_valid; // Valid data is available within the read buffer.
143166 logic [SeqWidth- 1 : 0 ] rdbuf_seq; // Sequence number of read buffer contents.
144- logic [top_pkg :: TL_DW - 1 : 0 ] rdbuf_dout;
167+ logic [top_pkg :: TL_DW - 1 : 0 ] rdbuf_dout;
145168
146169 // Invalidate the read buffer contents when a write occurs.
147170 //
@@ -219,12 +242,21 @@ module hbmc_tl_port import tlul_pkg::*; #(
219242 localparam int unsigned TL_REQ_FIFO_DEPTH = 4 ;
220243 localparam int unsigned TLReqFifoDepthW = prim_util_pkg :: vbits (TL_REQ_FIFO_DEPTH + 1 );
221244
222- // Metadata from inbound TileLink transactions that needs to be saved to produce the response
245+ // Verdict on the TL-UL request.
246+ typedef enum logic [1 : 0 ] {
247+ TLRspRdBuf, // Return buffered read data.
248+ TLRspRdFetch, // Fetching read data from HBMC.
249+ TLRspWrOk, // Valid write.
250+ TLRspWrErr // Return error on write.
251+ } tl_rsp_type_e ;
252+
253+ // Description of a queued TL-UL request-response.
223254 typedef struct packed {
255+ // Metadata from inbound TileLink transactions that needs to be saved to produce the response.
224256 logic [top_pkg :: TL_AIW - 1 : 0 ] tl_source;
225257 logic [top_pkg :: TL_SZW - 1 : 0 ] tl_size;
226- logic cmd_fetch;
227- logic cmd_wr_not_rd ;
258+ // Response to be returned.
259+ tl_rsp_type_e rsp_type ;
228260 } tl_req_info_t ;
229261
230262 tl_req_info_t tl_req_fifo_wdata, tl_req_fifo_rdata;
@@ -242,7 +274,7 @@ module hbmc_tl_port import tlul_pkg::*; #(
242274 // To be a contender in the arbitration among all ports, we need to express our intention
243275 // to write into the command buffer.
244276 wire cmd_req = tl_i.a_valid && tl_req_fifo_wready && ! rdbuf_hit &&
245- (tl_i.a_opcode == Get || ~ dfifo_wr_full);
277+ (tl_i.a_opcode == Get || ( ! dfifo_wr_full & ! wr_err) );
246278
247279 assign issue = tl_i.a_valid & can_accept;
248280
@@ -257,26 +289,24 @@ module hbmc_tl_port import tlul_pkg::*; #(
257289
258290 if (issue) begin
259291 // Write to the relevant FIFOs and indicate ready on TileLink A channel
260- tag_cmd_req = 1'b1 ;
292+ // - no tag request if the write was rejected.
293+ tag_cmd_req = ! wr_err;
261294 tl_req_fifo_wvalid = 1'b1 ;
262-
263- if (tl_i.a_opcode != Get) begin
264- dfifo_wr_ena = 1'b1 ;
265- end
295+ // Write into the downstream FIFO only for a valid write.
296+ dfifo_wr_ena = wr_req;
266297 end
267298 end
268299
269300 assign tag_cmd_wr_not_rd = cmd_wr_not_rd;
270- assign tag_cmd_mem_addr = tl_i.a_address[HyperRAMAddrW- 1 : ABIT ];
271-
272- wire tl_cmd_fetch = ~ (rd_req & rdbuf_valid);
273- wire tl_cmd_wr_not_rd = (tl_i.a_opcode != Get);
301+ assign tag_cmd_mem_addr = tl_i.a_address[HyperRAMTagAddrW- 1 : ABIT ];
274302
303+ // Decide on the type of response to be sent; encoded using an enumeration to reduce FIFO width.
304+ tl_rsp_type_e tl_cmd_rsp = (rd_req ? (rdbuf_valid ? TLRspRdBuf : TLRspRdFetch)
305+ : (wr_err ? TLRspWrErr : TLRspWrOk));
275306 assign tl_req_fifo_wdata = '{
276307 tl_source : tl_i.a_source,
277308 tl_size : tl_i.a_size,
278- cmd_fetch : tl_cmd_fetch,
279- cmd_wr_not_rd : tl_cmd_wr_not_rd
309+ rsp_type : tl_cmd_rsp
280310 } ;
281311
282312 // We decant the read data from the 'Upstream FIFO' into the read buffer as soon as possible,
@@ -300,6 +330,11 @@ module hbmc_tl_port import tlul_pkg::*; #(
300330 logic [top_pkg :: TL_DW - 1 : 0 ] ufifo_dout_first;
301331 assign ufifo_dout_first = ufifo_rd_dout[top_pkg :: TL_DW - 1 : 0 ];
302332
333+ // Decode control signals from the response type.
334+ wire tl_rsp_wr_not_rd = (tl_req_fifo_rdata.rsp_type == TLRspWrOk ||
335+ tl_req_fifo_rdata.rsp_type == TLRspWrErr);
336+ wire tl_rsp_rd_buffered = (tl_req_fifo_rdata.rsp_type == TLRspRdBuf);
337+
303338 // If the data from the read buffer is not accepted immediately by the host we must register it
304339 // to prevent it being invalidated by another read.
305340 logic rdata_valid_q;
@@ -311,9 +346,9 @@ module hbmc_tl_port import tlul_pkg::*; #(
311346 if (tl_i.d_ready) rdata_valid_q <= 1'b0 ; // Response sent.
312347 else begin
313348 // Capture read data and keep it stable until it is accepted by the host.
314- rdata_valid_q <= ! tl_req_fifo_rdata.cmd_wr_not_rd ;
349+ rdata_valid_q <= ! tl_rsp_wr_not_rd ;
315350 if (! rdata_valid_q) begin
316- rdata_q <= tl_req_fifo_rdata.cmd_fetch ? ufifo_dout_first : rdbuf_dout ;
351+ rdata_q <= tl_rsp_rd_buffered ? rdbuf_dout : ufifo_dout_first ;
317352 end
318353 end
319354 end
@@ -328,23 +363,23 @@ module hbmc_tl_port import tlul_pkg::*; #(
328363 tl_o_int = '0 ;
329364 if (tl_req_fifo_rvalid) begin
330365 // We have an incoming request that needs a response
331- if (tl_req_fifo_rdata.cmd_wr_not_rd ) begin
366+ if (tl_rsp_wr_not_rd ) begin
332367 // If it's a write then return an immediate response (early response is reasonable as any
333368 // read that could observe the memory cannot occur until the write has actually happened)
334369 tl_o_int.d_valid = 1'b1 ;
335370 end else begin
336371 // Otherwise wait until we have the first word of data to return.
337372 tl_o_int.d_valid = |{ ufifo_rd_ena & ~ ufifo_rd_bursting, // Initial word of burst read.
338- ~ tl_req_fifo_rdata.cmd_fetch , // From read buffer.
373+ tl_rsp_rd_buffered , // From read buffer.
339374 rdata_valid_q} ; // Holding read data stable until accepted.
340375 end
341376 end
342-
343- tl_o_int.d_opcode = tl_req_fifo_rdata.cmd_wr_not_rd ? AccessAck : AccessAckData;
377+ tl_o_int.d_error = (tl_req_fifo_rdata.rsp_type == TLRspWrErr);
378+ tl_o_int.d_opcode = tl_rsp_wr_not_rd ? AccessAck : AccessAckData;
344379 tl_o_int.d_size = tl_req_fifo_rdata.tl_size;
345380 tl_o_int.d_source = tl_req_fifo_rdata.tl_source;
346381 tl_o_int.d_data = rdata_valid_q ? rdata_q :
347- (tl_req_fifo_rdata.cmd_fetch ? ufifo_dout_first : rdbuf_dout );
382+ (tl_rsp_rd_buffered ? rdbuf_dout : ufifo_dout_first );
348383 tl_o_int.d_user.capability = tl_tag_bit;
349384 tl_o_int.a_ready = issue;
350385 end
@@ -354,7 +389,7 @@ module hbmc_tl_port import tlul_pkg::*; #(
354389 assign tl_req_fifo_rready = tl_o_int.d_valid & tl_i.d_ready;
355390
356391 // Discard the tag read data once the _read_ data is accepted.
357- assign tag_rdata_rready = tl_o_int.d_valid & tl_i.d_ready & ~ tl_req_fifo_rdata.cmd_wr_not_rd ;
392+ assign tag_rdata_rready = tl_o_int.d_valid & tl_i.d_ready & ~ tl_rsp_wr_not_rd ;
358393
359394 // Generate integrity for outgoing response.
360395 tlul_rsp_intg_gen # (
0 commit comments