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

631 lines
29 KiB
Verilog
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ═══════════════════════════════════════════════════════
// 基础时序乘法器模块 (无 DSP,移位累加,32个周期)
// ═══════════════════════════════════════════════════════
module shift_add_mult (
input clk,
input rstn,
input start,
input [31:0] a,
input [31:0] b,
output reg [63:0] p,
output reg done
);
reg [5:0] cnt;
reg [63:0] a_reg;
reg [31:0] b_reg;
reg busy;
always @(posedge clk) begin
if (!rstn) begin
busy <= 1'b0;
done <= 1'b0;
p <= 64'b0;
cnt <= 6'd0;
a_reg<= 64'b0;
b_reg<= 32'b0;
end else begin
if (start && !busy) begin
a_reg <= {32'b0, a};
b_reg <= b;
p <= 64'b0;
cnt <= 6'd0;
busy <= 1'b1;
done <= 1'b0;
end else if (busy) begin
if (cnt == 6'd32) begin
busy <= 1'b0;
done <= 1'b1;
end else begin
if (b_reg[0]) begin
p <= p + a_reg;
end
a_reg <= a_reg << 1;
b_reg <= b_reg >> 1;
cnt <= cnt + 6'd1;
end
end else begin
done <= 1'b0;
end
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,
// 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_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 done;
reg error;
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];
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 = s_axi_rdata;
wire crc_stream_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 [31:0] crc_t0, crc_c0, crc_t1, crc_c1, crc_t2, crc_c2, crc_t3, crc_next;
assign crc_t0 = crc32_table[(crc_reg[7:0] ^ crc_stream_data[7:0])];
assign crc_c0 = crc_t0 ^ {8'h00, crc_reg[31:8]};
assign crc_t1 = crc32_table[(crc_c0[7:0] ^ crc_stream_data[15:8])];
assign crc_c1 = crc_t1 ^ {8'h00, crc_c0[31:8]};
assign crc_t2 = crc32_table[(crc_c1[7:0] ^ crc_stream_data[23:16])];
assign crc_c2 = crc_t2 ^ {8'h00, crc_c1[31:8]};
assign crc_t3 = crc32_table[(crc_c2[7:0] ^ crc_stream_data[31:24])];
assign crc_next = crc_t3 ^ {8'h00, crc_c2[31:8]};
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_CALC = 2'd1;
localparam C_WAIT_MULT = 2'd2;
localparam C_ACCUM = 2'd3;
reg [1:0] state;
reg cur_bank;
reg calc_done_pulse;
// 【修改点 1】单独引出一个写脉冲信号给 CRC 清零用
wire crc_clear_pulse = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready && (w_offset == ADDR_CRC);
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 <= 1'b0;
error <= 1'b0;
end else begin
if (req_0 && state == C_CALC && cur_bank == 1'b0) req_0 <= 1'b0;
if (req_1 && state == C_CALC && cur_bank == 1'b1) req_1 <= 1'b0;
if (calc_done_pulse) begin
done <= 1'b1;
end
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;
end
else if (w_offset == ADDR_STATUS) begin
if (s_axi_wdata[1]) done <= 1'b0;
if (s_axi_wdata[2]) error <= 1'b0;
end
// 【修改点 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
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 = c0_offset / 3;
wire [1:0] c0_part = c0_offset % 3;
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 = c1_offset / 3;
wire [1:0] c1_part = c1_offset % 3;
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 = {29'b0, error, done, busy};
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
// CRC register: update on each C data read beat, clear on write to 0x010
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_stream_valid) begin
crc_reg <= crc_next;
end
end
// ==========================================
// 计算引擎 (Compute FSM)
// ==========================================
reg [3:0] calc_idx;
wire [1:0] row = calc_idx[3:2];
wire [1:0] col = calc_idx[1:0];
reg mult_start;
wire mult_done [0:3];
wire [63:0] mult_p [0:3];
reg [63:0] mult_p_r [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
shift_add_mult u_mult (
.clk (clk),
.rstn (resetn),
.start (mult_start),
.a (m_in_a[i]),
.b (m_in_b[i]),
.p (mult_p[i]),
.done (mult_done[i])
);
end
endgenerate
always @(posedge clk) begin
if (!resetn) begin
state <= C_IDLE;
busy <= 1'b0;
cur_bank <= 1'b0;
calc_idx <= 4'd0;
mult_start <= 1'b0;
calc_done_pulse <= 1'b0;
end else begin
calc_done_pulse <= 1'b0;
case (state)
C_IDLE: begin
calc_idx <= 4'd0;
if (req_0) begin
cur_bank <= 1'b0;
busy <= 1'b1;
state <= C_CALC;
end else if (req_1) begin
cur_bank <= 1'b1;
busy <= 1'b1;
state <= C_CALC;
end else begin
busy <= 1'b0;
end
end
C_CALC: begin
if (cur_bank == 1'b0) begin
m_in_a[0] <= b0_a[{row, 2'd0}]; m_in_b[0] <= b0_b[{2'd0, col}];
m_in_a[1] <= b0_a[{row, 2'd1}]; m_in_b[1] <= b0_b[{2'd1, col}];
m_in_a[2] <= b0_a[{row, 2'd2}]; m_in_b[2] <= b0_b[{2'd2, col}];
m_in_a[3] <= b0_a[{row, 2'd3}]; m_in_b[3] <= b0_b[{2'd3, col}];
end else begin
m_in_a[0] <= b1_a[{row, 2'd0}]; m_in_b[0] <= b1_b[{2'd0, col}];
m_in_a[1] <= b1_a[{row, 2'd1}]; m_in_b[1] <= b1_b[{2'd1, col}];
m_in_a[2] <= b1_a[{row, 2'd2}]; m_in_b[2] <= b1_b[{2'd2, col}];
m_in_a[3] <= b1_a[{row, 2'd3}]; m_in_b[3] <= b1_b[{2'd3, col}];
end
mult_start <= 1'b1;
state <= C_WAIT_MULT;
end
C_WAIT_MULT: begin
mult_start <= 1'b0;
if (mult_done[0] && mult_done[1] && mult_done[2] && mult_done[3]) begin
mult_p_r[0] <= mult_p[0];
mult_p_r[1] <= mult_p[1];
mult_p_r[2] <= mult_p[2];
mult_p_r[3] <= mult_p[3];
state <= C_ACCUM;
end
end
C_ACCUM: begin
if (cur_bank == 1'b0)
b0_c[calc_idx] <= ({2'b0, mult_p_r[0]} + {2'b0, mult_p_r[1]}) +
({2'b0, mult_p_r[2]} + {2'b0, mult_p_r[3]});
else
b1_c[calc_idx] <= ({2'b0, mult_p_r[0]} + {2'b0, mult_p_r[1]}) +
({2'b0, mult_p_r[2]} + {2'b0, mult_p_r[3]});
if (calc_idx == 4'd15) begin
calc_done_pulse <= 1'b1;
busy <= 1'b0;
state <= C_IDLE;
end else begin
calc_idx <= calc_idx + 4'd1;
state <= C_CALC;
end
end
endcase
end
end
assign intr = done;
endmodule