Rewrite burst logic with FFT-style state machine (W_IDLE/DATA/RESP, R_IDLE/DATA)

This commit is contained in:
2026-06-25 00:22:30 +08:00
parent 27d818390f
commit 99c85f1a20

View File

@@ -11,16 +11,16 @@ module matmul_axi_slave (
input [3:0] s_axi_awcache, input [3:0] s_axi_awcache,
input [2:0] s_axi_awprot, input [2:0] s_axi_awprot,
input s_axi_awvalid, input s_axi_awvalid,
output s_axi_awready, output reg s_axi_awready,
input [4:0] s_axi_wid, input [4:0] s_axi_wid,
input [31:0] s_axi_wdata, input [31:0] s_axi_wdata,
input [3:0] s_axi_wstrb, input [3:0] s_axi_wstrb,
input s_axi_wlast, input s_axi_wlast,
input s_axi_wvalid, input s_axi_wvalid,
output s_axi_wready, output reg s_axi_wready,
output reg [4:0] s_axi_bid, output [4:0] s_axi_bid,
output [1:0] s_axi_bresp, output [1:0] s_axi_bresp,
output reg s_axi_bvalid, output reg s_axi_bvalid,
input s_axi_bready, input s_axi_bready,
@@ -34,7 +34,7 @@ module matmul_axi_slave (
input [3:0] s_axi_arcache, input [3:0] s_axi_arcache,
input [2:0] s_axi_arprot, input [2:0] s_axi_arprot,
input s_axi_arvalid, input s_axi_arvalid,
output s_axi_arready, output reg s_axi_arready,
output reg [4:0] s_axi_rid, output reg [4:0] s_axi_rid,
output reg [31:0] s_axi_rdata, output reg [31:0] s_axi_rdata,
@@ -60,36 +60,38 @@ reg [31:0] a_data [0:15];
reg [31:0] b_data [0:15]; reg [31:0] b_data [0:15];
reg [65:0] c_data [0:15]; reg [65:0] c_data [0:15];
reg [31:0] awaddr_hold; // ══ Write burst state machine (same pattern as fft_controller) ══
reg [4:0] awid_hold; localparam W_IDLE = 2'd0;
reg [7:0] awlen_hold; localparam W_DATA = 2'd1;
reg [7:0] wbeat_cnt; localparam W_RESP = 2'd2;
reg aw_hold_valid; reg [1:0] w_state;
reg rburst_active; reg [31:0] w_addr;
reg [7:0] rburst_rem; reg [4:0] w_id;
reg [31:0] wdata_hold;
reg [3:0] wstrb_hold;
reg w_hold_valid;
wire [11:0] w_offset = w_addr[11:0];
wire w_active = (w_state == W_DATA) && s_axi_wvalid && s_axi_wready;
wire w_start = (w_offset == ADDR_CTRL) && s_axi_wdata[0] && !busy;
assign s_axi_bid = w_id;
assign s_axi_bresp = 2'b00;
// ══ Read burst state machine ══
localparam R_IDLE = 2'd0;
localparam R_DATA = 2'd1;
reg [1:0] r_state;
reg [31:0] r_addr;
reg [4:0] r_id;
reg [7:0] r_cnt;
wire [11:0] r_offset = r_addr[11:0];
assign s_axi_rresp = 2'b00;
// ══ Compute engine ══
reg busy; reg busy;
reg done; reg done;
reg error; reg error;
reg [3:0] calc_index; reg [3:0] calc_index;
wire write_fire;
wire start_fire;
wire [11:0] write_offset = awaddr_hold[11:0];
wire [11:0] read_offset = s_axi_araddr[11:0];
assign s_axi_awready = !aw_hold_valid;
assign s_axi_wready = !w_hold_valid;
assign s_axi_bresp = 2'b00;
assign s_axi_arready = !s_axi_rvalid;
assign s_axi_rresp = 2'b00;
assign write_fire = aw_hold_valid && w_hold_valid && !s_axi_bvalid;
assign start_fire = write_fire && (write_offset == ADDR_CTRL) && wdata_hold[0] && !busy;
function [31:0] apply_wstrb; function [31:0] apply_wstrb;
input [31:0] old_value; input [31:0] old_value;
input [31:0] new_value; input [31:0] new_value;
@@ -194,19 +196,21 @@ always @(posedge clk) begin
src_base <= 32'b0; src_base <= 32'b0;
dst_base <= 32'b0; dst_base <= 32'b0;
group_num <= 32'd1; group_num <= 32'd1;
awaddr_hold <= 32'b0; w_state <= W_IDLE;
awid_hold <= 5'b0; s_axi_awready <= 1'b1;
aw_hold_valid <= 1'b0; s_axi_wready <= 1'b0;
wdata_hold <= 32'b0;
wstrb_hold <= 4'b0;
w_hold_valid <= 1'b0;
s_axi_bid <= 5'b0;
s_axi_bvalid <= 1'b0; s_axi_bvalid <= 1'b0;
wbeat_cnt <= 8'd0; w_addr <= 32'b0;
rburst_active <= 1'b0; w_id <= 5'b0;
r_state <= R_IDLE;
s_axi_arready <= 1'b1;
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
r_addr <= 32'b0;
r_id <= 5'b0;
r_cnt <= 8'b0;
s_axi_rid <= 5'b0; s_axi_rid <= 5'b0;
s_axi_rdata <= 32'b0; s_axi_rdata <= 32'b0;
s_axi_rvalid <= 1'b0;
busy <= 1'b0; busy <= 1'b0;
done <= 1'b0; done <= 1'b0;
error <= 1'b0; error <= 1'b0;
@@ -218,97 +222,141 @@ always @(posedge clk) begin
c_data[i] <= 66'b0; c_data[i] <= 66'b0;
end end
end else begin end else begin
// ═══════════════════════════════════════════════════════
// Write burst FSM (FFT pattern)
// ═══════════════════════════════════════════════════════
case (w_state)
W_IDLE: begin
s_axi_awready <= 1'b1;
if (s_axi_awvalid && s_axi_awready) begin if (s_axi_awvalid && s_axi_awready) begin
awaddr_hold <= s_axi_awaddr; s_axi_awready <= 1'b0;
awid_hold <= s_axi_awid; s_axi_wready <= 1'b1;
awlen_hold <= s_axi_awlen; w_addr <= s_axi_awaddr;
aw_hold_valid <= 1'b1; w_id <= s_axi_awid;
w_state <= W_DATA;
end end
end
W_DATA: begin
if (s_axi_wvalid && s_axi_wready) begin if (s_axi_wvalid && s_axi_wready) begin
wdata_hold <= s_axi_wdata; // Register write
wstrb_hold <= s_axi_wstrb; if (w_offset == ADDR_SRC_BASE) begin
w_hold_valid <= 1'b1; src_base <= apply_wstrb(src_base, s_axi_wdata, s_axi_wstrb);
end end else if (w_offset == ADDR_DST_BASE) begin
dst_base <= apply_wstrb(dst_base, s_axi_wdata, s_axi_wstrb);
if (s_axi_bvalid && s_axi_bready) begin end else if (w_offset == ADDR_GROUP_NUM) begin
s_axi_bvalid <= 1'b0; group_num <= apply_wstrb(group_num, s_axi_wdata, s_axi_wstrb);
end end else if ((w_offset >= ADDR_A_BASE) && (w_offset < ADDR_B_BASE)) begin
a_data[(w_offset - ADDR_A_BASE) >> 2] <=
if (write_fire) begin apply_wstrb(a_data[(w_offset - ADDR_A_BASE) >> 2], s_axi_wdata, s_axi_wstrb);
wbeat_cnt <= wbeat_cnt + 8'd1; end else if ((w_offset >= ADDR_B_BASE) && (w_offset < ADDR_C_BASE)) begin
w_hold_valid <= 1'b0; b_data[(w_offset - ADDR_B_BASE) >> 2] <=
apply_wstrb(b_data[(w_offset - ADDR_B_BASE) >> 2], s_axi_wdata, s_axi_wstrb);
if (s_axi_wlast) begin end else if (w_offset == ADDR_STATUS) begin
s_axi_bid <= awid_hold; if (s_axi_wdata[1]) done <= 1'b0;
s_axi_bvalid <= 1'b1; if (s_axi_wdata[2]) error <= 1'b0;
aw_hold_valid <= 1'b0; end else if ((w_offset != ADDR_CTRL) && (w_offset < ADDR_C_BASE)) begin
wbeat_cnt <= 8'd0;
end
if (write_offset == ADDR_SRC_BASE) begin
src_base <= apply_wstrb(src_base, wdata_hold, wstrb_hold);
end else if (write_offset == ADDR_DST_BASE) begin
dst_base <= apply_wstrb(dst_base, wdata_hold, wstrb_hold);
end else if (write_offset == ADDR_GROUP_NUM) begin
group_num <= apply_wstrb(group_num, wdata_hold, wstrb_hold);
end else if ((write_offset >= ADDR_A_BASE) && (write_offset < ADDR_B_BASE)) begin
a_data[(write_offset - ADDR_A_BASE) >> 2] <=
apply_wstrb(a_data[(write_offset - ADDR_A_BASE) >> 2], wdata_hold, wstrb_hold);
end else if ((write_offset >= ADDR_B_BASE) && (write_offset < ADDR_C_BASE)) begin
b_data[(write_offset - ADDR_B_BASE) >> 2] <=
apply_wstrb(b_data[(write_offset - ADDR_B_BASE) >> 2], wdata_hold, wstrb_hold);
end else if (write_offset == ADDR_STATUS) begin
if (wdata_hold[1]) done <= 1'b0;
if (wdata_hold[2]) error <= 1'b0;
end else if ((write_offset != ADDR_CTRL) && (write_offset < ADDR_C_BASE)) begin
error <= 1'b1; error <= 1'b1;
end end
awaddr_hold[31:0] <= awaddr_hold[31:0] + 32'd4; // Auto-increment address for next beat
end 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
// ═══════════════════════════════════════════════════════
// Read burst FSM (FFT pattern, no BRAM latency)
// ═══════════════════════════════════════════════════════
case (r_state)
R_IDLE: begin
s_axi_arready <= 1'b1;
if (s_axi_arvalid && s_axi_arready) begin if (s_axi_arvalid && s_axi_arready) begin
s_axi_rid <= s_axi_arid; s_axi_arready <= 1'b0;
r_addr <= s_axi_araddr;
r_id <= s_axi_arid;
r_cnt <= 8'd0;
s_axi_rvalid <= 1'b1; s_axi_rvalid <= 1'b1;
s_axi_rlast <= (s_axi_arlen == 8'd0); s_axi_rlast <= (s_axi_arlen == 8'd0);
rburst_rem <= s_axi_arlen;
rburst_active <= (s_axi_arlen > 8'd0);
if (read_offset == ADDR_CTRL) begin // Output data for current address
if (r_offset == ADDR_CTRL)
s_axi_rdata <= 32'b0; s_axi_rdata <= 32'b0;
end else if (read_offset == ADDR_STATUS) begin else if (r_offset == ADDR_STATUS)
s_axi_rdata <= {29'b0, error, done, busy}; s_axi_rdata <= {29'b0, error, done, busy};
end else if (read_offset == ADDR_SRC_BASE) begin else if (r_offset == ADDR_SRC_BASE)
s_axi_rdata <= src_base; s_axi_rdata <= src_base;
end else if (read_offset == ADDR_DST_BASE) begin else if (r_offset == ADDR_DST_BASE)
s_axi_rdata <= dst_base; s_axi_rdata <= dst_base;
end else if (read_offset == ADDR_GROUP_NUM) begin else if (r_offset == ADDR_GROUP_NUM)
s_axi_rdata <= group_num; s_axi_rdata <= group_num;
end else if ((read_offset >= ADDR_A_BASE) && (read_offset < ADDR_B_BASE)) begin else if ((r_offset >= ADDR_A_BASE) && (r_offset < ADDR_B_BASE))
s_axi_rdata <= a_data[(read_offset - ADDR_A_BASE) >> 2]; s_axi_rdata <= a_data[(r_offset - ADDR_A_BASE) >> 2];
end else if ((read_offset >= ADDR_B_BASE) && (read_offset < ADDR_C_BASE)) begin else if ((r_offset >= ADDR_B_BASE) && (r_offset < ADDR_C_BASE))
s_axi_rdata <= b_data[(read_offset - ADDR_B_BASE) >> 2]; s_axi_rdata <= b_data[(r_offset - ADDR_B_BASE) >> 2];
end else if ((read_offset >= ADDR_C_BASE) && (read_offset < (ADDR_C_BASE + 12'h0c0))) begin else if ((r_offset >= ADDR_C_BASE) && (r_offset < (ADDR_C_BASE + 12'h0c0)))
s_axi_rdata <= c_read_word((read_offset - ADDR_C_BASE) >> 2); s_axi_rdata <= c_read_word((r_offset - ADDR_C_BASE) >> 2);
else
s_axi_rdata <= 32'b0;
s_axi_rid <= s_axi_arid;
r_state <= R_DATA;
end
end
R_DATA: begin
if (s_axi_rvalid && s_axi_rready) begin
if (r_cnt == s_axi_arlen) begin
s_axi_rvalid <= 1'b0;
s_axi_rlast <= 1'b0;
s_axi_arready <= 1'b1;
r_state <= R_IDLE;
end else begin end else begin
r_cnt <= r_cnt + 8'd1;
r_addr <= r_addr + 32'd4;
s_axi_rlast <= (r_cnt + 8'd1 == s_axi_arlen);
// Output next beat data
if ((r_offset + 12'd4) == ADDR_CTRL)
s_axi_rdata <= 32'b0;
else if ((r_offset + 12'd4) == ADDR_STATUS)
s_axi_rdata <= {29'b0, error, done, busy};
else if ((r_offset + 12'd4) == ADDR_SRC_BASE)
s_axi_rdata <= src_base;
else if ((r_offset + 12'd4) == ADDR_DST_BASE)
s_axi_rdata <= dst_base;
else if ((r_offset + 12'd4) == ADDR_GROUP_NUM)
s_axi_rdata <= group_num;
else if (((r_offset + 12'd4) >= ADDR_A_BASE) && ((r_offset + 12'd4) < ADDR_B_BASE))
s_axi_rdata <= a_data[((r_offset + 12'd4) - ADDR_A_BASE) >> 2];
else if (((r_offset + 12'd4) >= ADDR_B_BASE) && ((r_offset + 12'd4) < ADDR_C_BASE))
s_axi_rdata <= b_data[((r_offset + 12'd4) - ADDR_B_BASE) >> 2];
else if (((r_offset + 12'd4) >= ADDR_C_BASE) && ((r_offset + 12'd4) < (ADDR_C_BASE + 12'h0c0)))
s_axi_rdata <= c_read_word(((r_offset + 12'd4) - ADDR_C_BASE) >> 2);
else
s_axi_rdata <= 32'b0; s_axi_rdata <= 32'b0;
end end
end else if (s_axi_rvalid && s_axi_rready) begin
if (rburst_active && rburst_rem > 8'd0) begin
s_axi_rdata <= c_read_word((s_axi_araddr[11:0] - ADDR_C_BASE + 12'd4*(s_axi_arlen - rburst_rem + 8'd1)) >> 2);
rburst_rem <= rburst_rem - 8'd1;
s_axi_rlast <= (rburst_rem == 8'd1);
if (rburst_rem == 8'd1) begin
s_axi_rvalid <= 1'b0;
rburst_active <= 1'b0;
end
end else begin
s_axi_rvalid <= 1'b0;
end end
end end
default: r_state <= R_IDLE;
endcase
if (start_fire) begin // ═══════════════════════════════════════════════════════
// Compute engine (unchanged)
// ═══════════════════════════════════════════════════════
if (w_start) begin
busy <= 1'b1; busy <= 1'b1;
done <= 1'b0; done <= 1'b0;
error <= 1'b0; error <= 1'b0;