This repository has been archived on 2026-08-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ciciec2026/rtl/ip/matmul/matmul_axi_slave.v

1111 lines
48 KiB
Verilog

// ═══════════════════════════════════════════════════════
// 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,
input rstn,
input [31:0] a,
input [31:0] b,
output reg [63:0] p
);
reg [31:0] a_r, b_r;
(* use_dsp = "no", use_dsp48 = "no", syn_multstyle = "logic" *)
reg [63:0] prod;
function automatic [63:0] lut_mul32;
input [31:0] lhs;
input [31:0] rhs;
integer bit_idx;
reg [63:0] acc;
begin
acc = 64'b0;
for (bit_idx = 0; bit_idx < 32; bit_idx = bit_idx + 1) begin
if (rhs[bit_idx])
acc = acc + ({32'b0, lhs} << bit_idx);
end
lut_mul32 = acc;
end
endfunction
always @(posedge clk) begin
if (!rstn) begin
a_r <= 32'b0; b_r <= 32'b0;
prod <= 64'b0; p <= 64'b0;
end else begin
a_r <= a; // Stage 1: register inputs
b_r <= b;
prod <= lut_mul32(a_r, b_r); // Stage 2: LUT-based multiply
p <= prod; // Stage 3: register output
end
end
endmodule
// ═══════════════════════════════════════════════════════
// 矩阵乘法器顶层模块 (AXI Burst Slave + Ping-Pong + Stream CRC32)
// ═══════════════════════════════════════════════════════
module matmul_axi_slave (
input clk,
input resetn,
// AXI Write Address Channel
input [4:0] s_axi_awid,
input [31:0] s_axi_awaddr,
input [7:0] s_axi_awlen,
input [2:0] s_axi_awsize,
input [1:0] s_axi_awburst,
input s_axi_awlock,
input [3:0] s_axi_awcache,
input [2:0] s_axi_awprot,
input s_axi_awvalid,
output reg s_axi_awready,
// AXI Write Data Channel
input [4:0] s_axi_wid,
input [31:0] s_axi_wdata,
input [3:0] s_axi_wstrb,
input s_axi_wlast,
input s_axi_wvalid,
output reg s_axi_wready,
// AXI Write Response Channel
output [4:0] s_axi_bid,
output [1:0] s_axi_bresp,
output reg s_axi_bvalid,
input s_axi_bready,
// AXI Read Address Channel
input [4:0] s_axi_arid,
input [31:0] s_axi_araddr,
input [7:0] s_axi_arlen,
input [2:0] s_axi_arsize,
input [1:0] s_axi_arburst,
input s_axi_arlock,
input [3:0] s_axi_arcache,
input [2:0] s_axi_arprot,
input s_axi_arvalid,
output reg s_axi_arready,
// AXI Read Data Channel
output reg [4:0] s_axi_rid,
output reg [31:0] s_axi_rdata,
output [1:0] s_axi_rresp,
output reg s_axi_rlast,
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,
output reg [7:0] m_axi_awlen,
output reg [2:0] m_axi_awsize,
output reg [1:0] m_axi_awburst,
output reg m_axi_awlock,
output reg [3:0] m_axi_awcache,
output reg [2:0] m_axi_awprot,
output reg m_axi_awvalid,
input m_axi_awready,
output reg [31:0] m_axi_wdata,
output reg [3:0] m_axi_wstrb,
output reg m_axi_wlast,
output reg m_axi_wvalid,
input m_axi_wready,
input [3:0] m_axi_bid,
input [1:0] m_axi_bresp,
input m_axi_bvalid,
output reg m_axi_bready,
output reg [3:0] m_axi_arid,
output reg [31:0] m_axi_araddr,
output reg [7:0] m_axi_arlen,
output reg [2:0] m_axi_arsize,
output reg [1:0] m_axi_arburst,
output reg m_axi_arlock,
output reg [3:0] m_axi_arcache,
output reg [2:0] m_axi_arprot,
output reg m_axi_arvalid,
input m_axi_arready,
input [3:0] m_axi_rid,
input [31:0] m_axi_rdata,
input [1:0] m_axi_rresp,
input m_axi_rlast,
input m_axi_rvalid,
output reg m_axi_rready,
// Interrupt output (active high level, pulsed by calc_done)
output intr
);
// ==========================================
// 内存地址映射 (Memory Map)
// ==========================================
localparam ADDR_CTRL = 12'h000;
localparam ADDR_STATUS = 12'h004;
localparam ADDR_CRC = 12'h010;
localparam ADDR_DMA_SRC_BASE = 12'h020;
localparam ADDR_DMA_DST_BASE = 12'h024;
localparam ADDR_DMA_GROUPS = 12'h028;
localparam ADDR_DMA_SRC_STRIDE = 12'h02C;
localparam ADDR_DMA_DST_STRIDE = 12'h030;
localparam ADDR_B0_A = 12'h100;
localparam ADDR_B0_B = 12'h140;
localparam ADDR_B0_C = 12'h180;
localparam ADDR_B1_A = 12'h300;
localparam ADDR_B1_B = 12'h340;
localparam ADDR_B1_C = 12'h380;
// ==========================================
// 寄存器与数据缓冲
// ==========================================
reg req_0, req_1;
reg busy;
reg [1:0] done_count;
reg error;
wire done = (done_count != 2'd0);
reg [31:0] b0_a [0:15];
reg [31:0] b0_b [0:15];
reg [65:0] b0_c [0:15];
reg [31:0] b1_a [0:15];
reg [31:0] b1_b [0:15];
reg [65:0] b1_c [0:15];
reg [31:0] dma_src_base;
reg [31:0] dma_dst_base;
reg [31:0] dma_groups;
reg [31:0] dma_src_stride;
reg [31:0] dma_dst_stride;
reg dma_busy;
reg dma_done;
reg [31:0] load_group;
reg [31:0] store_group;
reg [31:0] dma_next_rd_addr;
reg [31:0] dma_next_wr_addr;
reg [31:0] completed_groups;
reg [1:0] bank_loaded;
reg [1:0] bank_store_pending;
reg [1:0] bank_storing;
reg [1:0] bank_compute_pending;
reg dma_compute_bank;
reg dma_load_bank;
reg dma_store_bank;
reg dma_start_pulse;
reg dma_done_clear_pulse;
reg dma_req0_pulse;
reg dma_req1_pulse;
function [3:0] c_elem_from_word;
input [5:0] word_idx;
begin
case (word_idx)
6'd0, 6'd1, 6'd2: c_elem_from_word = 4'd0;
6'd3, 6'd4, 6'd5: c_elem_from_word = 4'd1;
6'd6, 6'd7, 6'd8: c_elem_from_word = 4'd2;
6'd9, 6'd10, 6'd11: c_elem_from_word = 4'd3;
6'd12, 6'd13, 6'd14: c_elem_from_word = 4'd4;
6'd15, 6'd16, 6'd17: c_elem_from_word = 4'd5;
6'd18, 6'd19, 6'd20: c_elem_from_word = 4'd6;
6'd21, 6'd22, 6'd23: c_elem_from_word = 4'd7;
6'd24, 6'd25, 6'd26: c_elem_from_word = 4'd8;
6'd27, 6'd28, 6'd29: c_elem_from_word = 4'd9;
6'd30, 6'd31, 6'd32: c_elem_from_word = 4'd10;
6'd33, 6'd34, 6'd35: c_elem_from_word = 4'd11;
6'd36, 6'd37, 6'd38: c_elem_from_word = 4'd12;
6'd39, 6'd40, 6'd41: c_elem_from_word = 4'd13;
6'd42, 6'd43, 6'd44: c_elem_from_word = 4'd14;
default: c_elem_from_word = 4'd15;
endcase
end
endfunction
function [1:0] c_part_from_word;
input [5:0] word_idx;
begin
case (word_idx)
6'd0, 6'd3, 6'd6, 6'd9,
6'd12, 6'd15, 6'd18, 6'd21,
6'd24, 6'd27, 6'd30, 6'd33,
6'd36, 6'd39, 6'd42, 6'd45: c_part_from_word = 2'd0;
6'd1, 6'd4, 6'd7, 6'd10,
6'd13, 6'd16, 6'd19, 6'd22,
6'd25, 6'd28, 6'd31, 6'd34,
6'd37, 6'd40, 6'd43, 6'd46: c_part_from_word = 2'd1;
default: c_part_from_word = 2'd2;
endcase
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;
input [3:0] strobe;
begin
apply_wstrb = old_value;
if (strobe[0]) apply_wstrb[7:0] = new_value[7:0];
if (strobe[1]) apply_wstrb[15:8] = new_value[15:8];
if (strobe[2]) apply_wstrb[23:16] = new_value[23:16];
if (strobe[3]) apply_wstrb[31:24] = new_value[31:24];
end
endfunction
// ==========================================
// CRC32 Engine (IEEE 802.3, polynomial 0xEDB88320)
// ==========================================
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;
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;
function [31:0] crc32_update_word;
input [31:0] crc_in;
input [31:0] data_in;
reg [31:0] c0;
reg [31:0] c1;
reg [31:0] c2;
begin
c0 = crc32_table[(crc_in[7:0] ^ data_in[7:0])] ^ {8'h00, crc_in[31:8]};
c1 = crc32_table[(c0[7:0] ^ data_in[15:8])] ^ {8'h00, c0[31:8]};
c2 = crc32_table[(c1[7:0] ^ data_in[23:16])] ^ {8'h00, c1[31:8]};
crc32_update_word = crc32_table[(c2[7:0] ^ data_in[31:24])] ^ {8'h00, c2[31:8]};
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
wire [31:0] crc_next = crc32_update_word(crc_reg, crc_stream_data);
initial begin
crc32_table[0 ] = 32'h00000000; crc32_table[1 ] = 32'h77073096;
crc32_table[2 ] = 32'hEE0E612C; crc32_table[3 ] = 32'h990951BA;
crc32_table[4 ] = 32'h076DC419; crc32_table[5 ] = 32'h706AF48F;
crc32_table[6 ] = 32'hE963A535; crc32_table[7 ] = 32'h9E6495A3;
crc32_table[8 ] = 32'h0EDB8832; crc32_table[9 ] = 32'h79DCB8A4;
crc32_table[10 ] = 32'hE0D5E91E; crc32_table[11 ] = 32'h97D2D988;
crc32_table[12 ] = 32'h09B64C2B; crc32_table[13 ] = 32'h7EB17CBD;
crc32_table[14 ] = 32'hE7B82D07; crc32_table[15 ] = 32'h90BF1D91;
crc32_table[16 ] = 32'h1DB71064; crc32_table[17 ] = 32'h6AB020F2;
crc32_table[18 ] = 32'hF3B97148; crc32_table[19 ] = 32'h84BE41DE;
crc32_table[20 ] = 32'h1ADAD47D; crc32_table[21 ] = 32'h6DDDE4EB;
crc32_table[22 ] = 32'hF4D4B551; crc32_table[23 ] = 32'h83D385C7;
crc32_table[24 ] = 32'h136C9856; crc32_table[25 ] = 32'h646BA8C0;
crc32_table[26 ] = 32'hFD62F97A; crc32_table[27 ] = 32'h8A65C9EC;
crc32_table[28 ] = 32'h14015C4F; crc32_table[29 ] = 32'h63066CD9;
crc32_table[30 ] = 32'hFA0F3D63; crc32_table[31 ] = 32'h8D080DF5;
crc32_table[32 ] = 32'h3B6E20C8; crc32_table[33 ] = 32'h4C69105E;
crc32_table[34 ] = 32'hD56041E4; crc32_table[35 ] = 32'hA2677172;
crc32_table[36 ] = 32'h3C03E4D1; crc32_table[37 ] = 32'h4B04D447;
crc32_table[38 ] = 32'hD20D85FD; crc32_table[39 ] = 32'hA50AB56B;
crc32_table[40 ] = 32'h35B5A8FA; crc32_table[41 ] = 32'h42B2986C;
crc32_table[42 ] = 32'hDBBBC9D6; crc32_table[43 ] = 32'hACBCF940;
crc32_table[44 ] = 32'h32D86CE3; crc32_table[45 ] = 32'h45DF5C75;
crc32_table[46 ] = 32'hDCD60DCF; crc32_table[47 ] = 32'hABD13D59;
crc32_table[48 ] = 32'h26D930AC; crc32_table[49 ] = 32'h51DE003A;
crc32_table[50 ] = 32'hC8D75180; crc32_table[51 ] = 32'hBFD06116;
crc32_table[52 ] = 32'h21B4F4B5; crc32_table[53 ] = 32'h56B3C423;
crc32_table[54 ] = 32'hCFBA9599; crc32_table[55 ] = 32'hB8BDA50F;
crc32_table[56 ] = 32'h2802B89E; crc32_table[57 ] = 32'h5F058808;
crc32_table[58 ] = 32'hC60CD9B2; crc32_table[59 ] = 32'hB10BE924;
crc32_table[60 ] = 32'h2F6F7C87; crc32_table[61 ] = 32'h58684C11;
crc32_table[62 ] = 32'hC1611DAB; crc32_table[63 ] = 32'hB6662D3D;
crc32_table[64 ] = 32'h76DC4190; crc32_table[65 ] = 32'h01DB7106;
crc32_table[66 ] = 32'h98D220BC; crc32_table[67 ] = 32'hEFD5102A;
crc32_table[68 ] = 32'h71B18589; crc32_table[69 ] = 32'h06B6B51F;
crc32_table[70 ] = 32'h9FBFE4A5; crc32_table[71 ] = 32'hE8B8D433;
crc32_table[72 ] = 32'h7807C9A2; crc32_table[73 ] = 32'h0F00F934;
crc32_table[74 ] = 32'h9609A88E; crc32_table[75 ] = 32'hE10E9818;
crc32_table[76 ] = 32'h7F6A0DBB; crc32_table[77 ] = 32'h086D3D2D;
crc32_table[78 ] = 32'h91646C97; crc32_table[79 ] = 32'hE6635C01;
crc32_table[80 ] = 32'h6B6B51F4; crc32_table[81 ] = 32'h1C6C6162;
crc32_table[82 ] = 32'h856530D8; crc32_table[83 ] = 32'hF262004E;
crc32_table[84 ] = 32'h6C0695ED; crc32_table[85 ] = 32'h1B01A57B;
crc32_table[86 ] = 32'h8208F4C1; crc32_table[87 ] = 32'hF50FC457;
crc32_table[88 ] = 32'h65B0D9C6; crc32_table[89 ] = 32'h12B7E950;
crc32_table[90 ] = 32'h8BBEB8EA; crc32_table[91 ] = 32'hFCB9887C;
crc32_table[92 ] = 32'h62DD1DDF; crc32_table[93 ] = 32'h15DA2D49;
crc32_table[94 ] = 32'h8CD37CF3; crc32_table[95 ] = 32'hFBD44C65;
crc32_table[96 ] = 32'h4DB26158; crc32_table[97 ] = 32'h3AB551CE;
crc32_table[98 ] = 32'hA3BC0074; crc32_table[99 ] = 32'hD4BB30E2;
crc32_table[100] = 32'h4ADFA541; crc32_table[101] = 32'h3DD895D7;
crc32_table[102] = 32'hA4D1C46D; crc32_table[103] = 32'hD3D6F4FB;
crc32_table[104] = 32'h4369E96A; crc32_table[105] = 32'h346ED9FC;
crc32_table[106] = 32'hAD678846; crc32_table[107] = 32'hDA60B8D0;
crc32_table[108] = 32'h44042D73; crc32_table[109] = 32'h33031DE5;
crc32_table[110] = 32'hAA0A4C5F; crc32_table[111] = 32'hDD0D7CC9;
crc32_table[112] = 32'h5005713C; crc32_table[113] = 32'h270241AA;
crc32_table[114] = 32'hBE0B1010; crc32_table[115] = 32'hC90C2086;
crc32_table[116] = 32'h5768B525; crc32_table[117] = 32'h206F85B3;
crc32_table[118] = 32'hB966D409; crc32_table[119] = 32'hCE61E49F;
crc32_table[120] = 32'h5EDEF90E; crc32_table[121] = 32'h29D9C998;
crc32_table[122] = 32'hB0D09822; crc32_table[123] = 32'hC7D7A8B4;
crc32_table[124] = 32'h59B33D17; crc32_table[125] = 32'h2EB40D81;
crc32_table[126] = 32'hB7BD5C3B; crc32_table[127] = 32'hC0BA6CAD;
crc32_table[128] = 32'hEDB88320; crc32_table[129] = 32'h9ABFB3B6;
crc32_table[130] = 32'h03B6E20C; crc32_table[131] = 32'h74B1D29A;
crc32_table[132] = 32'hEAD54739; crc32_table[133] = 32'h9DD277AF;
crc32_table[134] = 32'h04DB2615; crc32_table[135] = 32'h73DC1683;
crc32_table[136] = 32'hE3630B12; crc32_table[137] = 32'h94643B84;
crc32_table[138] = 32'h0D6D6A3E; crc32_table[139] = 32'h7A6A5AA8;
crc32_table[140] = 32'hE40ECF0B; crc32_table[141] = 32'h9309FF9D;
crc32_table[142] = 32'h0A00AE27; crc32_table[143] = 32'h7D079EB1;
crc32_table[144] = 32'hF00F9344; crc32_table[145] = 32'h8708A3D2;
crc32_table[146] = 32'h1E01F268; crc32_table[147] = 32'h6906C2FE;
crc32_table[148] = 32'hF762575D; crc32_table[149] = 32'h806567CB;
crc32_table[150] = 32'h196C3671; crc32_table[151] = 32'h6E6B06E7;
crc32_table[152] = 32'hFED41B76; crc32_table[153] = 32'h89D32BE0;
crc32_table[154] = 32'h10DA7A5A; crc32_table[155] = 32'h67DD4ACC;
crc32_table[156] = 32'hF9B9DF6F; crc32_table[157] = 32'h8EBEEFF9;
crc32_table[158] = 32'h17B7BE43; crc32_table[159] = 32'h60B08ED5;
crc32_table[160] = 32'hD6D6A3E8; crc32_table[161] = 32'hA1D1937E;
crc32_table[162] = 32'h38D8C2C4; crc32_table[163] = 32'h4FDFF252;
crc32_table[164] = 32'hD1BB67F1; crc32_table[165] = 32'hA6BC5767;
crc32_table[166] = 32'h3FB506DD; crc32_table[167] = 32'h48B2364B;
crc32_table[168] = 32'hD80D2BDA; crc32_table[169] = 32'hAF0A1B4C;
crc32_table[170] = 32'h36034AF6; crc32_table[171] = 32'h41047A60;
crc32_table[172] = 32'hDF60EFC3; crc32_table[173] = 32'hA867DF55;
crc32_table[174] = 32'h316E8EEF; crc32_table[175] = 32'h4669BE79;
crc32_table[176] = 32'hCB61B38C; crc32_table[177] = 32'hBC66831A;
crc32_table[178] = 32'h256FD2A0; crc32_table[179] = 32'h5268E236;
crc32_table[180] = 32'hCC0C7795; crc32_table[181] = 32'hBB0B4703;
crc32_table[182] = 32'h220216B9; crc32_table[183] = 32'h5505262F;
crc32_table[184] = 32'hC5BA3BBE; crc32_table[185] = 32'hB2BD0B28;
crc32_table[186] = 32'h2BB45A92; crc32_table[187] = 32'h5CB36A04;
crc32_table[188] = 32'hC2D7FFA7; crc32_table[189] = 32'hB5D0CF31;
crc32_table[190] = 32'h2CD99E8B; crc32_table[191] = 32'h5BDEAE1D;
crc32_table[192] = 32'h9B64C2B0; crc32_table[193] = 32'hEC63F226;
crc32_table[194] = 32'h756AA39C; crc32_table[195] = 32'h026D930A;
crc32_table[196] = 32'h9C0906A9; crc32_table[197] = 32'hEB0E363F;
crc32_table[198] = 32'h72076785; crc32_table[199] = 32'h05005713;
crc32_table[200] = 32'h95BF4A82; crc32_table[201] = 32'hE2B87A14;
crc32_table[202] = 32'h7BB12BAE; crc32_table[203] = 32'h0CB61B38;
crc32_table[204] = 32'h92D28E9B; crc32_table[205] = 32'hE5D5BE0D;
crc32_table[206] = 32'h7CDCEFB7; crc32_table[207] = 32'h0BDBDF21;
crc32_table[208] = 32'h86D3D2D4; crc32_table[209] = 32'hF1D4E242;
crc32_table[210] = 32'h68DDB3F8; crc32_table[211] = 32'h1FDA836E;
crc32_table[212] = 32'h81BE16CD; crc32_table[213] = 32'hF6B9265B;
crc32_table[214] = 32'h6FB077E1; crc32_table[215] = 32'h18B74777;
crc32_table[216] = 32'h88085AE6; crc32_table[217] = 32'hFF0F6A70;
crc32_table[218] = 32'h66063BCA; crc32_table[219] = 32'h11010B5C;
crc32_table[220] = 32'h8F659EFF; crc32_table[221] = 32'hF862AE69;
crc32_table[222] = 32'h616BFFD3; crc32_table[223] = 32'h166CCF45;
crc32_table[224] = 32'hA00AE278; crc32_table[225] = 32'hD70DD2EE;
crc32_table[226] = 32'h4E048354; crc32_table[227] = 32'h3903B3C2;
crc32_table[228] = 32'hA7672661; crc32_table[229] = 32'hD06016F7;
crc32_table[230] = 32'h4969474D; crc32_table[231] = 32'h3E6E77DB;
crc32_table[232] = 32'hAED16A4A; crc32_table[233] = 32'hD9D65ADC;
crc32_table[234] = 32'h40DF0B66; crc32_table[235] = 32'h37D83BF0;
crc32_table[236] = 32'hA9BCAE53; crc32_table[237] = 32'hDEBB9EC5;
crc32_table[238] = 32'h47B2CF7F; crc32_table[239] = 32'h30B5FFE9;
crc32_table[240] = 32'hBDBDF21C; crc32_table[241] = 32'hCABAC28A;
crc32_table[242] = 32'h53B39330; crc32_table[243] = 32'h24B4A3A6;
crc32_table[244] = 32'hBAD03605; crc32_table[245] = 32'hCDD70693;
crc32_table[246] = 32'h54DE5729; crc32_table[247] = 32'h23D967BF;
crc32_table[248] = 32'hB3667A2E; crc32_table[249] = 32'hC4614AB8;
crc32_table[250] = 32'h5D681B02; crc32_table[251] = 32'h2A6F2B94;
crc32_table[252] = 32'hB40BBE37; crc32_table[253] = 32'hC30C8EA1;
crc32_table[254] = 32'h5A05DF1B; crc32_table[255] = 32'h2D02EF8D;
end
// ==========================================
// AXI Write 通道逻辑 (支持 INCR Burst)
// ==========================================
localparam W_IDLE = 2'd0;
localparam W_DATA = 2'd1;
localparam W_RESP = 2'd2;
reg [1:0] w_state;
reg [31:0] w_addr;
reg [4:0] w_id;
reg [1:0] w_burst;
wire [11:0] w_offset = w_addr[11:0];
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;
reg cur_bank;
reg calc_done_pulse;
localparam DMA_RD_IDLE = 2'd0;
localparam DMA_RD_ADDR = 2'd1;
localparam DMA_RD_DATA = 2'd2;
reg [1:0] dma_rd_state;
reg [4:0] dma_rd_count;
reg dma_rd_bank;
wire [3:0] dma_rd_word_idx = dma_rd_count[3:0];
wire dma_rd_commit = (dma_rd_state == DMA_RD_DATA) && m_axi_rvalid && m_axi_rready;
localparam DMA_WR_IDLE = 2'd0;
localparam DMA_WR_ADDR = 2'd1;
localparam DMA_WR_DATA = 2'd2;
localparam DMA_WR_RESP = 2'd3;
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];
always @(posedge clk) begin
if (!resetn) begin
w_state <= W_IDLE;
s_axi_awready <= 1'b1;
s_axi_wready <= 1'b0;
s_axi_bvalid <= 1'b0;
req_0 <= 1'b0;
req_1 <= 1'b0;
done_count <= 2'd0;
error <= 1'b0;
dma_src_base <= 32'd0;
dma_dst_base <= 32'd0;
dma_groups <= 32'd0;
dma_src_stride <= 32'd128;
dma_dst_stride <= 32'd192;
dma_start_pulse <= 1'b0;
dma_done_clear_pulse <= 1'b0;
end else begin
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)
b0_a[dma_rd_word_idx] <= m_axi_rdata;
else
b0_b[dma_rd_word_idx] <= m_axi_rdata;
end else begin
if (dma_rd_count < 5'd16)
b1_a[dma_rd_word_idx] <= m_axi_rdata;
else
b1_b[dma_rd_word_idx] <= m_axi_rdata;
end
end
if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0;
if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0;
if (dma_req0_pulse) req_0 <= 1'b1;
if (dma_req1_pulse) req_1 <= 1'b1;
case (w_state)
W_IDLE: begin
s_axi_awready <= 1'b1;
if (s_axi_awvalid && s_axi_awready) begin
s_axi_awready <= 1'b0;
s_axi_wready <= 1'b1;
w_addr <= s_axi_awaddr;
w_id <= s_axi_awid;
w_burst <= s_axi_awburst;
w_state <= W_DATA;
end
end
W_DATA: begin
if (s_axi_wvalid && s_axi_wready) begin
if (w_offset == ADDR_CTRL) begin
if (s_axi_wdata[0]) req_0 <= 1'b1;
if (s_axi_wdata[1]) req_1 <= 1'b1;
if (s_axi_wdata[8]) dma_start_pulse <= 1'b1;
end
else if (w_offset == ADDR_STATUS) begin
if (s_axi_wdata[2]) error <= 1'b0;
if (s_axi_wdata[4]) dma_done_clear_pulse <= 1'b1;
end
else if (w_offset == ADDR_DMA_SRC_BASE)
dma_src_base <= apply_wstrb(dma_src_base, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_DST_BASE)
dma_dst_base <= apply_wstrb(dma_dst_base, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_GROUPS)
dma_groups <= apply_wstrb(dma_groups, s_axi_wdata, s_axi_wstrb);
else if (w_offset == ADDR_DMA_SRC_STRIDE)
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 <= ... } 防止多重驱动
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)
b0_b[(w_offset - ADDR_B0_B) >> 2] <= apply_wstrb(b0_b[(w_offset - ADDR_B0_B) >> 2], s_axi_wdata, s_axi_wstrb);
else if (w_offset >= ADDR_B1_A && w_offset < ADDR_B1_B)
b1_a[(w_offset - ADDR_B1_A) >> 2] <= apply_wstrb(b1_a[(w_offset - ADDR_B1_A) >> 2], s_axi_wdata, s_axi_wstrb);
else if (w_offset >= ADDR_B1_B && w_offset < ADDR_B1_C)
b1_b[(w_offset - ADDR_B1_B) >> 2] <= apply_wstrb(b1_b[(w_offset - ADDR_B1_B) >> 2], s_axi_wdata, s_axi_wstrb);
else if (w_offset != ADDR_CRC) begin
error <= 1'b1;
end
if (w_burst == 2'b01) w_addr <= w_addr + 32'd4;
if (s_axi_wlast) begin
s_axi_wready <= 1'b0;
s_axi_bvalid <= 1'b1;
w_state <= W_RESP;
end
end
end
W_RESP: begin
if (s_axi_bvalid && s_axi_bready) begin
s_axi_bvalid <= 1'b0;
s_axi_awready <= 1'b1;
w_state <= W_IDLE;
end
end
default: w_state <= W_IDLE;
endcase
case ({calc_done_pulse, done_clear_pulse})
2'b10: if (done_count != 2'd3) done_count <= done_count + 2'd1;
2'b01: if (done_count != 2'd0) done_count <= done_count - 2'd1;
default: done_count <= done_count;
endcase
end
end
// ==========================================
// AXI Read 通道逻辑 (支持 INCR Burst)
// ==========================================
localparam R_IDLE = 2'd0;
localparam R_DATA = 2'd1;
reg [1:0] r_state;
reg [31:0] r_addr;
reg [7:0] r_cnt;
reg [7:0] r_len;
reg [1:0] r_burst;
wire [11:0] r_offset = r_addr[11:0];
assign s_axi_rresp = 2'b00;
wire [5:0] c0_offset = (r_offset - ADDR_B0_C) >> 2;
wire [3:0] c0_elem = c_elem_from_word(c0_offset);
wire [1:0] c0_part = c_part_from_word(c0_offset);
wire [65:0] target_c0 = b0_c[c0_elem];
wire [5:0] c1_offset = (r_offset - ADDR_B1_C) >> 2;
wire [3:0] c1_elem = c_elem_from_word(c1_offset);
wire [1:0] c1_part = c_part_from_word(c1_offset);
wire [65:0] target_c1 = b1_c[c1_elem];
wire crc_read_en = (r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) ||
(r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0));
always @(posedge clk) begin
if (!resetn) begin
r_state <= R_IDLE;
s_axi_arready <= 1'b1;
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
s_axi_rid <= 5'b0;
end else begin
case (r_state)
R_IDLE: begin
s_axi_arready <= 1'b1;
if (s_axi_arvalid && s_axi_arready) begin
s_axi_arready <= 1'b0;
r_addr <= s_axi_araddr;
r_len <= s_axi_arlen;
r_burst <= s_axi_arburst;
r_cnt <= 8'd0;
s_axi_rvalid <= 1'b1;
s_axi_rlast <= (s_axi_arlen == 8'd0);
s_axi_rid <= s_axi_arid;
r_state <= R_DATA;
end
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;
s_axi_arready <= 1'b1;
r_state <= R_IDLE;
end else begin
r_cnt <= r_cnt + 8'd1;
s_axi_rlast <= (r_cnt + 8'd1 == r_len);
if (r_burst == 2'b01) r_addr <= r_addr + 32'd4;
end
end
end
default: r_state <= R_IDLE;
endcase
end
end
wire [11:0] current_r_offset = (r_state == R_DATA) ? r_offset : s_axi_araddr[11:0];
always @(*) begin
s_axi_rdata = 32'b0;
if (r_state == R_DATA || (r_state == R_IDLE && s_axi_arvalid)) begin
if (current_r_offset == ADDR_CTRL)
s_axi_rdata = {30'b0, req_1, req_0};
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};
else if (current_r_offset == ADDR_DMA_SRC_BASE)
s_axi_rdata = dma_src_base;
else if (current_r_offset == ADDR_DMA_DST_BASE)
s_axi_rdata = dma_dst_base;
else if (current_r_offset == ADDR_DMA_GROUPS)
s_axi_rdata = dma_groups;
else if (current_r_offset == ADDR_DMA_SRC_STRIDE)
s_axi_rdata = dma_src_stride;
else if (current_r_offset == ADDR_DMA_DST_STRIDE)
s_axi_rdata = dma_dst_stride;
else if (current_r_offset >= ADDR_B0_A && current_r_offset < ADDR_B0_B)
s_axi_rdata = b0_a[(current_r_offset - ADDR_B0_A) >> 2];
else if (current_r_offset >= ADDR_B0_B && current_r_offset < ADDR_B0_C)
s_axi_rdata = b0_b[(current_r_offset - ADDR_B0_B) >> 2];
else if (current_r_offset >= ADDR_B0_C && current_r_offset < (ADDR_B0_C + 12'h0C0)) begin
if (c0_part == 2'd0) s_axi_rdata = target_c0[31:0];
else if (c0_part == 2'd1) s_axi_rdata = target_c0[63:32];
else s_axi_rdata = {30'b0, target_c0[65:64]};
end
else if (current_r_offset >= ADDR_B1_A && current_r_offset < ADDR_B1_B)
s_axi_rdata = b1_a[(current_r_offset - ADDR_B1_A) >> 2];
else if (current_r_offset >= ADDR_B1_B && current_r_offset < ADDR_B1_C)
s_axi_rdata = b1_b[(current_r_offset - ADDR_B1_B) >> 2];
else if (current_r_offset >= ADDR_B1_C && current_r_offset < (ADDR_B1_C + 12'h0C0)) begin
if (c1_part == 2'd0) s_axi_rdata = target_c1[31:0];
else if (c1_part == 2'd1) s_axi_rdata = target_c1[63:32];
else s_axi_rdata = {30'b0, target_c1[65:64]};
end
end
end
// ==========================================
// 计算引擎 (Compute FSM)
// ==========================================
wire [63:0] mult_p [0:3];
reg [31:0] m_in_a [0:3];
reg [31:0] m_in_b [0:3];
genvar i;
generate
for (i = 0; i < 4; i = i + 1) begin : mult_inst
pipelined_mult_32x32 u_mult (
.clk (clk),
.rstn (resetn),
.a (m_in_a[i]),
.b (m_in_b[i]),
.p (mult_p[i])
);
end
endgenerate
// Pipeline delay shift registers for accumulation (4 stages = 3 multiplier pipe + 1)
reg [3:0] acc_idx_d1, acc_idx_d2, acc_idx_d3, acc_idx_d4;
reg acc_bank_d1, acc_bank_d2, acc_bank_d3, acc_bank_d4;
reg acc_valid_d1, acc_valid_d2, acc_valid_d3, acc_valid_d4;
reg [4:0] pipe_cnt;
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.
always @(posedge clk) begin
if (!resetn) begin
crc_reg <= 32'hFFFFFFFF;
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;
end
end
task start_calc_bank;
input bank;
begin
cur_bank <= bank;
busy <= 1'b1;
state <= C_RUN;
pipe_cnt <= 5'd1;
acc_idx_d1 <= 4'd0;
acc_bank_d1 <= bank;
acc_valid_d1 <= 1'b1;
if (bank == 1'b0) begin
m_in_a[0] <= b0_a[4'd0]; m_in_b[0] <= b0_b[4'd0];
m_in_a[1] <= b0_a[4'd1]; m_in_b[1] <= b0_b[4'd4];
m_in_a[2] <= b0_a[4'd2]; m_in_b[2] <= b0_b[4'd8];
m_in_a[3] <= b0_a[4'd3]; m_in_b[3] <= b0_b[4'd12];
end else begin
m_in_a[0] <= b1_a[4'd0]; m_in_b[0] <= b1_b[4'd0];
m_in_a[1] <= b1_a[4'd1]; m_in_b[1] <= b1_b[4'd4];
m_in_a[2] <= b1_a[4'd2]; m_in_b[2] <= b1_b[4'd8];
m_in_a[3] <= b1_a[4'd3]; m_in_b[3] <= b1_b[4'd12];
end
end
endtask
always @(posedge clk) begin
if (!resetn) begin
state <= C_IDLE;
busy <= 1'b0;
cur_bank <= 1'b0;
calc_done_pulse <= 1'b0;
pipe_cnt <= 5'd0;
acc_idx_d1 <= 4'd0;
acc_idx_d2 <= 4'd0;
acc_idx_d3 <= 4'd0;
acc_idx_d4 <= 4'd0;
acc_bank_d1 <= 1'b0;
acc_bank_d2 <= 1'b0;
acc_bank_d3 <= 1'b0;
acc_bank_d4 <= 1'b0;
acc_valid_d1 <= 1'b0;
acc_valid_d2 <= 1'b0;
acc_valid_d3 <= 1'b0;
acc_valid_d4 <= 1'b0;
end else begin
calc_done_pulse <= 1'b0;
// Pipeline shift: issue_idx → d1 → d2 → d3 → d4 (4 cycles total)
acc_idx_d4 <= acc_idx_d3;
acc_idx_d3 <= acc_idx_d2;
acc_idx_d2 <= acc_idx_d1;
acc_idx_d1 <= 4'd0;
acc_bank_d4 <= acc_bank_d3;
acc_bank_d3 <= acc_bank_d2;
acc_bank_d2 <= acc_bank_d1;
acc_bank_d1 <= 1'b0;
acc_valid_d4 <= acc_valid_d3;
acc_valid_d3 <= acc_valid_d2;
acc_valid_d2 <= acc_valid_d1;
acc_valid_d1 <= 1'b0;
case (state)
C_IDLE: begin
if (req_0) begin
start_calc_bank(1'b0);
end else if (req_1) begin
start_calc_bank(1'b1);
end else begin
pipe_cnt <= 5'd0;
busy <= 1'b0;
end
end
C_RUN: begin
// Issue 4 new operands every cycle (pipe_cnt 0-15, 16 rounds)
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]}];
end
end
// Accumulate results from 4 cycles ago.
if (acc_valid_d4) begin
if (acc_bank_d4 == 1'b0)
b0_c[acc_idx_d4] <= acc_result;
else
b1_c[acc_idx_d4] <= acc_result;
end
if (acc_valid_d4 && acc_idx_d4 == 4'd15) begin
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;
end
end
endcase
end
end
// ==========================================
// Autonomous AXI master loader with inline result CRC.
// ==========================================
always @(posedge clk) begin
if (!resetn) begin
dma_busy <= 1'b0;
dma_done <= 1'b0;
load_group <= 32'd0;
store_group <= 32'd0;
dma_next_rd_addr <= 32'd0;
dma_next_wr_addr <= 32'd0;
completed_groups <= 32'd0;
bank_loaded <= 2'b00;
bank_store_pending <= 2'b00;
bank_storing <= 2'b00;
bank_compute_pending <= 2'b00;
dma_compute_bank <= 1'b0;
dma_load_bank <= 1'b0;
dma_store_bank <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
dma_rd_count <= 5'd0;
dma_rd_bank <= 1'b0;
dma_wr_state <= DMA_WR_IDLE;
dma_wr_count <= 6'd0;
m_axi_arid <= 4'd0;
m_axi_araddr <= 32'd0;
m_axi_arlen <= 8'd31;
m_axi_arsize <= 3'd2;
m_axi_arburst <= 2'b01;
m_axi_arlock <= 1'b0;
m_axi_arcache <= 4'b0;
m_axi_arprot <= 3'b0;
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b0;
m_axi_awid <= 4'd0;
m_axi_awaddr <= 32'd0;
m_axi_awlen <= 8'd47;
m_axi_awsize <= 3'd2;
m_axi_awburst <= 2'b01;
m_axi_awlock <= 1'b0;
m_axi_awcache <= 4'b0;
m_axi_awprot <= 3'b0;
m_axi_awvalid <= 1'b0;
m_axi_wdata <= 32'd0;
m_axi_wstrb <= 4'hF;
m_axi_wlast <= 1'b0;
m_axi_wvalid <= 1'b0;
m_axi_bready <= 1'b0;
dma_req0_pulse <= 1'b0;
dma_req1_pulse <= 1'b0;
end else begin
dma_req0_pulse <= 1'b0;
dma_req1_pulse <= 1'b0;
if (dma_done_clear_pulse)
dma_done <= 1'b0;
if (dma_start_pulse && !dma_busy && dma_groups != 32'd0) begin
dma_busy <= 1'b1;
dma_done <= 1'b0;
load_group <= 32'd0;
store_group <= 32'd0;
dma_next_rd_addr <= dma_src_base;
dma_next_wr_addr <= dma_dst_base;
completed_groups <= 32'd0;
bank_loaded <= 2'b00;
bank_store_pending <= 2'b00;
bank_storing <= 2'b00;
bank_compute_pending <= 2'b00;
dma_compute_bank <= 1'b0;
dma_load_bank <= 1'b0;
dma_store_bank <= 1'b0;
dma_rd_state <= DMA_RD_IDLE;
dma_wr_state <= DMA_WR_IDLE;
end
if (dma_busy) begin
if (state == C_RUN)
bank_compute_pending[cur_bank] <= 1'b0;
if (bank_loaded[0] && !req_0 &&
!bank_compute_pending[0] && !(state == C_RUN && cur_bank == 1'b0)) begin
dma_req0_pulse <= 1'b1;
bank_loaded[0] <= 1'b0;
bank_compute_pending[0] <= 1'b1;
dma_compute_bank <= 1'b0;
end else if (bank_loaded[1] && !req_1 &&
!bank_compute_pending[1] && !(state == C_RUN && cur_bank == 1'b1)) begin
dma_req1_pulse <= 1'b1;
bank_loaded[1] <= 1'b0;
bank_compute_pending[1] <= 1'b1;
dma_compute_bank <= 1'b1;
end
end
if (calc_done_pulse && dma_busy) begin
store_group <= store_group + 32'd1;
completed_groups <= completed_groups + 32'd1;
if ((completed_groups + 32'd1) >= dma_groups) begin
dma_busy <= 1'b0;
dma_done <= 1'b1;
end
end
case (dma_rd_state)
DMA_RD_IDLE: begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b0;
if (dma_busy && load_group < dma_groups && !bank_loaded[dma_load_bank] &&
!bank_compute_pending[dma_load_bank] &&
!((dma_load_bank == 1'b0) ? req_0 : req_1) &&
!(state == C_RUN && cur_bank == dma_load_bank)) begin
dma_rd_bank <= dma_load_bank;
dma_rd_count <= 5'd0;
m_axi_araddr <= dma_next_rd_addr;
m_axi_arlen <= 8'd31;
m_axi_arsize <= 3'd2;
m_axi_arburst <= 2'b01;
m_axi_arvalid <= 1'b1;
dma_rd_state <= DMA_RD_ADDR;
end
end
DMA_RD_ADDR: begin
if (m_axi_arvalid && m_axi_arready) begin
m_axi_arvalid <= 1'b0;
m_axi_rready <= 1'b1;
dma_rd_state <= DMA_RD_DATA;
end
end
DMA_RD_DATA: begin
if (m_axi_rvalid && m_axi_rready) begin
if (m_axi_rlast) begin
m_axi_rready <= 1'b0;
bank_loaded[dma_rd_bank] <= 1'b1;
load_group <= load_group + 32'd1;
dma_next_rd_addr <= dma_next_rd_addr + dma_src_stride;
dma_load_bank <= ~dma_load_bank;
dma_rd_state <= DMA_RD_IDLE;
end else begin
dma_rd_count <= dma_rd_count + 5'd1;
end
end
end
default: dma_rd_state <= DMA_RD_IDLE;
endcase
case (dma_wr_state)
DMA_WR_IDLE: begin
m_axi_awvalid <= 1'b0;
m_axi_wvalid <= 1'b0;
m_axi_bready <= 1'b0;
end
DMA_WR_ADDR: begin
m_axi_awvalid <= 1'b0;
dma_wr_state <= DMA_WR_DATA;
end
DMA_WR_DATA: begin
m_axi_wvalid <= 1'b0;
m_axi_wlast <= 1'b0;
if (dma_wr_count == 6'd47) begin
bank_storing[dma_store_bank] <= 1'b0;
dma_store_bank <= ~dma_store_bank;
store_group <= store_group + 32'd1;
completed_groups <= completed_groups + 32'd1;
if ((completed_groups + 32'd1) >= dma_groups) begin
dma_busy <= 1'b0;
dma_done <= 1'b1;
end
dma_wr_state <= DMA_WR_IDLE;
end else begin
dma_wr_count <= dma_wr_count + 6'd1;
end
end
DMA_WR_RESP: begin
m_axi_bready <= 1'b0;
dma_wr_state <= DMA_WR_IDLE;
end
default: dma_wr_state <= DMA_WR_IDLE;
endcase
end
end
assign intr = done;
endmodule