649 lines
29 KiB
Verilog
649 lines
29 KiB
Verilog
// ═══════════════════════════════════════════════════════
|
||
// 基础时序乘法器模块 (无 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
|
||
// 如果 b 的当前最低位为 1,则累加 a
|
||
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)
|
||
// ═══════════════════════════════════════════════════════
|
||
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;
|
||
|
||
// Bank 0 (可完全当作原来的单缓冲使用)
|
||
localparam ADDR_B0_A = 12'h100;
|
||
localparam ADDR_B0_B = 12'h140;
|
||
localparam ADDR_B0_C = 12'h180;
|
||
|
||
// Bank 1 (供无等待计算扩展使用)
|
||
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)
|
||
// ==========================================
|
||
localparam ADDR_CRC = 12'h010;
|
||
|
||
reg [31:0] crc32_table [0:255];
|
||
reg [31:0] crc_reg;
|
||
|
||
// Stream CRC: triggered when AXI reads C results
|
||
reg [31:0] crc_stream_data;
|
||
reg crc_stream_valid;
|
||
|
||
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]};
|
||
|
||
// CRC32 Table Initialization (IEEE 802.3 reflected)
|
||
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
|
||
|
||
// CRC register update: stream when reading C data, reset on write
|
||
always @(posedge clk) begin
|
||
if (!resetn) begin
|
||
crc_reg <= 32'hFFFFFFFF;
|
||
crc_stream_valid <= 1'b0;
|
||
end else begin
|
||
if (crc_stream_valid)
|
||
crc_reg <= crc_next;
|
||
else
|
||
crc_stream_valid <= 1'b0;
|
||
end
|
||
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;
|
||
|
||
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;
|
||
|
||
// 引擎计算完成,拉高通用 done 标志
|
||
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; // 启动 Bank 0
|
||
if (s_axi_wdata[1]) req_1 <= 1'b1; // 启动 Bank 1
|
||
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
|
||
else if (w_offset == ADDR_CRC) begin
|
||
crc_reg <= 32'hFFFFFFFF; // 写任意值复位 CRC
|
||
end
|
||
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 begin
|
||
// 访问无效地址,拉高 error 标志
|
||
error <= 1'b1;
|
||
end
|
||
|
||
// ===== Burst 地址累加 =====
|
||
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];
|
||
|
||
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
|
||
// CRC32 stream: feed read data when in C result range
|
||
if (crc_read_en) begin
|
||
crc_stream_data <= s_axi_rdata;
|
||
crc_stream_valid <= 1'b1;
|
||
end
|
||
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 声明提取到 always 块外部
|
||
wire [11:0] current_r_offset = (r_state == R_DATA) ? r_offset : s_axi_araddr[11:0];
|
||
|
||
// CRC stream trigger: valid when reading C result data
|
||
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));
|
||
|
||
// 组合逻辑准备 Read 数据
|
||
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
|
||
|
||
// ==========================================
|
||
// 计算引擎 (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]; // registered for stable accumulation
|
||
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
|
||
|
||
// Interrupt: driven by done, cleared when software writes STATUS[1]
|
||
assign intr = done;
|
||
|
||
endmodule |