optimize
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 [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,14 +236,15 @@ 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);
|
||||
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
|
||||
@@ -248,23 +254,12 @@ module axi2sram_sp_external #(
|
||||
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 +267,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 +290,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;
|
||||
|
||||
@@ -366,6 +324,9 @@ module axi2sram_sp_external #(
|
||||
ax_req_q_size <= 3'h0;
|
||||
req_addr_q <= 'h0;
|
||||
cnt_q <= 8'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 +336,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
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// 3-stage pipelined multiplier (LUT-based, no DSP)
|
||||
// latency=3, throughput=1 result/cycle
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// 3-stage pipelined multiplier (LUT-based, no DSP)
|
||||
// latency=3, throughput=1 result/cycle
|
||||
(* use_dsp = "no", use_dsp48 = "no", syn_multstyle = "logic" *)
|
||||
module pipelined_mult_32x32 (
|
||||
input clk,
|
||||
@@ -43,9 +41,7 @@ module pipelined_mult_32x32 (
|
||||
endmodule
|
||||
|
||||
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// 矩阵乘法器顶层模块 (AXI Burst Slave + Ping-Pong + Stream CRC32)
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// AXI Burst Slave + Ping-Pong + Stream CRC32
|
||||
module matmul_axi_slave (
|
||||
input clk,
|
||||
input resetn,
|
||||
@@ -96,21 +92,6 @@ module matmul_axi_slave (
|
||||
output reg s_axi_rvalid,
|
||||
input s_axi_rready,
|
||||
|
||||
// CDMA local endpoint port
|
||||
input ep_wr_valid,
|
||||
input [3:0] ep_wr_id,
|
||||
input [3:0] ep_wr_bank,
|
||||
input [7:0] ep_wr_word_addr,
|
||||
input [31:0] ep_wr_data,
|
||||
output ep_wr_ready,
|
||||
|
||||
input ep_rd_valid,
|
||||
input [3:0] ep_rd_id,
|
||||
input [3:0] ep_rd_bank,
|
||||
input [7:0] ep_rd_word_addr,
|
||||
output reg [31:0] ep_rd_data,
|
||||
output ep_rd_ready,
|
||||
|
||||
// AXI master port for autonomous matrix stream load/store
|
||||
output reg [3:0] m_axi_awid,
|
||||
output reg [31:0] m_axi_awaddr,
|
||||
@@ -157,7 +138,7 @@ module matmul_axi_slave (
|
||||
);
|
||||
|
||||
// ==========================================
|
||||
// 内存地址映射 (Memory Map)
|
||||
// Memory Map
|
||||
// ==========================================
|
||||
localparam ADDR_CTRL = 12'h000;
|
||||
localparam ADDR_STATUS = 12'h004;
|
||||
@@ -177,7 +158,7 @@ module matmul_axi_slave (
|
||||
localparam ADDR_B1_C = 12'h380;
|
||||
|
||||
// ==========================================
|
||||
// 寄存器与数据缓冲
|
||||
// Registers and data buffers
|
||||
// ==========================================
|
||||
reg req_0, req_1;
|
||||
reg busy;
|
||||
@@ -258,31 +239,6 @@ module matmul_axi_slave (
|
||||
end
|
||||
endfunction
|
||||
|
||||
assign ep_wr_ready = 1'b1;
|
||||
assign ep_rd_ready = 1'b1;
|
||||
|
||||
wire [3:0] ep_wr_lo_idx = ep_wr_word_addr[3:0];
|
||||
wire [3:0] ep_wr_hi_idx = ep_wr_word_addr[3:0];
|
||||
wire [3:0] ep_rd_elem = c_elem_from_word(ep_rd_word_addr[5:0]);
|
||||
wire [1:0] ep_rd_part = c_part_from_word(ep_rd_word_addr[5:0]);
|
||||
wire [65:0] ep_rd_c0 = b0_c[ep_rd_elem];
|
||||
wire [65:0] ep_rd_c1 = b1_c[ep_rd_elem];
|
||||
|
||||
always @(*) begin
|
||||
ep_rd_data = 32'b0;
|
||||
if (ep_rd_word_addr < 8'd48) begin
|
||||
if (ep_rd_bank[0] == 1'b0) begin
|
||||
if (ep_rd_part == 2'd0) ep_rd_data = ep_rd_c0[31:0];
|
||||
else if (ep_rd_part == 2'd1) ep_rd_data = ep_rd_c0[63:32];
|
||||
else ep_rd_data = {30'b0, ep_rd_c0[65:64]};
|
||||
end else begin
|
||||
if (ep_rd_part == 2'd0) ep_rd_data = ep_rd_c1[31:0];
|
||||
else if (ep_rd_part == 2'd1) ep_rd_data = ep_rd_c1[63:32];
|
||||
else ep_rd_data = {30'b0, ep_rd_c1[65:64]};
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function [31:0] apply_wstrb;
|
||||
input [31:0] old_value;
|
||||
input [31:0] new_value;
|
||||
@@ -298,16 +254,24 @@ module matmul_axi_slave (
|
||||
|
||||
// ==========================================
|
||||
// CRC32 Engine (IEEE 802.3, polynomial 0xEDB88320)
|
||||
//
|
||||
// AXI-stream: single-cycle crc32_update_word (4 LUT lookup depth, ok for
|
||||
// AXI timing—the bus runs at or below internal compute rate).
|
||||
// DMA-calc: 2-stage pipelined word engine (2 bytes/stage) + 6-cycle
|
||||
// serial FSM for 66-bit C-elements, with 16-deep FIFO to absorb the
|
||||
// compute pipeline burst. Critical path: 2 table lookups + 1 XOR per
|
||||
// stage vs 12 table lookups in the original single-cycle design.
|
||||
// ==========================================
|
||||
reg [31:0] crc32_table [0:255];
|
||||
reg [31:0] crc_reg;
|
||||
|
||||
wire [31:0] crc_stream_data = ep_rd_valid ? ep_rd_data : s_axi_rdata;
|
||||
// ---- AXI-stream CRC (single-cycle) ----------------------------------
|
||||
wire [31:0] crc_stream_data = s_axi_rdata;
|
||||
wire crc_axi_valid = (r_state == R_DATA) && s_axi_rvalid && s_axi_rready &&
|
||||
((r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) ||
|
||||
(r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0)));
|
||||
wire crc_ep_valid = ep_rd_valid && ep_rd_ready && (ep_rd_word_addr < 8'd48);
|
||||
wire crc_stream_valid = crc_axi_valid || crc_ep_valid;
|
||||
wire crc_stream_valid = crc_axi_valid;
|
||||
wire [31:0] crc_next = crc32_update_word(crc_reg, crc_stream_data);
|
||||
|
||||
function [31:0] crc32_update_word;
|
||||
input [31:0] crc_in;
|
||||
@@ -323,19 +287,23 @@ module matmul_axi_slave (
|
||||
end
|
||||
endfunction
|
||||
|
||||
function [31:0] crc32_update_c66;
|
||||
input [31:0] crc_in;
|
||||
input [65:0] c_in;
|
||||
reg [31:0] crc_mid0;
|
||||
reg [31:0] crc_mid1;
|
||||
begin
|
||||
crc_mid0 = crc32_update_word(crc_in, c_in[31:0]);
|
||||
crc_mid1 = crc32_update_word(crc_mid0, c_in[63:32]);
|
||||
crc32_update_c66 = crc32_update_word(crc_mid1, {30'b0, c_in[65:64]});
|
||||
end
|
||||
endfunction
|
||||
// ---- DMA-calc 3-stage shift register pipeline -----------------------
|
||||
// Stage 0: capture acc_result, compute word0 CRC.
|
||||
// Stage 1: shift, compute word1 CRC.
|
||||
// Final: crc_reg updated when stage 1 valid (word2 CRC).
|
||||
// Latency 3 cycles; compute FSM inserts issue gaps so result spacing
|
||||
// is ≥3 cycles, ensuring crc_reg is committed before the next capture.
|
||||
reg crc_c66_s0_valid, crc_c66_s1_valid;
|
||||
reg [31:0] crc_c66_s0_crc, crc_c66_s1_crc;
|
||||
reg [31:0] crc_c66_s0_word1, crc_c66_s1_word2;
|
||||
reg [31:0] crc_c66_s0_word2;
|
||||
reg crc_c66_s0_last, crc_c66_s1_last;
|
||||
|
||||
wire [31:0] crc_next = crc32_update_word(crc_reg, crc_stream_data);
|
||||
wire [31:0] crc_c66_s0_next = crc32_update_word(crc_reg, acc_result[31:0]);
|
||||
wire [31:0] crc_c66_s1_next = crc32_update_word(crc_c66_s0_crc, crc_c66_s0_word1);
|
||||
wire [31:0] crc_c66_final_next = crc32_update_word(crc_c66_s1_crc, crc_c66_s1_word2);
|
||||
|
||||
wire crc_c66_busy = crc_c66_s0_valid || crc_c66_s1_valid;
|
||||
|
||||
initial begin
|
||||
crc32_table[0 ] = 32'h00000000; crc32_table[1 ] = 32'h77073096;
|
||||
@@ -469,7 +437,7 @@ module matmul_axi_slave (
|
||||
end
|
||||
|
||||
// ==========================================
|
||||
// AXI Write 通道逻辑 (支持 INCR Burst)
|
||||
// AXI Write (INCR Burst)
|
||||
// ==========================================
|
||||
localparam W_IDLE = 2'd0;
|
||||
localparam W_DATA = 2'd1;
|
||||
@@ -485,7 +453,6 @@ module matmul_axi_slave (
|
||||
assign s_axi_bid = w_id;
|
||||
assign s_axi_bresp = 2'b00;
|
||||
|
||||
// 前向声明引擎的状态
|
||||
localparam C_IDLE = 2'd0;
|
||||
localparam C_RUN = 2'd1;
|
||||
reg [1:0] state;
|
||||
@@ -508,7 +475,6 @@ module matmul_axi_slave (
|
||||
reg [1:0] dma_wr_state;
|
||||
reg [5:0] dma_wr_count;
|
||||
|
||||
// 【修改点 1】单独引出一个写脉冲信号给 CRC 清零用
|
||||
wire crc_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready && (w_offset == ADDR_CRC);
|
||||
wire done_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready &&
|
||||
(w_offset == ADDR_STATUS) && s_axi_wdata[1];
|
||||
@@ -534,24 +500,6 @@ module matmul_axi_slave (
|
||||
dma_start_pulse <= 1'b0;
|
||||
dma_done_clear_pulse <= 1'b0;
|
||||
|
||||
if (ep_wr_valid && ep_wr_ready) begin
|
||||
if (ep_wr_bank[0] == 1'b0) begin
|
||||
if (ep_wr_word_addr < 8'd16)
|
||||
b0_a[ep_wr_lo_idx] <= ep_wr_data;
|
||||
else if (ep_wr_word_addr < 8'd32)
|
||||
b0_b[ep_wr_hi_idx] <= ep_wr_data;
|
||||
else
|
||||
error <= 1'b1;
|
||||
end else begin
|
||||
if (ep_wr_word_addr < 8'd16)
|
||||
b1_a[ep_wr_lo_idx] <= ep_wr_data;
|
||||
else if (ep_wr_word_addr < 8'd32)
|
||||
b1_b[ep_wr_hi_idx] <= ep_wr_data;
|
||||
else
|
||||
error <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (dma_rd_commit) begin
|
||||
if (dma_rd_bank == 1'b0) begin
|
||||
if (dma_rd_count < 5'd16)
|
||||
@@ -604,7 +552,7 @@ module matmul_axi_slave (
|
||||
dma_src_stride <= apply_wstrb(dma_src_stride, s_axi_wdata, s_axi_wstrb);
|
||||
else if (w_offset == ADDR_DMA_DST_STRIDE)
|
||||
dma_dst_stride <= apply_wstrb(dma_dst_stride, s_axi_wdata, s_axi_wstrb);
|
||||
// 【修改点 2】删除 else if (w_offset == ADDR_CRC) { crc_reg <= ... } 防止多重驱动
|
||||
// CRC register is now managed by the pipelined CRC engine
|
||||
else if (w_offset >= ADDR_B0_A && w_offset < ADDR_B0_B)
|
||||
b0_a[(w_offset - ADDR_B0_A) >> 2] <= apply_wstrb(b0_a[(w_offset - ADDR_B0_A) >> 2], s_axi_wdata, s_axi_wstrb);
|
||||
else if (w_offset >= ADDR_B0_B && w_offset < ADDR_B0_C)
|
||||
@@ -645,7 +593,7 @@ module matmul_axi_slave (
|
||||
end
|
||||
|
||||
// ==========================================
|
||||
// AXI Read 通道逻辑 (支持 INCR Burst)
|
||||
// AXI Read (INCR Burst)
|
||||
// ==========================================
|
||||
localparam R_IDLE = 2'd0;
|
||||
localparam R_DATA = 2'd1;
|
||||
@@ -697,7 +645,6 @@ module matmul_axi_slave (
|
||||
end
|
||||
R_DATA: begin
|
||||
if (s_axi_rvalid && s_axi_rready) begin
|
||||
// 【修改点 3】删掉直接赋值 crc_stream_valid 的逻辑,移至专用 Pipeline 块
|
||||
if (r_cnt == r_len) begin
|
||||
s_axi_rvalid <= 1'b0;
|
||||
s_axi_rlast <= 1'b0;
|
||||
@@ -725,7 +672,7 @@ module matmul_axi_slave (
|
||||
else if (current_r_offset == ADDR_CRC)
|
||||
s_axi_rdata = crc_reg ^ 32'hFFFFFFFF;
|
||||
else if (current_r_offset == ADDR_STATUS)
|
||||
s_axi_rdata = {27'b0, dma_done, dma_busy, error, done, busy};
|
||||
s_axi_rdata = {26'b0, crc_c66_busy, dma_done, dma_busy, error, done, busy};
|
||||
else if (current_r_offset == ADDR_DMA_SRC_BASE)
|
||||
s_axi_rdata = dma_src_base;
|
||||
else if (current_r_offset == ADDR_DMA_DST_BASE)
|
||||
@@ -758,7 +705,7 @@ module matmul_axi_slave (
|
||||
end
|
||||
|
||||
// ==========================================
|
||||
// 计算引擎 (Compute FSM)
|
||||
// Compute FSM
|
||||
// ==========================================
|
||||
wire [63:0] mult_p [0:3];
|
||||
reg [31:0] m_in_a [0:3];
|
||||
@@ -785,19 +732,66 @@ module matmul_axi_slave (
|
||||
wire [65:0] acc_result = ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
|
||||
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
|
||||
wire crc_calc_valid = dma_busy && acc_valid_d4;
|
||||
wire [31:0] crc_calc_next = crc32_update_c66(crc_reg, acc_result);
|
||||
|
||||
// CRC register: software/EP reads keep the legacy 32-bit path; autonomous DMA
|
||||
// folds each 66-bit C element directly as low/mid/high words.
|
||||
// DMA CRC issue spacing: compute FSM stalls via this counter to ensure
|
||||
// ≥3 cycles between consecutive acc_result captures, matching the 3-stage
|
||||
// CRC pipeline latency so crc_reg is committed before the next element.
|
||||
reg [1:0] dma_crc_issue_gap;
|
||||
wire dma_crc_issue_ready = !dma_busy || ((dma_crc_issue_gap == 2'd0) && !crc_c66_busy);
|
||||
|
||||
// CRC register update: DMA calc result (pipelined, 3-cycle latency)
|
||||
// takes priority over AXI-stream (single-cycle). The stream path is
|
||||
// only permitted when the DMA pipeline is idle (!crc_c66_busy).
|
||||
always @(posedge clk) begin
|
||||
if (!resetn) begin
|
||||
crc_reg <= 32'hFFFFFFFF;
|
||||
crc_reg <= 32'hFFFFFFFF;
|
||||
crc_c66_s0_valid <= 1'b0;
|
||||
crc_c66_s0_crc <= 32'b0;
|
||||
crc_c66_s0_word1 <= 32'b0;
|
||||
crc_c66_s0_word2 <= 32'b0;
|
||||
crc_c66_s0_last <= 1'b0;
|
||||
crc_c66_s1_valid <= 1'b0;
|
||||
crc_c66_s1_crc <= 32'b0;
|
||||
crc_c66_s1_word2 <= 32'b0;
|
||||
crc_c66_s1_last <= 1'b0;
|
||||
end else if (crc_clear_pulse) begin
|
||||
crc_reg <= 32'hFFFFFFFF;
|
||||
end else if (crc_calc_valid) begin
|
||||
crc_reg <= crc_calc_next;
|
||||
end else if (crc_stream_valid) begin
|
||||
crc_reg <= crc_next;
|
||||
crc_reg <= 32'hFFFFFFFF;
|
||||
crc_c66_s0_valid <= 1'b0;
|
||||
crc_c66_s0_crc <= 32'b0;
|
||||
crc_c66_s0_word1 <= 32'b0;
|
||||
crc_c66_s0_word2 <= 32'b0;
|
||||
crc_c66_s0_last <= 1'b0;
|
||||
crc_c66_s1_valid <= 1'b0;
|
||||
crc_c66_s1_crc <= 32'b0;
|
||||
crc_c66_s1_word2 <= 32'b0;
|
||||
crc_c66_s1_last <= 1'b0;
|
||||
end else begin
|
||||
// Stage 1 → crc_reg finalize (word2 CRC)
|
||||
if (crc_c66_s1_valid)
|
||||
crc_reg <= crc_c66_final_next;
|
||||
else if (crc_stream_valid && !crc_c66_busy)
|
||||
crc_reg <= crc_next;
|
||||
|
||||
// Stage 0 → Stage 1 shift
|
||||
crc_c66_s1_valid <= crc_c66_s0_valid;
|
||||
if (crc_c66_s0_valid) begin
|
||||
crc_c66_s1_crc <= crc_c66_s1_next;
|
||||
crc_c66_s1_word2 <= crc_c66_s0_word2;
|
||||
crc_c66_s1_last <= crc_c66_s0_last;
|
||||
end else begin
|
||||
crc_c66_s1_last <= 1'b0;
|
||||
end
|
||||
|
||||
// Capture → Stage 0
|
||||
crc_c66_s0_valid <= crc_calc_valid;
|
||||
if (crc_calc_valid) begin
|
||||
crc_c66_s0_crc <= crc_c66_s0_next;
|
||||
crc_c66_s0_word1 <= acc_result[63:32];
|
||||
crc_c66_s0_word2 <= {30'b0, acc_result[65:64]};
|
||||
crc_c66_s0_last <= (acc_idx_d4 == 4'd15);
|
||||
end else begin
|
||||
crc_c66_s0_last <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -808,6 +802,7 @@ module matmul_axi_slave (
|
||||
busy <= 1'b1;
|
||||
state <= C_RUN;
|
||||
pipe_cnt <= 5'd1;
|
||||
dma_crc_issue_gap <= dma_busy ? 2'd2 : 2'd0;
|
||||
acc_idx_d1 <= 4'd0;
|
||||
acc_bank_d1 <= bank;
|
||||
acc_valid_d1 <= 1'b1;
|
||||
@@ -832,6 +827,7 @@ module matmul_axi_slave (
|
||||
cur_bank <= 1'b0;
|
||||
calc_done_pulse <= 1'b0;
|
||||
pipe_cnt <= 5'd0;
|
||||
dma_crc_issue_gap <= 2'd0;
|
||||
acc_idx_d1 <= 4'd0;
|
||||
acc_idx_d2 <= 4'd0;
|
||||
acc_idx_d3 <= 4'd0;
|
||||
@@ -846,8 +842,10 @@ module matmul_axi_slave (
|
||||
acc_valid_d4 <= 1'b0;
|
||||
end else begin
|
||||
calc_done_pulse <= 1'b0;
|
||||
if (dma_crc_issue_gap != 2'd0)
|
||||
dma_crc_issue_gap <= dma_crc_issue_gap - 2'd1;
|
||||
|
||||
// Pipeline shift: issue_idx → d1 → d2 → d3 → d4 (4 cycles total)
|
||||
// Pipeline shift (4 cycles total)
|
||||
acc_idx_d4 <= acc_idx_d3;
|
||||
acc_idx_d3 <= acc_idx_d2;
|
||||
acc_idx_d2 <= acc_idx_d1;
|
||||
@@ -874,21 +872,28 @@ module matmul_axi_slave (
|
||||
end
|
||||
|
||||
C_RUN: begin
|
||||
// Issue 4 new operands every cycle (pipe_cnt 0-15, 16 rounds)
|
||||
// Issue 4 new operands per round. DMA mode inserts gap
|
||||
// so the 3-stage CRC pipeline can commit before the next
|
||||
// C-element capture.
|
||||
if (pipe_cnt < 5'd16) begin
|
||||
acc_idx_d1 <= pipe_cnt[3:0];
|
||||
acc_bank_d1 <= cur_bank;
|
||||
acc_valid_d1 <= 1'b1;
|
||||
if (cur_bank == 1'b0) begin
|
||||
m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}];
|
||||
m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}];
|
||||
m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}];
|
||||
m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}];
|
||||
end else begin
|
||||
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}];
|
||||
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}];
|
||||
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}];
|
||||
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}];
|
||||
if (dma_crc_issue_ready) begin
|
||||
acc_idx_d1 <= pipe_cnt[3:0];
|
||||
acc_bank_d1 <= cur_bank;
|
||||
acc_valid_d1 <= 1'b1;
|
||||
if (cur_bank == 1'b0) begin
|
||||
m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}];
|
||||
m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}];
|
||||
m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}];
|
||||
m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}];
|
||||
end else begin
|
||||
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}];
|
||||
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}];
|
||||
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}];
|
||||
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}];
|
||||
end
|
||||
if (dma_busy)
|
||||
dma_crc_issue_gap <= 2'd2;
|
||||
pipe_cnt <= pipe_cnt + 5'd1;
|
||||
end
|
||||
end
|
||||
|
||||
@@ -904,17 +909,30 @@ module matmul_axi_slave (
|
||||
calc_done_pulse <= 1'b1;
|
||||
end
|
||||
|
||||
if (pipe_cnt < 5'd16) begin
|
||||
pipe_cnt <= pipe_cnt + 5'd1;
|
||||
end else if (cur_bank == 1'b0 && req_1) begin
|
||||
start_calc_bank(1'b1);
|
||||
end else if (cur_bank == 1'b1 && req_0) begin
|
||||
start_calc_bank(1'b0);
|
||||
end else if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
|
||||
busy <= 1'b0;
|
||||
state <= C_IDLE;
|
||||
end else begin
|
||||
pipe_cnt <= pipe_cnt + 5'd1;
|
||||
if (pipe_cnt >= 5'd16) begin
|
||||
if (dma_busy) begin
|
||||
if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
|
||||
if (cur_bank == 1'b0 && req_1)
|
||||
start_calc_bank(1'b1);
|
||||
else if (cur_bank == 1'b1 && req_0)
|
||||
start_calc_bank(1'b0);
|
||||
else begin
|
||||
busy <= 1'b0;
|
||||
state <= C_IDLE;
|
||||
end
|
||||
end else begin
|
||||
pipe_cnt <= pipe_cnt + 5'd1;
|
||||
end
|
||||
end else if (cur_bank == 1'b0 && req_1) begin
|
||||
start_calc_bank(1'b1);
|
||||
end else if (cur_bank == 1'b1 && req_0) begin
|
||||
start_calc_bank(1'b0);
|
||||
end else if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
|
||||
busy <= 1'b0;
|
||||
state <= C_IDLE;
|
||||
end else begin
|
||||
pipe_cnt <= pipe_cnt + 5'd1;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
@@ -75,21 +75,17 @@ module axi_wrap_ram_sp_external (
|
||||
output axi_bvalid ,
|
||||
input axi_bready ,
|
||||
|
||||
//BaseRAM信号
|
||||
inout [31:0] base_ram_data, //BaseRAM数据,低8位与CPLD串口控制器共享
|
||||
output [19:0] base_ram_addr, //BaseRAM地址
|
||||
output [ 3:0] base_ram_be_n, //BaseRAM字节使能,低有效。如果不使用字节使能,请保持为0
|
||||
output base_ram_ce_n, //BaseRAM片选,低有效
|
||||
output base_ram_oe_n, //BaseRAM读使能,低有效
|
||||
output base_ram_we_n, //BaseRAM写使能,低有效
|
||||
//BaseRAM\Uffffffff\Uffffffff\Uffffffff inout [31:0] base_ram_data, //BaseRAM\Uffffffff\Uffffffff\u0763\Uffffffff\Uffffffff\Uffffffff\u03bb\UffffffffCPLD\Uffffffff\Uffffffff\Uffffffff\u06bf\Uffffffff\Uffffffff\Uffffffff\Uffffffff output [19:0] base_ram_addr, //BaseRAM\Uffffffff\Uffffffff\Uffffffff
|
||||
output [ 3:0] base_ram_be_n, //BaseRAM\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff0
|
||||
output base_ram_ce_n, //BaseRAM\u01ac\u0461\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff
|
||||
output base_ram_oe_n, //BaseRAM\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff
|
||||
output base_ram_we_n, //BaseRAM\u0434\u02b9\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff
|
||||
|
||||
//ExtRAM信号
|
||||
inout [31:0] ext_ram_data, //ExtRAM数据
|
||||
output [19:0] ext_ram_addr, //ExtRAM地址
|
||||
output [ 3:0] ext_ram_be_n, //ExtRAM字节使能,低有效。如果不使用字节使能,请保持为0
|
||||
output ext_ram_ce_n, //ExtRAM片选,低有效
|
||||
output ext_ram_oe_n, //ExtRAM读使能,低有效
|
||||
output ext_ram_we_n //ExtRAM写使能,低有效
|
||||
//ExtRAM\Uffffffff\Uffffffff\Uffffffff inout [31:0] ext_ram_data, //ExtRAM\Uffffffff\Uffffffff\Uffffffff output [19:0] ext_ram_addr, //ExtRAM\Uffffffff\Uffffffff\Uffffffff
|
||||
output [ 3:0] ext_ram_be_n, //ExtRAM\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff0
|
||||
output ext_ram_ce_n, //ExtRAM\u01ac\u0461\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff
|
||||
output ext_ram_oe_n, //ExtRAM\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff
|
||||
output ext_ram_we_n //ExtRAM\u0434\u02b9\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff\Uffffffff
|
||||
);
|
||||
|
||||
|
||||
@@ -139,6 +135,7 @@ wire ram_bready ;
|
||||
wire [31:0] soc_sram_addr;
|
||||
wire soc_sram_cs;
|
||||
wire soc_sram_we;
|
||||
wire soc_sram_bank;
|
||||
wire [3:0] soc_sram_be;
|
||||
wire [31:0] soc_sram_wdata;
|
||||
wire [31:0] soc_sram_rdata;
|
||||
@@ -188,7 +185,8 @@ assign ram_bready = axi_bready ;
|
||||
axi2sram_sp_external #(
|
||||
.AXI_ID_WIDTH ( 5 ),
|
||||
.AXI_ADDR_WIDTH ( 32 ),
|
||||
.AXI_DATA_WIDTH ( 32 ))
|
||||
.AXI_DATA_WIDTH ( 32 ),
|
||||
.FAST_READ_BURST( 1 ))
|
||||
u_axi_sram_sp (
|
||||
.clk ( aclk ),
|
||||
.resetn ( aresetn ),
|
||||
@@ -232,12 +230,13 @@ axi2sram_sp_external #(
|
||||
.req_o ( soc_sram_cs ),
|
||||
.we_o ( soc_sram_we ),
|
||||
.addr_o ( soc_sram_addr ),
|
||||
.bank_o ( soc_sram_bank ),
|
||||
.be_o ( soc_sram_be ),
|
||||
.data_o ( soc_sram_wdata ),
|
||||
.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;
|
||||
|
||||
assign base_ram_addr = soc_sram_addr[21:2];
|
||||
|
||||
Reference in New Issue
Block a user