feat: optimize sram controller

This commit is contained in:
2026-07-15 10:03:39 +08:00
parent d45646342b
commit fc91511950
2 changed files with 101 additions and 111 deletions

View File

@@ -65,6 +65,7 @@ module axi2sram_sp_external #(
output reg req_o, output reg req_o,
output reg we_o, output reg we_o,
output reg [AXI_ADDR_WIDTH-1:0] addr_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/8-1:0] be_o,
output reg [AXI_DATA_WIDTH-1:0] data_o, output reg [AXI_DATA_WIDTH-1:0] data_o,
input [AXI_DATA_WIDTH-1:0] data_i input [AXI_DATA_WIDTH-1:0] data_i
@@ -101,40 +102,34 @@ module axi2sram_sp_external #(
localparam FIXED = 2'b00; localparam FIXED = 2'b00;
localparam INCR = 2'b01; localparam INCR = 2'b01;
localparam WRAP = 2'b10; 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 [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; wire [AXI_ADDR_WIDTH-1:0] ar_burst_bytes =
input [AXI_ADDR_WIDTH-1:0] unaligned_address; ({{(AXI_ADDR_WIDTH-8){1'b0}}, s_arlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
input [7:0] len; wire [AXI_ADDR_WIDTH-1:0] aw_burst_bytes =
begin ({{(AXI_ADDR_WIDTH-8){1'b0}}, s_awlen} + {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1}) << LOG_NR_BYTES;
get_wrap_boundary = 'h0; wire [AXI_ADDR_WIDTH-1:0] ar_wrap_mask = ar_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
// for wrapping transfers ax_len can only be of size 1, 3, 7 or 15 wire [AXI_ADDR_WIDTH-1:0] aw_wrap_mask = aw_burst_bytes - {{(AXI_ADDR_WIDTH-1){1'b0}}, 1'b1};
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
reg [AXI_ADDR_WIDTH-1:0] aligned_address; reg [AXI_ADDR_WIDTH-1:0] next_addr;
reg [AXI_ADDR_WIDTH-1:0] wrap_boundary; reg [AXI_ADDR_WIDTH-1:0] seq_addr;
reg [AXI_ADDR_WIDTH-1:0] upper_wrap_boundary;
reg [AXI_ADDR_WIDTH-1:0] cons_addr;
always @ (*) begin always @ (*) begin
// address generation seq_addr = req_addr_q + ADDR_INCR;
aligned_address = {ax_req_q_addr[AXI_ADDR_WIDTH-1:LOG_NR_BYTES], {{LOG_NR_BYTES}{1'b0}}}; case (ax_req_q_burst)
wrap_boundary = get_wrap_boundary(ax_req_q_addr, ax_req_q_len); FIXED: next_addr = req_addr_q;
// this will overflow INCR: next_addr = seq_addr;
upper_wrap_boundary = wrap_boundary + ((ax_req_q_len + 1) << LOG_NR_BYTES); WRAP: next_addr = (req_addr_q & ~wrap_mask_q) | (seq_addr & wrap_mask_q);
// calculate consecutive address default: next_addr = seq_addr;
cons_addr = aligned_address + (cnt_q << LOG_NR_BYTES); endcase
// Transaction attributes // Transaction attributes
// default assignments // default assignments
@@ -146,12 +141,16 @@ module axi2sram_sp_external #(
ax_req_d_burst = ax_req_q_burst; ax_req_d_burst = ax_req_q_burst;
req_addr_d = req_addr_q; req_addr_d = req_addr_q;
cnt_d = cnt_q; cnt_d = cnt_q;
wrap_mask_d = wrap_mask_q;
req_bank_d = req_bank_q;
read_capture = 1'b0;
// Memory default assignments // Memory default assignments
data_o = s_wdata; data_o = s_wdata;
be_o = s_wstrb; be_o = s_wstrb;
we_o = 1'b0; we_o = 1'b0;
req_o = 1'b0; req_o = 1'b0;
addr_o = 'h0; addr_o = 'h0;
bank_o = req_bank_q;
// AXI assignments // AXI assignments
// request // request
s_awready = 1'b0; s_awready = 1'b0;
@@ -184,14 +183,17 @@ module axi2sram_sp_external #(
ax_req_d_len = s_arlen; ax_req_d_len = s_arlen;
ax_req_d_size = s_arsize; ax_req_d_size = s_arsize;
ax_req_d_burst = s_arburst; 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 // we can request the first address, this saves us time
req_o = 1'b1; req_o = 1'b1;
addr_o = s_araddr; addr_o = s_araddr;
bank_o = s_araddr[22];
// save the address // save the address
req_addr_d = s_araddr; req_addr_d = s_araddr;
// save the ar_len // save the ar_len
cnt_d = 1; cnt_d = 0;
// ------------ // ------------
// Write // Write
// ------------ // ------------
@@ -205,6 +207,9 @@ module axi2sram_sp_external #(
ax_req_d_len = s_awlen; ax_req_d_len = s_awlen;
ax_req_d_size = s_awsize; ax_req_d_size = s_awsize;
ax_req_d_burst = s_awburst; 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 // we've got our first w_valid so start the write process
if (s_wvalid) begin if (s_wvalid) begin
req_o = 1'b1; req_o = 1'b1;
@@ -231,40 +236,52 @@ module axi2sram_sp_external #(
end end
READ: begin READ: begin
// keep request to memory high
req_o = 1'b1;
addr_o = req_addr_q;
// send the response // send the response
s_rvalid = 1'b1; s_rvalid = 1'b1;
s_rdata = data_i; s_rdata = read_data_q;
s_rid = ax_req_q_id; 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 // check that the master is ready, the slave must not wait on this
if (s_rready) begin if (s_rready) begin
// we sent the last byte -> go back to idle // we sent the last byte -> go back to idle
if (s_rlast) begin if (s_rlast) begin
state_d = IDLE; if (s_arvalid) begin
// we already got everything // 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 end
else begin else begin
if (FAST_READ_BURST) begin if (FAST_READ_BURST) begin
// Queue the next async-SRAM address for the clock read_capture = 1'b1;
// edge after the current read data is sampled. req_addr_d = next_addr;
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
cnt_d = cnt_q + 1; cnt_d = cnt_q + 1;
state_d = READ; state_d = READ;
end else begin end else begin
req_addr_d = next_addr;
state_d = READ_ADDR; state_d = READ_ADDR;
end end
end end
@@ -272,34 +289,12 @@ module axi2sram_sp_external #(
end end
READ_ADDR: begin 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; req_o = 1'b1;
// send the response addr_o = req_addr_q;
s_rvalid = 1'b0; read_capture = 1'b1;
// ----------------------------
// 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
cnt_d = cnt_q + 1; cnt_d = cnt_q + 1;
// save the request address for the next cycle
req_addr_d = addr_o;
state_d = READ; state_d = READ;
end end
@@ -317,24 +312,9 @@ module axi2sram_sp_external #(
// Next address generation // Next address generation
// ---------------------------- // ----------------------------
// handle the correct burst type // handle the correct burst type
case (ax_req_q_burst) addr_o = next_addr;
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
// save the request address for the next cycle // 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 // we can decrease the counter as the master has consumed the read data
cnt_d = cnt_q + 1; cnt_d = cnt_q + 1;
@@ -365,7 +345,10 @@ module axi2sram_sp_external #(
ax_req_q_len <= 8'h0; ax_req_q_len <= 8'h0;
ax_req_q_size <= 3'h0; ax_req_q_size <= 3'h0;
req_addr_q <= '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 end else begin
state_q <= state_d; state_q <= state_d;
ax_req_q_addr <= ax_req_d_addr; ax_req_q_addr <= ax_req_d_addr;
@@ -375,6 +358,10 @@ module axi2sram_sp_external #(
ax_req_q_size <= ax_req_d_size; ax_req_q_size <= ax_req_d_size;
req_addr_q <= req_addr_d; req_addr_q <= req_addr_d;
cnt_q <= cnt_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
end end

View File

@@ -75,21 +75,21 @@ module axi_wrap_ram_sp_external (
output axi_bvalid , output axi_bvalid ,
input axi_bready , input axi_bready ,
//BaseRAM信号 // BaseRAM
inout [31:0] base_ram_data, //BaseRAM数据,低8位与CPLD串口控制器共享 inout [31:0] base_ram_data,
output [19:0] base_ram_addr, //BaseRAM地址 output [19:0] base_ram_addr,
output [ 3:0] base_ram_be_n, //BaseRAM字节使能,低有效。如果不使用字节使能,请保持为0 output [ 3:0] base_ram_be_n,
output base_ram_ce_n, //BaseRAM片选,低有效 output base_ram_ce_n,
output base_ram_oe_n, //BaseRAM读使能,低有效 output base_ram_oe_n,
output base_ram_we_n, //BaseRAM写使能,低有效 output base_ram_we_n,
//ExtRAM信号 // ExtRAM
inout [31:0] ext_ram_data, //ExtRAM数据 inout [31:0] ext_ram_data,
output [19:0] ext_ram_addr, //ExtRAM地址 output [19:0] ext_ram_addr,
output [ 3:0] ext_ram_be_n, //ExtRAM字节使能,低有效。如果不使用字节使能,请保持为0 output [ 3:0] ext_ram_be_n,
output ext_ram_ce_n, //ExtRAM片选,低有效 output ext_ram_ce_n,
output ext_ram_oe_n, //ExtRAM读使能,低有效 output ext_ram_oe_n,
output ext_ram_we_n //ExtRAM写使能,低有效 output ext_ram_we_n
); );
@@ -139,6 +139,7 @@ wire ram_bready ;
wire [31:0] soc_sram_addr; wire [31:0] soc_sram_addr;
wire soc_sram_cs; wire soc_sram_cs;
wire soc_sram_we; wire soc_sram_we;
wire soc_sram_bank;
wire [3:0] soc_sram_be; wire [3:0] soc_sram_be;
wire [31:0] soc_sram_wdata; wire [31:0] soc_sram_wdata;
wire [31:0] soc_sram_rdata; wire [31:0] soc_sram_rdata;
@@ -188,7 +189,8 @@ assign ram_bready = axi_bready ;
axi2sram_sp_external #( axi2sram_sp_external #(
.AXI_ID_WIDTH ( 5 ), .AXI_ID_WIDTH ( 5 ),
.AXI_ADDR_WIDTH ( 32 ), .AXI_ADDR_WIDTH ( 32 ),
.AXI_DATA_WIDTH ( 32 )) .AXI_DATA_WIDTH ( 32 ),
.FAST_READ_BURST( 1 ))
u_axi_sram_sp ( u_axi_sram_sp (
.clk ( aclk ), .clk ( aclk ),
.resetn ( aresetn ), .resetn ( aresetn ),
@@ -232,12 +234,13 @@ axi2sram_sp_external #(
.req_o ( soc_sram_cs ), .req_o ( soc_sram_cs ),
.we_o ( soc_sram_we ), .we_o ( soc_sram_we ),
.addr_o ( soc_sram_addr ), .addr_o ( soc_sram_addr ),
.bank_o ( soc_sram_bank ),
.be_o ( soc_sram_be ), .be_o ( soc_sram_be ),
.data_o ( soc_sram_wdata ), .data_o ( soc_sram_wdata ),
.data_i ( soc_sram_rdata ) .data_i ( soc_sram_rdata )
); );
wire choose_sram = soc_sram_addr[22];//1:ExtRAM 0:BaseRAM wire choose_sram = soc_sram_bank;//1:ExtRAM 0:BaseRAM
wire [3:0] be_out = soc_sram_we ? soc_sram_be : 4'b1111; wire [3:0] be_out = soc_sram_we ? soc_sram_be : 4'b1111;
assign base_ram_addr = soc_sram_addr[21:2]; assign base_ram_addr = soc_sram_addr[21:2];