Skip to content

Commit 5da67be

Browse files
committed
Introduce a separate parameter for the tag RAM size
Parameterise the tagged portion of the HyperRAM so that it is possible to map the entire HyperRAM without exhausting the block RAMs of the A50T. Attempting to store a capability to the untagged region shall return a bus error to the LSU.
1 parent 030d173 commit 5da67be

9 files changed

Lines changed: 148 additions & 101 deletions

File tree

data/xbar_ifetch.hjson

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
xbar: false,
3838
addr_range: [{
3939
base_addr: "0x40000000",
40-
size_byte: "0x00100000",
40+
size_byte: "0x00800000",
4141
}],
4242
},
4343
{ name: "dbg_dev", // Debug module fetch interface

data/xbar_main.hjson

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
xbar: false,
4949
addr_range: [{
5050
base_addr: "0x40000000",
51-
size_byte: "0x00100000",
51+
size_byte: "0x00800000",
5252
}],
5353
},
5454
{ name: "rev_tag", // Revocation tag memory

data/xbar_main.hjson.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
xbar: false,
4949
addr_range: [{
5050
base_addr: "0x40000000",
51-
size_byte: "0x00100000",
51+
size_byte: "0x00800000",
5252
}],
5353
},
5454
{ name: "rev_tag", // Revocation tag memory

rtl/bus/tl_ifetch_pkg.sv

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rtl/bus/tl_main_pkg.sv

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rtl/ip/hyperram/rtl/hbmc_tl_port.sv

Lines changed: 101 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,23 @@
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+
1015
module 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

Comments
 (0)