From 99c85f1a2080da743a3a9a49b6b4c503688aed75 Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Thu, 25 Jun 2026 00:22:30 +0800 Subject: [PATCH] Rewrite burst logic with FFT-style state machine (W_IDLE/DATA/RESP, R_IDLE/DATA) --- rtl/ip/matmul/matmul_axi_slave.v | 302 ++++++++++++++++++------------- 1 file changed, 175 insertions(+), 127 deletions(-) diff --git a/rtl/ip/matmul/matmul_axi_slave.v b/rtl/ip/matmul/matmul_axi_slave.v index d4086b0..b0cb511 100644 --- a/rtl/ip/matmul/matmul_axi_slave.v +++ b/rtl/ip/matmul/matmul_axi_slave.v @@ -11,16 +11,16 @@ module matmul_axi_slave ( input [3:0] s_axi_awcache, input [2:0] s_axi_awprot, input s_axi_awvalid, - output s_axi_awready, + output reg s_axi_awready, 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 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 reg s_axi_bvalid, input s_axi_bready, @@ -34,7 +34,7 @@ module matmul_axi_slave ( input [3:0] s_axi_arcache, input [2:0] s_axi_arprot, input s_axi_arvalid, - output s_axi_arready, + output reg s_axi_arready, output reg [4:0] s_axi_rid, 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 [65:0] c_data [0:15]; -reg [31:0] awaddr_hold; -reg [4:0] awid_hold; -reg [7:0] awlen_hold; -reg [7:0] wbeat_cnt; -reg aw_hold_valid; -reg rburst_active; -reg [7:0] rburst_rem; -reg [31:0] wdata_hold; -reg [3:0] wstrb_hold; -reg w_hold_valid; +// ══ Write burst state machine (same pattern as fft_controller) ══ +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; +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 done; reg error; 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; input [31:0] old_value; input [31:0] new_value; @@ -194,19 +196,21 @@ always @(posedge clk) begin src_base <= 32'b0; dst_base <= 32'b0; group_num <= 32'd1; - awaddr_hold <= 32'b0; - awid_hold <= 5'b0; - aw_hold_valid <= 1'b0; - wdata_hold <= 32'b0; - wstrb_hold <= 4'b0; - w_hold_valid <= 1'b0; - s_axi_bid <= 5'b0; + w_state <= W_IDLE; + s_axi_awready <= 1'b1; + s_axi_wready <= 1'b0; s_axi_bvalid <= 1'b0; - wbeat_cnt <= 8'd0; - rburst_active <= 1'b0; + w_addr <= 32'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_rdata <= 32'b0; - s_axi_rvalid <= 1'b0; busy <= 1'b0; done <= 1'b0; error <= 1'b0; @@ -218,97 +222,141 @@ always @(posedge clk) begin c_data[i] <= 66'b0; end end else begin - if (s_axi_awvalid && s_axi_awready) begin - awaddr_hold <= s_axi_awaddr; - awid_hold <= s_axi_awid; - awlen_hold <= s_axi_awlen; - aw_hold_valid <= 1'b1; - end - - if (s_axi_wvalid && s_axi_wready) begin - wdata_hold <= s_axi_wdata; - wstrb_hold <= s_axi_wstrb; - w_hold_valid <= 1'b1; - end - - if (s_axi_bvalid && s_axi_bready) begin - s_axi_bvalid <= 1'b0; - end - - if (write_fire) begin - wbeat_cnt <= wbeat_cnt + 8'd1; - w_hold_valid <= 1'b0; - - if (s_axi_wlast) begin - s_axi_bid <= awid_hold; - s_axi_bvalid <= 1'b1; - aw_hold_valid <= 1'b0; - 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; - end - - awaddr_hold[31:0] <= awaddr_hold[31:0] + 32'd4; - end - - if (s_axi_arvalid && s_axi_arready) begin - s_axi_rid <= s_axi_arid; - s_axi_rvalid <= 1'b1; - 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 - s_axi_rdata <= 32'b0; - end else if (read_offset == ADDR_STATUS) begin - s_axi_rdata <= {29'b0, error, done, busy}; - end else if (read_offset == ADDR_SRC_BASE) begin - s_axi_rdata <= src_base; - end else if (read_offset == ADDR_DST_BASE) begin - s_axi_rdata <= dst_base; - end else if (read_offset == ADDR_GROUP_NUM) begin - s_axi_rdata <= group_num; - end else if ((read_offset >= ADDR_A_BASE) && (read_offset < ADDR_B_BASE)) begin - s_axi_rdata <= a_data[(read_offset - ADDR_A_BASE) >> 2]; - end else if ((read_offset >= ADDR_B_BASE) && (read_offset < ADDR_C_BASE)) begin - s_axi_rdata <= b_data[(read_offset - ADDR_B_BASE) >> 2]; - end else if ((read_offset >= ADDR_C_BASE) && (read_offset < (ADDR_C_BASE + 12'h0c0))) begin - s_axi_rdata <= c_read_word((read_offset - ADDR_C_BASE) >> 2); - end else begin - s_axi_rdata <= 32'b0; - 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; + // ═══════════════════════════════════════════════════════ + // Write burst FSM (FFT pattern) + // ═══════════════════════════════════════════════════════ + 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_state <= W_DATA; end - end else begin - s_axi_rvalid <= 1'b0; end - end + W_DATA: begin + if (s_axi_wvalid && s_axi_wready) begin + // Register write + if (w_offset == ADDR_SRC_BASE) begin + src_base <= apply_wstrb(src_base, s_axi_wdata, s_axi_wstrb); + end else if (w_offset == ADDR_DST_BASE) begin + dst_base <= apply_wstrb(dst_base, s_axi_wdata, s_axi_wstrb); + end else if (w_offset == ADDR_GROUP_NUM) begin + group_num <= apply_wstrb(group_num, s_axi_wdata, s_axi_wstrb); + end else if ((w_offset >= ADDR_A_BASE) && (w_offset < ADDR_B_BASE)) begin + a_data[(w_offset - ADDR_A_BASE) >> 2] <= + apply_wstrb(a_data[(w_offset - ADDR_A_BASE) >> 2], s_axi_wdata, s_axi_wstrb); + end else if ((w_offset >= ADDR_B_BASE) && (w_offset < ADDR_C_BASE)) begin + b_data[(w_offset - ADDR_B_BASE) >> 2] <= + apply_wstrb(b_data[(w_offset - ADDR_B_BASE) >> 2], s_axi_wdata, s_axi_wstrb); + 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_CTRL) && (w_offset < ADDR_C_BASE)) begin + error <= 1'b1; + end - if (start_fire) begin + // Auto-increment address for next beat + 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 + 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_rlast <= (s_axi_arlen == 8'd0); + + // Output data for current address + if (r_offset == ADDR_CTRL) + s_axi_rdata <= 32'b0; + else if (r_offset == ADDR_STATUS) + s_axi_rdata <= {29'b0, error, done, busy}; + else if (r_offset == ADDR_SRC_BASE) + s_axi_rdata <= src_base; + else if (r_offset == ADDR_DST_BASE) + s_axi_rdata <= dst_base; + else if (r_offset == ADDR_GROUP_NUM) + s_axi_rdata <= group_num; + else if ((r_offset >= ADDR_A_BASE) && (r_offset < ADDR_B_BASE)) + s_axi_rdata <= a_data[(r_offset - ADDR_A_BASE) >> 2]; + else if ((r_offset >= ADDR_B_BASE) && (r_offset < ADDR_C_BASE)) + s_axi_rdata <= b_data[(r_offset - ADDR_B_BASE) >> 2]; + else if ((r_offset >= ADDR_C_BASE) && (r_offset < (ADDR_C_BASE + 12'h0c0))) + 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 + 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; + end + end + end + default: r_state <= R_IDLE; + endcase + + // ═══════════════════════════════════════════════════════ + // Compute engine (unchanged) + // ═══════════════════════════════════════════════════════ + if (w_start) begin busy <= 1'b1; done <= 1'b0; error <= 1'b0; @@ -326,4 +374,4 @@ always @(posedge clk) begin end end -endmodule \ No newline at end of file +endmodule