Split CDMA matmul endpoint engines

This commit is contained in:
2026-07-04 20:42:31 +08:00
parent 2725f6eb57
commit d3a08b1f9d
3 changed files with 408 additions and 315 deletions

View File

@@ -41,16 +41,23 @@ module cdma_matmul_bridge #(
output logic s_axil_rvalid,
input logic s_axil_rready,
output logic cdma_req_valid,
input logic cdma_req_ready,
output logic [1:0] cdma_req_mode,
output logic [ADDR_WIDTH-1:0] cdma_req_src,
output logic [ADDR_WIDTH-1:0] cdma_req_dst,
output logic [31:0] cdma_req_bytes,
output logic [3:0] cdma_req_ep_id,
output logic [3:0] cdma_req_ep_bank,
output logic [7:0] cdma_req_ep_word_off,
input logic cdma_req_done,
output logic cdma_rd_req_valid,
input logic cdma_rd_req_ready,
output logic [ADDR_WIDTH-1:0] cdma_rd_req_src,
output logic [31:0] cdma_rd_req_bytes,
output logic [3:0] cdma_rd_req_ep_id,
output logic [3:0] cdma_rd_req_ep_bank,
output logic [7:0] cdma_rd_req_ep_word_off,
input logic cdma_rd_req_done,
output logic cdma_wr_req_valid,
input logic cdma_wr_req_ready,
output logic [ADDR_WIDTH-1:0] cdma_wr_req_dst,
output logic [31:0] cdma_wr_req_bytes,
output logic [3:0] cdma_wr_req_ep_id,
output logic [3:0] cdma_wr_req_ep_bank,
output logic [7:0] cdma_wr_req_ep_word_off,
input logic cdma_wr_req_done,
output logic mat_start_valid,
output logic mat_start_bank,
@@ -61,9 +68,6 @@ module cdma_matmul_bridge #(
output logic seq_done_irq
);
localparam logic [1:0] MODE_MEM2EP = 2'd1;
localparam logic [1:0] MODE_EP2MEM = 2'd2;
localparam logic [7:0] REG_CTRL = 8'h00;
localparam logic [7:0] REG_STATUS = 8'h04;
localparam logic [7:0] REG_SRC_BASE = 8'h08;
@@ -76,21 +80,6 @@ module cdma_matmul_bridge #(
localparam logic [31:0] MAT_AB_BYTES = 32'd128;
localparam logic [31:0] MAT_C_BYTES = 32'd192;
typedef enum logic [3:0] {
SQ_IDLE,
SQ_CLEAR,
SQ_LOAD_START,
SQ_LOAD_REQ,
SQ_LOAD_WAIT,
SQ_WAIT_DONE,
SQ_STORE_START,
SQ_STORE_REQ,
SQ_STORE_WAIT,
SQ_DONE
} seq_state_t;
seq_state_t seq_state;
logic [31:0] seq_src_base;
logic [31:0] seq_dst_base;
logic [31:0] seq_groups;
@@ -99,21 +88,51 @@ module cdma_matmul_bridge #(
logic [31:0] seq_dst_stride;
logic seq_busy;
logic seq_done_flag;
logic [31:0] seq_load_idx;
logic [31:0] seq_store_idx;
logic seq_compute_bank;
logic seq_skip_writeback;
logic seq_defer_load_start;
logic seq_deferred_start_valid;
logic seq_deferred_start_bank;
logic [31:0] load_next_idx;
logic [31:0] groups_retired;
logic [1:0] bank_load_active;
logic [1:0] bank_ab_valid;
logic [1:0] bank_compute_active;
logic [1:0] bank_store_pending;
logic [1:0] bank_store_active;
logic [31:0] bank_group_idx [2];
logic rd_busy;
logic wr_busy;
logic rd_active_bank;
logic wr_active_bank;
logic [1:0] compute_q;
logic [1:0] compute_q_count;
logic mat_done_seen;
wire [7:0] wr_off = s_axil_awaddr[7:0];
wire [7:0] rd_off = s_axil_araddr[7:0];
wire do_write;
wire start_req = do_write && (wr_off == REG_CTRL) && s_axil_wstrb[0] && s_axil_wdata[0];
wire done_clear_req = do_write && (wr_off == REG_STATUS) && s_axil_wstrb[0] && s_axil_wdata[1];
wire [31:0] src_addr_for_load = seq_src_base + (seq_load_idx * seq_src_stride);
wire [31:0] dst_addr_for_store = seq_dst_base + (seq_store_idx * seq_dst_stride);
wire loaded_bank = seq_load_idx[0];
wire load_target_bank = load_next_idx[0];
wire load_target_free = !bank_load_active[load_target_bank] &&
!bank_ab_valid[load_target_bank] &&
!bank_compute_active[load_target_bank] &&
!bank_store_pending[load_target_bank] &&
!bank_store_active[load_target_bank];
wire bank0_start_ready = bank_ab_valid[0] && !bank_compute_active[0] &&
!bank_store_pending[0] && !bank_store_active[0];
wire bank1_start_ready = bank_ab_valid[1] && !bank_compute_active[1] &&
!bank_store_pending[1] && !bank_store_active[1];
wire start_sel_bank = bank1_start_ready &&
(!bank0_start_ready || (bank_group_idx[1] < bank_group_idx[0]));
wire start_ready_any = bank0_start_ready || bank1_start_ready;
wire store_sel_bank = bank_store_pending[1] && !bank_store_active[1] &&
!(bank_store_pending[0] && !bank_store_active[0]);
wire store_ready_any = (bank_store_pending[0] && !bank_store_active[0]) ||
(bank_store_pending[1] && !bank_store_active[1]);
wire mat_done_event = mat_done && !mat_done_seen;
wire retire_from_store = seq_busy && cdma_wr_req_done;
wire retire_from_compute = seq_busy && seq_skip_writeback && mat_done_event && (compute_q_count != 2'd0);
wire [31:0] retire_inc = {31'd0, retire_from_store} + {31'd0, retire_from_compute};
function automatic logic [31:0] apply_wstrb(
input logic [31:0] old_val,
@@ -128,35 +147,6 @@ module cdma_matmul_bridge #(
end
endfunction
task issue_load_req;
input [31:0] load_idx;
begin
cdma_req_mode <= MODE_MEM2EP;
cdma_req_src <= seq_src_base + (load_idx * seq_src_stride);
cdma_req_dst <= '0;
cdma_req_bytes <= MAT_AB_BYTES;
cdma_req_ep_id <= 4'd0;
cdma_req_ep_bank <= {3'b000, load_idx[0]};
cdma_req_ep_word_off <= 8'd0;
cdma_req_valid <= 1'b1;
seq_state <= SQ_LOAD_REQ;
end
endtask
task issue_store_req;
begin
cdma_req_mode <= MODE_EP2MEM;
cdma_req_src <= '0;
cdma_req_dst <= dst_addr_for_store;
cdma_req_bytes <= MAT_C_BYTES;
cdma_req_ep_id <= 4'd0;
cdma_req_ep_bank <= {3'b000, seq_compute_bank};
cdma_req_ep_word_off <= 8'd0;
cdma_req_valid <= 1'b1;
seq_state <= SQ_STORE_REQ;
end
endtask
assign s_axil_bresp = 2'b00;
assign s_axil_rresp = 2'b00;
assign seq_done_irq = seq_done_flag;
@@ -176,7 +166,7 @@ module cdma_matmul_bridge #(
end
end
wire do_write = s_axil_awready && s_axil_awvalid && s_axil_wready && s_axil_wvalid;
assign do_write = s_axil_awready && s_axil_awvalid && s_axil_wready && s_axil_wvalid;
always_ff @(posedge clk) begin
if (!rst_n) begin
@@ -209,7 +199,7 @@ module cdma_matmul_bridge #(
end else if (do_read) begin
s_axil_rvalid <= 1'b1;
case (rd_off)
REG_CTRL: s_axil_rdata <= {31'd0, start_req};
REG_CTRL: s_axil_rdata <= {30'd0, seq_skip_writeback, 1'b0};
REG_STATUS: s_axil_rdata <= {30'd0, seq_done_flag, seq_busy};
REG_SRC_BASE: s_axil_rdata <= seq_src_base;
REG_DST_BASE: s_axil_rdata <= seq_dst_base;
@@ -248,151 +238,150 @@ module cdma_matmul_bridge #(
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_state <= SQ_IDLE;
seq_busy <= 1'b0;
seq_done_flag <= 1'b0;
seq_load_idx <= 32'd0;
seq_store_idx <= 32'd0;
seq_compute_bank <= 1'b0;
seq_skip_writeback <= 1'b0;
seq_defer_load_start <= 1'b0;
seq_deferred_start_valid <= 1'b0;
seq_deferred_start_bank <= 1'b0;
cdma_req_valid <= 1'b0;
cdma_req_mode <= MODE_MEM2EP;
cdma_req_src <= '0;
cdma_req_dst <= '0;
cdma_req_bytes <= '0;
cdma_req_ep_id <= 4'd0;
cdma_req_ep_bank <= 4'd0;
cdma_req_ep_word_off <= 8'd0;
mat_start_valid <= 1'b0;
mat_start_bank <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
seq_busy <= 1'b0;
seq_done_flag <= 1'b0;
seq_skip_writeback <= 1'b0;
load_next_idx <= 32'd0;
groups_retired <= 32'd0;
bank_load_active <= 2'b00;
bank_ab_valid <= 2'b00;
bank_compute_active <= 2'b00;
bank_store_pending <= 2'b00;
bank_store_active <= 2'b00;
bank_group_idx[0] <= 32'd0;
bank_group_idx[1] <= 32'd0;
rd_busy <= 1'b0;
wr_busy <= 1'b0;
rd_active_bank <= 1'b0;
wr_active_bank <= 1'b0;
compute_q <= 2'b00;
compute_q_count <= 2'd0;
mat_done_seen <= 1'b0;
cdma_rd_req_valid <= 1'b0;
cdma_rd_req_src <= '0;
cdma_rd_req_bytes <= '0;
cdma_rd_req_ep_id <= 4'd0;
cdma_rd_req_ep_bank <= 4'd0;
cdma_rd_req_ep_word_off <= 8'd0;
cdma_wr_req_valid <= 1'b0;
cdma_wr_req_dst <= '0;
cdma_wr_req_bytes <= '0;
cdma_wr_req_ep_id <= 4'd0;
cdma_wr_req_ep_bank <= 4'd0;
cdma_wr_req_ep_word_off <= 8'd0;
mat_start_valid <= 1'b0;
mat_start_bank <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
end else begin
mat_start_valid <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
mat_done_seen <= mat_done;
if (done_clear_req)
seq_done_flag <= 1'b0;
case (seq_state)
SQ_IDLE: begin
seq_busy <= 1'b0;
cdma_req_valid <= 1'b0;
if (start_req && (seq_groups != 32'd0)) begin
seq_busy <= 1'b1;
seq_done_flag <= 1'b0;
seq_load_idx <= 32'd0;
seq_store_idx <= 32'd0;
seq_compute_bank <= 1'b0;
seq_skip_writeback <= s_axil_wstrb[0] && s_axil_wdata[1];
seq_defer_load_start <= 1'b0;
seq_deferred_start_valid <= 1'b0;
seq_deferred_start_bank <= 1'b0;
mat_crc_clear <= 1'b1;
mat_done_clear <= 1'b1;
seq_state <= SQ_CLEAR;
if (cdma_rd_req_valid && cdma_rd_req_ready)
cdma_rd_req_valid <= 1'b0;
if (cdma_wr_req_valid && cdma_wr_req_ready)
cdma_wr_req_valid <= 1'b0;
if (start_req && !seq_busy && (seq_groups != 32'd0)) begin
seq_busy <= 1'b1;
seq_done_flag <= 1'b0;
seq_skip_writeback <= s_axil_wstrb[0] && s_axil_wdata[1];
load_next_idx <= 32'd0;
groups_retired <= 32'd0;
bank_load_active <= 2'b00;
bank_ab_valid <= 2'b00;
bank_compute_active <= 2'b00;
bank_store_pending <= 2'b00;
bank_store_active <= 2'b00;
bank_group_idx[0] <= 32'd0;
bank_group_idx[1] <= 32'd0;
rd_busy <= 1'b0;
wr_busy <= 1'b0;
compute_q <= 2'b00;
compute_q_count <= 2'd0;
mat_done_seen <= 1'b1;
mat_crc_clear <= 1'b1;
mat_done_clear <= 1'b1;
cdma_rd_req_valid <= 1'b0;
cdma_wr_req_valid <= 1'b0;
end else if (seq_busy) begin
if (retire_inc != 32'd0) begin
groups_retired <= groups_retired + retire_inc;
if ((groups_retired + retire_inc) >= seq_groups) begin
seq_busy <= 1'b0;
seq_done_flag <= 1'b1;
end
end
SQ_CLEAR: begin
issue_load_req(32'd0);
if (cdma_rd_req_done) begin
rd_busy <= 1'b0;
bank_load_active[rd_active_bank] <= 1'b0;
bank_ab_valid[rd_active_bank] <= 1'b1;
end
SQ_LOAD_START: begin
issue_load_req(seq_load_idx);
if (cdma_wr_req_done) begin
wr_busy <= 1'b0;
bank_store_active[wr_active_bank] <= 1'b0;
end
SQ_LOAD_REQ: begin
if (cdma_req_valid && cdma_req_ready) begin
cdma_req_valid <= 1'b0;
seq_state <= SQ_LOAD_WAIT;
if (mat_done_event && (compute_q_count != 2'd0)) begin
mat_done_clear <= 1'b1;
mat_done_seen <= 1'b1;
bank_compute_active[compute_q[0]] <= 1'b0;
if (!seq_skip_writeback) begin
bank_store_pending[compute_q[0]] <= 1'b1;
end
if (compute_q_count == 2'd2)
compute_q[0] <= compute_q[1];
compute_q_count <= compute_q_count - 2'd1;
end
SQ_LOAD_WAIT: begin
if (cdma_req_done) begin
seq_load_idx <= seq_load_idx + 32'd1;
if (seq_defer_load_start) begin
seq_defer_load_start <= 1'b0;
seq_deferred_start_valid <= 1'b1;
seq_deferred_start_bank <= cdma_req_ep_bank[0];
issue_store_req();
end else begin
mat_start_valid <= 1'b1;
mat_start_bank <= cdma_req_ep_bank[0];
if ((seq_load_idx + 32'd1) < seq_groups && (seq_load_idx == 32'd0)) begin
issue_load_req(seq_load_idx + 32'd1);
end else begin
seq_state <= SQ_WAIT_DONE;
end
end
end
if (!rd_busy && !cdma_rd_req_valid && (load_next_idx < seq_groups) && load_target_free) begin
cdma_rd_req_src <= seq_src_base + (load_next_idx * seq_src_stride);
cdma_rd_req_bytes <= MAT_AB_BYTES;
cdma_rd_req_ep_id <= 4'd0;
cdma_rd_req_ep_bank <= {3'b000, load_target_bank};
cdma_rd_req_ep_word_off <= 8'd0;
cdma_rd_req_valid <= 1'b1;
rd_busy <= 1'b1;
rd_active_bank <= load_target_bank;
bank_load_active[load_target_bank] <= 1'b1;
bank_group_idx[load_target_bank] <= load_next_idx;
load_next_idx <= load_next_idx + 32'd1;
end
SQ_WAIT_DONE: begin
if (mat_done) begin
mat_done_clear <= 1'b1;
if (seq_skip_writeback) begin
seq_store_idx <= seq_store_idx + 32'd1;
seq_compute_bank <= ~seq_compute_bank;
if ((seq_store_idx + 32'd1) >= seq_groups) begin
seq_state <= SQ_DONE;
end else if (seq_load_idx < seq_groups) begin
issue_load_req(seq_load_idx);
end else begin
seq_state <= SQ_WAIT_DONE;
end
end else if (seq_load_idx < seq_groups) begin
seq_defer_load_start <= 1'b1;
issue_load_req(seq_load_idx);
end else begin
issue_store_req();
end
end
if (!seq_skip_writeback && !wr_busy && !cdma_wr_req_valid && store_ready_any) begin
cdma_wr_req_dst <= seq_dst_base + (bank_group_idx[store_sel_bank] * seq_dst_stride);
cdma_wr_req_bytes <= MAT_C_BYTES;
cdma_wr_req_ep_id <= 4'd0;
cdma_wr_req_ep_bank <= {3'b000, store_sel_bank};
cdma_wr_req_ep_word_off <= 8'd0;
cdma_wr_req_valid <= 1'b1;
wr_busy <= 1'b1;
wr_active_bank <= store_sel_bank;
bank_store_pending[store_sel_bank] <= 1'b0;
bank_store_active[store_sel_bank] <= 1'b1;
end
SQ_STORE_START: begin
issue_store_req();
if ((compute_q_count < 2'd2) && start_ready_any && !(mat_done_event && (compute_q_count != 2'd0))) begin
mat_start_valid <= 1'b1;
mat_start_bank <= start_sel_bank;
bank_ab_valid[start_sel_bank] <= 1'b0;
bank_compute_active[start_sel_bank] <= 1'b1;
if (compute_q_count == 2'd0)
compute_q[0] <= start_sel_bank;
else
compute_q[1] <= start_sel_bank;
compute_q_count <= compute_q_count + 2'd1;
end
SQ_STORE_REQ: begin
if (cdma_req_valid && cdma_req_ready) begin
cdma_req_valid <= 1'b0;
seq_state <= SQ_STORE_WAIT;
end
end
SQ_STORE_WAIT: begin
if (cdma_req_done) begin
seq_store_idx <= seq_store_idx + 32'd1;
seq_compute_bank <= ~seq_compute_bank;
if (seq_deferred_start_valid) begin
mat_start_valid <= 1'b1;
mat_start_bank <= seq_deferred_start_bank;
seq_deferred_start_valid <= 1'b0;
end
if ((seq_store_idx + 32'd1) >= seq_groups) begin
seq_state <= SQ_DONE;
end else if (seq_load_idx < seq_groups) begin
seq_state <= SQ_WAIT_DONE;
end else begin
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_DONE: begin
seq_busy <= 1'b0;
seq_done_flag <= 1'b1;
seq_state <= SQ_IDLE;
end
default: seq_state <= SQ_IDLE;
endcase
end
end
end