feat: optimize sram controller
This commit is contained in:
@@ -65,6 +65,7 @@ module axi2sram_sp_external #(
|
||||
output reg req_o,
|
||||
output reg we_o,
|
||||
output reg [AXI_ADDR_WIDTH-1:0] addr_o,
|
||||
output reg bank_o,
|
||||
output reg [AXI_DATA_WIDTH/8-1:0] be_o,
|
||||
output reg [AXI_DATA_WIDTH-1:0] data_o,
|
||||
input [AXI_DATA_WIDTH-1:0] data_i
|
||||
@@ -101,40 +102,34 @@ module axi2sram_sp_external #(
|
||||
localparam FIXED = 2'b00;
|
||||
localparam INCR = 2'b01;
|
||||
localparam WRAP = 2'b10;
|
||||
localparam [AXI_ADDR_WIDTH-1:0] ADDR_INCR =
|
||||
{{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1} << LOG_NR_BYTES;
|
||||
|
||||
reg [AXI_ADDR_WIDTH-1:0] req_addr_d, req_addr_q;
|
||||
reg [7:0] cnt_d, cnt_q;
|
||||
reg [8:0] cnt_d, cnt_q;
|
||||
reg [AXI_ADDR_WIDTH-1:0] wrap_mask_d, wrap_mask_q;
|
||||
reg req_bank_d, req_bank_q;
|
||||
reg [AXI_DATA_WIDTH-1:0] read_data_q;
|
||||
reg read_capture;
|
||||
|
||||
function automatic [AXI_ADDR_WIDTH-1:0] get_wrap_boundary;
|
||||
input [AXI_ADDR_WIDTH-1:0] unaligned_address;
|
||||
input [7:0] len;
|
||||
begin
|
||||
get_wrap_boundary = 'h0;
|
||||
// for wrapping transfers ax_len can only be of size 1, 3, 7 or 15
|
||||
if (len == 4'b1)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:1+LOG_NR_BYTES];
|
||||
else if (len == 4'b11)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-1:2+LOG_NR_BYTES];
|
||||
else if (len == 4'b111)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:3+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:2+LOG_NR_BYTES];
|
||||
else if (len == 4'b1111)
|
||||
get_wrap_boundary[AXI_ADDR_WIDTH-1:4+LOG_NR_BYTES] = unaligned_address[AXI_ADDR_WIDTH-3:4+LOG_NR_BYTES];
|
||||
end
|
||||
endfunction
|
||||
wire [AXI_ADDR_WIDTH-1:0] ar_burst_bytes =
|
||||
({{(AXI_ADDR_WIDTH-8){1'b0}}, s_arlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
|
||||
wire [AXI_ADDR_WIDTH-1:0] aw_burst_bytes =
|
||||
({{(AXI_ADDR_WIDTH-8){1'b0}}, s_awlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
|
||||
wire [AXI_ADDR_WIDTH-1:0] ar_wrap_mask = ar_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
|
||||
wire [AXI_ADDR_WIDTH-1:0] aw_wrap_mask = aw_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
|
||||
|
||||
reg [AXI_ADDR_WIDTH-1:0] aligned_address;
|
||||
reg [AXI_ADDR_WIDTH-1:0] wrap_boundary;
|
||||
reg [AXI_ADDR_WIDTH-1:0] upper_wrap_boundary;
|
||||
reg [AXI_ADDR_WIDTH-1:0] cons_addr;
|
||||
reg [AXI_ADDR_WIDTH-1:0] next_addr;
|
||||
reg [AXI_ADDR_WIDTH-1:0] seq_addr;
|
||||
|
||||
always @ (*) begin
|
||||
// address generation
|
||||
aligned_address = {ax_req_q_addr[AXI_ADDR_WIDTH-1:LOG_NR_BYTES], {{LOG_NR_BYTES}{1'b0}}};
|
||||
wrap_boundary = get_wrap_boundary(ax_req_q_addr, ax_req_q_len);
|
||||
// this will overflow
|
||||
upper_wrap_boundary = wrap_boundary + ((ax_req_q_len + 1) << LOG_NR_BYTES);
|
||||
// calculate consecutive address
|
||||
cons_addr = aligned_address + (cnt_q << LOG_NR_BYTES);
|
||||
seq_addr = req_addr_q + ADDR_INCR;
|
||||
case (ax_req_q_burst)
|
||||
FIXED: next_addr = req_addr_q;
|
||||
INCR: next_addr = seq_addr;
|
||||
WRAP: next_addr = (req_addr_q & ~wrap_mask_q) | (seq_addr & wrap_mask_q);
|
||||
default: next_addr = seq_addr;
|
||||
endcase
|
||||
|
||||
// Transaction attributes
|
||||
// default assignments
|
||||
@@ -146,12 +141,16 @@ module axi2sram_sp_external #(
|
||||
ax_req_d_burst = ax_req_q_burst;
|
||||
req_addr_d = req_addr_q;
|
||||
cnt_d = cnt_q;
|
||||
wrap_mask_d = wrap_mask_q;
|
||||
req_bank_d = req_bank_q;
|
||||
read_capture = 1'b0;
|
||||
// Memory default assignments
|
||||
data_o = s_wdata;
|
||||
be_o = s_wstrb;
|
||||
we_o = 1'b0;
|
||||
req_o = 1'b0;
|
||||
addr_o = 'h0;
|
||||
bank_o = req_bank_q;
|
||||
// AXI assignments
|
||||
// request
|
||||
s_awready = 1'b0;
|
||||
@@ -184,14 +183,17 @@ module axi2sram_sp_external #(
|
||||
ax_req_d_len = s_arlen;
|
||||
ax_req_d_size = s_arsize;
|
||||
ax_req_d_burst = s_arburst;
|
||||
state_d = READ;
|
||||
wrap_mask_d = ar_wrap_mask;
|
||||
req_bank_d = s_araddr[22];
|
||||
state_d = READ_ADDR;
|
||||
// we can request the first address, this saves us time
|
||||
req_o = 1'b1;
|
||||
addr_o = s_araddr;
|
||||
bank_o = s_araddr[22];
|
||||
// save the address
|
||||
req_addr_d = s_araddr;
|
||||
// save the ar_len
|
||||
cnt_d = 1;
|
||||
cnt_d = 0;
|
||||
// ------------
|
||||
// Write
|
||||
// ------------
|
||||
@@ -205,6 +207,9 @@ module axi2sram_sp_external #(
|
||||
ax_req_d_len = s_awlen;
|
||||
ax_req_d_size = s_awsize;
|
||||
ax_req_d_burst = s_awburst;
|
||||
wrap_mask_d = aw_wrap_mask;
|
||||
req_bank_d = s_awaddr[22];
|
||||
bank_o = s_awaddr[22];
|
||||
// we've got our first w_valid so start the write process
|
||||
if (s_wvalid) begin
|
||||
req_o = 1'b1;
|
||||
@@ -231,40 +236,52 @@ module axi2sram_sp_external #(
|
||||
end
|
||||
|
||||
READ: begin
|
||||
// keep request to memory high
|
||||
req_o = 1'b1;
|
||||
addr_o = req_addr_q;
|
||||
// send the response
|
||||
s_rvalid = 1'b1;
|
||||
s_rdata = data_i;
|
||||
s_rdata = read_data_q;
|
||||
s_rid = ax_req_q_id;
|
||||
s_rlast = (cnt_q == ax_req_q_len + 1);
|
||||
s_rlast = (cnt_q == ({1'b0, ax_req_q_len} + 9'd1));
|
||||
if (FAST_READ_BURST && !s_rlast) begin
|
||||
req_o = 1'b1;
|
||||
addr_o = next_addr;
|
||||
end
|
||||
// check that the master is ready, the slave must not wait on this
|
||||
if (s_rready) begin
|
||||
// we sent the last byte -> go back to idle
|
||||
if (s_rlast) begin
|
||||
state_d = IDLE;
|
||||
// we already got everything
|
||||
if (s_arvalid) begin
|
||||
// Accept the next burst without an intervening
|
||||
// IDLE cycle and start its SRAM address phase.
|
||||
s_arready = 1'b1;
|
||||
ax_req_d_id = s_arid;
|
||||
ax_req_d_addr = s_araddr;
|
||||
ax_req_d_len = s_arlen;
|
||||
ax_req_d_size = s_arsize;
|
||||
ax_req_d_burst = s_arburst;
|
||||
wrap_mask_d = ar_wrap_mask;
|
||||
req_bank_d = s_araddr[22];
|
||||
req_o = 1'b1;
|
||||
addr_o = s_araddr;
|
||||
bank_o = s_araddr[22];
|
||||
req_addr_d = s_araddr;
|
||||
// ARVALID was presented during the preceding
|
||||
// beat, so the async-SRAM address has a full
|
||||
// cycle to settle before this capture edge.
|
||||
read_capture = 1'b1;
|
||||
cnt_d = 1;
|
||||
state_d = READ;
|
||||
end else begin
|
||||
state_d = IDLE;
|
||||
end
|
||||
end
|
||||
else begin
|
||||
if (FAST_READ_BURST) begin
|
||||
// Queue the next async-SRAM address for the clock
|
||||
// edge after the current read data is sampled.
|
||||
case (ax_req_q_burst)
|
||||
FIXED, INCR: req_addr_d = cons_addr;
|
||||
WRAP: begin
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
req_addr_d = wrap_boundary;
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
req_addr_d = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
end else begin
|
||||
req_addr_d = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
read_capture = 1'b1;
|
||||
req_addr_d = next_addr;
|
||||
cnt_d = cnt_q + 1;
|
||||
state_d = READ;
|
||||
end else begin
|
||||
req_addr_d = next_addr;
|
||||
state_d = READ_ADDR;
|
||||
end
|
||||
end
|
||||
@@ -272,34 +289,12 @@ module axi2sram_sp_external #(
|
||||
end
|
||||
|
||||
READ_ADDR: begin
|
||||
// keep request to memory high
|
||||
// Fill the read data register after the async-SRAM address has
|
||||
// been stable for one full sys_clk cycle.
|
||||
req_o = 1'b1;
|
||||
// send the response
|
||||
s_rvalid = 1'b0;
|
||||
// ----------------------------
|
||||
// Next address generation
|
||||
// ----------------------------
|
||||
// handle the correct burst type
|
||||
case (ax_req_q_burst)
|
||||
FIXED, INCR: addr_o = cons_addr;
|
||||
WRAP: begin
|
||||
// check if the address reached warp boundary
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
addr_o = wrap_boundary;
|
||||
// address warped beyond boundary
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
// we are still in the incremental regime
|
||||
end else begin
|
||||
addr_o = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
// we need to change the address here for the upcoming request
|
||||
// we can decrease the counter as the master has consumed the read data
|
||||
addr_o = req_addr_q;
|
||||
read_capture = 1'b1;
|
||||
cnt_d = cnt_q + 1;
|
||||
// save the request address for the next cycle
|
||||
req_addr_d = addr_o;
|
||||
state_d = READ;
|
||||
end
|
||||
|
||||
@@ -317,24 +312,9 @@ module axi2sram_sp_external #(
|
||||
// Next address generation
|
||||
// ----------------------------
|
||||
// handle the correct burst type
|
||||
case (ax_req_q_burst)
|
||||
|
||||
FIXED, INCR: addr_o = cons_addr;
|
||||
WRAP: begin
|
||||
// check if the address reached warp boundary
|
||||
if (cons_addr == upper_wrap_boundary) begin
|
||||
addr_o = wrap_boundary;
|
||||
// address warped beyond boundary
|
||||
end else if (cons_addr > upper_wrap_boundary) begin
|
||||
addr_o = ax_req_q_addr + ((cnt_q - ax_req_q_len) << LOG_NR_BYTES);
|
||||
// we are still in the incremental regime
|
||||
end else begin
|
||||
addr_o = cons_addr;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
addr_o = next_addr;
|
||||
// save the request address for the next cycle
|
||||
req_addr_d = addr_o;
|
||||
req_addr_d = next_addr;
|
||||
// we can decrease the counter as the master has consumed the read data
|
||||
cnt_d = cnt_q + 1;
|
||||
|
||||
@@ -365,7 +345,10 @@ module axi2sram_sp_external #(
|
||||
ax_req_q_len <= 8'h0;
|
||||
ax_req_q_size <= 3'h0;
|
||||
req_addr_q <= 'h0;
|
||||
cnt_q <= 8'h0;
|
||||
cnt_q <= 9'h0;
|
||||
wrap_mask_q <= 'h0;
|
||||
req_bank_q <= 1'b0;
|
||||
read_data_q <= 'h0;
|
||||
end else begin
|
||||
state_q <= state_d;
|
||||
ax_req_q_addr <= ax_req_d_addr;
|
||||
@@ -375,6 +358,10 @@ module axi2sram_sp_external #(
|
||||
ax_req_q_size <= ax_req_d_size;
|
||||
req_addr_q <= req_addr_d;
|
||||
cnt_q <= cnt_d;
|
||||
wrap_mask_q <= wrap_mask_d;
|
||||
req_bank_q <= req_bank_d;
|
||||
if (read_capture)
|
||||
read_data_q <= data_i;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user