Add standalone CDMA matmul bridge

This commit is contained in:
2026-07-04 19:35:42 +08:00
parent b7553418fa
commit bf6051c8c6
3 changed files with 611 additions and 279 deletions

View File

@@ -0,0 +1,347 @@
// ============================================================================
// cdma_matmul_bridge.sv
// Matmul-specific sequencer between the generic CDMA endpoint requester and
// the matmul local endpoint/control interface.
//
// AXI-Lite register map, relative to this bridge window:
// 0x00 CTRL bit0 start
// 0x04 STATUS bit0 busy, bit1 done (W1C)
// 0x08 SRC_BASE physical ExtRAM input base
// 0x0C DST_BASE physical ExtRAM result base
// 0x10 GROUPS
// 0x14 MAT_BASE reserved for software compatibility
// 0x18 SRC_STRIDE bytes, default 128
// 0x1C DST_STRIDE bytes, default 192
// ============================================================================
`timescale 1ns / 1ps
module cdma_matmul_bridge #(
parameter int ADDR_WIDTH = 32,
parameter int AXIL_ADDR_WIDTH = 32,
parameter int AXIL_DATA_WIDTH = 32
) (
input logic clk,
input logic rst_n,
input logic [AXIL_ADDR_WIDTH-1:0] s_axil_awaddr,
input logic s_axil_awvalid,
output logic s_axil_awready,
input logic [AXIL_DATA_WIDTH-1:0] s_axil_wdata,
input logic [AXIL_DATA_WIDTH/8-1:0] s_axil_wstrb,
input logic s_axil_wvalid,
output logic s_axil_wready,
output logic [1:0] s_axil_bresp,
output logic s_axil_bvalid,
input logic s_axil_bready,
input logic [AXIL_ADDR_WIDTH-1:0] s_axil_araddr,
input logic s_axil_arvalid,
output logic s_axil_arready,
output logic [AXIL_DATA_WIDTH-1:0] s_axil_rdata,
output logic [1:0] s_axil_rresp,
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 mat_start_valid,
output logic mat_start_bank,
output logic mat_done_clear,
output logic mat_crc_clear,
input logic mat_done,
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;
localparam logic [7:0] REG_DST_BASE = 8'h0C;
localparam logic [7:0] REG_GROUPS = 8'h10;
localparam logic [7:0] REG_MAT_BASE = 8'h14;
localparam logic [7:0] REG_SRC_STRIDE = 8'h18;
localparam logic [7:0] REG_DST_STRIDE = 8'h1C;
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;
logic [31:0] seq_mat_base;
logic [31:0] seq_src_stride;
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;
wire [7:0] wr_off = s_axil_awaddr[7:0];
wire [7:0] rd_off = s_axil_araddr[7:0];
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];
function automatic logic [31:0] apply_wstrb(
input logic [31:0] old_val,
input logic [31:0] new_val,
input logic [3:0] wstrb
);
begin
apply_wstrb[7:0] = wstrb[0] ? new_val[7:0] : old_val[7:0];
apply_wstrb[15:8] = wstrb[1] ? new_val[15:8] : old_val[15:8];
apply_wstrb[23:16] = wstrb[2] ? new_val[23:16] : old_val[23:16];
apply_wstrb[31:24] = wstrb[3] ? new_val[31:24] : old_val[31:24];
end
endfunction
assign s_axil_bresp = 2'b00;
assign s_axil_rresp = 2'b00;
assign seq_done_irq = seq_done_flag;
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_awready <= 1'b0;
s_axil_wready <= 1'b0;
end else begin
if (s_axil_awvalid && s_axil_wvalid && !s_axil_awready && (!s_axil_bvalid || s_axil_bready)) begin
s_axil_awready <= 1'b1;
s_axil_wready <= 1'b1;
end else begin
s_axil_awready <= 1'b0;
s_axil_wready <= 1'b0;
end
end
end
wire do_write = s_axil_awready && s_axil_awvalid && s_axil_wready && s_axil_wvalid;
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_bvalid <= 1'b0;
end else if (do_write) begin
s_axil_bvalid <= 1'b1;
end else if (s_axil_bready && s_axil_bvalid) begin
s_axil_bvalid <= 1'b0;
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_arready <= 1'b0;
end else begin
if (s_axil_arvalid && !s_axil_arready && (!s_axil_rvalid || s_axil_rready)) begin
s_axil_arready <= 1'b1;
end else begin
s_axil_arready <= 1'b0;
end
end
end
wire do_read = s_axil_arready && s_axil_arvalid;
always_ff @(posedge clk) begin
if (!rst_n) begin
s_axil_rvalid <= 1'b0;
s_axil_rdata <= '0;
end else if (do_read) begin
s_axil_rvalid <= 1'b1;
case (rd_off)
REG_CTRL: s_axil_rdata <= {31'd0, start_req};
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;
REG_GROUPS: s_axil_rdata <= seq_groups;
REG_MAT_BASE: s_axil_rdata <= seq_mat_base;
REG_SRC_STRIDE: s_axil_rdata <= seq_src_stride;
REG_DST_STRIDE: s_axil_rdata <= seq_dst_stride;
default: s_axil_rdata <= 32'd0;
endcase
end else if (s_axil_rready && s_axil_rvalid) begin
s_axil_rvalid <= 1'b0;
end
end
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_src_base <= 32'h0;
seq_dst_base <= 32'h0;
seq_groups <= 32'h0;
seq_mat_base <= 32'h1f50_0000;
seq_src_stride <= 32'd128;
seq_dst_stride <= 32'd192;
end else if (do_write) begin
case (wr_off)
REG_SRC_BASE: if (!seq_busy) seq_src_base <= apply_wstrb(seq_src_base, s_axil_wdata, s_axil_wstrb);
REG_DST_BASE: if (!seq_busy) seq_dst_base <= apply_wstrb(seq_dst_base, s_axil_wdata, s_axil_wstrb);
REG_GROUPS: if (!seq_busy) seq_groups <= apply_wstrb(seq_groups, s_axil_wdata, s_axil_wstrb);
REG_MAT_BASE: if (!seq_busy) seq_mat_base <= apply_wstrb(seq_mat_base, s_axil_wdata, s_axil_wstrb);
REG_SRC_STRIDE: if (!seq_busy) seq_src_stride <= apply_wstrb(seq_src_stride, s_axil_wdata, s_axil_wstrb);
REG_DST_STRIDE: if (!seq_busy) seq_dst_stride <= apply_wstrb(seq_dst_stride, s_axil_wdata, s_axil_wstrb);
default: begin
end
endcase
end
end
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;
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;
end else begin
mat_start_valid <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
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;
mat_crc_clear <= 1'b1;
mat_done_clear <= 1'b1;
seq_state <= SQ_CLEAR;
end
end
SQ_CLEAR: begin
seq_state <= SQ_LOAD_START;
end
SQ_LOAD_START: begin
cdma_req_mode <= MODE_MEM2EP;
cdma_req_src <= src_addr_for_load;
cdma_req_dst <= '0;
cdma_req_bytes <= MAT_AB_BYTES;
cdma_req_ep_id <= 4'd0;
cdma_req_ep_bank <= {3'b000, loaded_bank};
cdma_req_ep_word_off <= 8'd0;
cdma_req_valid <= 1'b1;
seq_state <= SQ_LOAD_REQ;
end
SQ_LOAD_REQ: begin
if (cdma_req_valid && cdma_req_ready) begin
cdma_req_valid <= 1'b0;
seq_state <= SQ_LOAD_WAIT;
end
end
SQ_LOAD_WAIT: begin
if (cdma_req_done) begin
mat_start_valid <= 1'b1;
mat_start_bank <= cdma_req_ep_bank[0];
seq_load_idx <= seq_load_idx + 32'd1;
if ((seq_load_idx + 32'd1) < seq_groups && (seq_load_idx == 32'd0)) begin
seq_state <= SQ_LOAD_START;
end else begin
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_WAIT_DONE: begin
if (mat_done) begin
mat_done_clear <= 1'b1;
seq_state <= SQ_STORE_START;
end
end
SQ_STORE_START: 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
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_store_idx + 32'd1) >= seq_groups) begin
seq_state <= SQ_DONE;
end else if (seq_load_idx < seq_groups) begin
seq_state <= SQ_LOAD_START;
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
endmodule

View File

@@ -112,13 +112,18 @@ module snix_axil_cdma_mux #(
input logic ep_rd_ready,
// ==========================================
// Matmul direct control sideband
// Generic external endpoint requester
// ==========================================
output logic mat_start_valid,
output logic mat_start_bank,
output logic mat_done_clear,
output logic mat_crc_clear,
input logic mat_done,
input logic ext_req_valid,
output logic ext_req_ready,
input logic [1:0] ext_req_mode,
input logic [ADDR_WIDTH-1:0] ext_req_src,
input logic [ADDR_WIDTH-1:0] ext_req_dst,
input logic [31:0] ext_req_bytes,
input logic [3:0] ext_req_ep_id,
input logic [3:0] ext_req_ep_bank,
input logic [7:0] ext_req_ep_word_off,
output logic ext_req_done,
// Global Interrupt (OR'd from all channels)
output logic dma_finish
@@ -132,26 +137,6 @@ module snix_axil_cdma_mux #(
localparam logic [1:0] MODE_MEM2EP = 2'd1;
localparam logic [1:0] MODE_EP2MEM = 2'd2;
localparam logic [7:0] SEQ_REG_CTRL = 8'h00;
localparam logic [7:0] SEQ_REG_STATUS = 8'h04;
localparam logic [7:0] SEQ_REG_SRC_BASE = 8'h08;
localparam logic [7:0] SEQ_REG_DST_BASE = 8'h0C;
localparam logic [7:0] SEQ_REG_GROUPS = 8'h10;
localparam logic [7:0] SEQ_REG_MAT_BASE = 8'h14;
localparam logic [7:0] SEQ_REG_SRC_STRIDE = 8'h18;
localparam logic [7:0] SEQ_REG_DST_STRIDE = 8'h1C;
localparam logic [11:0] MAT_CTRL_OFF = 12'h000;
localparam logic [11:0] MAT_STATUS_OFF = 12'h004;
localparam logic [11:0] MAT_CRC_OFF = 12'h010;
localparam logic [11:0] MAT_B0_AB_OFF = 12'h100;
localparam logic [11:0] MAT_B0_C_OFF = 12'h180;
localparam logic [11:0] MAT_B1_AB_OFF = 12'h300;
localparam logic [11:0] MAT_B1_C_OFF = 12'h380;
localparam logic [31:0] MAT_AB_BYTES = 32'd128;
localparam logic [31:0] MAT_C_BYTES = 32'd192;
// Function to safely apply WSTRB to 32-bit registers
function automatic logic [31:0] apply_wstrb(
input logic [31:0] old_val,
@@ -182,17 +167,6 @@ module snix_axil_cdma_mux #(
logic [PORTS-1:0] arb_set_done; // From Arbiter to CSR
logic [31:0] seq_src_base;
logic [31:0] seq_dst_base;
logic [31:0] seq_groups;
logic [31:0] seq_mat_base;
logic [31:0] seq_src_stride;
logic [31:0] seq_dst_stride;
logic seq_busy;
logic seq_done_flag;
wire seq_start_req;
wire seq_done_clear_req;
// ==========================================
// Address Decoding (0x40 offset per channel)
// ==========================================
@@ -200,14 +174,6 @@ module snix_axil_cdma_mux #(
wire [5:0] wr_reg = s_axil_awaddr[5:0];
wire [CH_BITS-1:0] rd_ch = s_axil_araddr[6 +: CH_BITS];
wire [5:0] rd_reg = s_axil_araddr[5:0];
wire wr_seq_reg = (s_axil_awaddr[11:8] == 4'h2);
wire rd_seq_reg = (s_axil_araddr[11:8] == 4'h2);
wire [7:0] wr_seq_off = s_axil_awaddr[7:0];
wire [7:0] rd_seq_off = s_axil_araddr[7:0];
assign seq_start_req = do_write && wr_seq_reg && (wr_seq_off == SEQ_REG_CTRL) &&
s_axil_wstrb[0] && s_axil_wdata[0];
assign seq_done_clear_req = do_write && wr_seq_reg && (wr_seq_off == SEQ_REG_STATUS) &&
s_axil_wstrb[0] && s_axil_wdata[1];
// ==========================================
// AXI-Lite Slave Logic (Robust Backpressure)
@@ -267,19 +233,7 @@ module snix_axil_cdma_mux #(
end else begin
if (do_read) begin
s_axil_rvalid <= 1'b1;
if (rd_seq_reg) begin
case (rd_seq_off)
SEQ_REG_CTRL: s_axil_rdata <= {31'd0, seq_start_req};
SEQ_REG_STATUS: s_axil_rdata <= {30'd0, seq_done_flag, seq_busy};
SEQ_REG_SRC_BASE: s_axil_rdata <= seq_src_base;
SEQ_REG_DST_BASE: s_axil_rdata <= seq_dst_base;
SEQ_REG_GROUPS: s_axil_rdata <= seq_groups;
SEQ_REG_MAT_BASE: s_axil_rdata <= seq_mat_base;
SEQ_REG_SRC_STRIDE: s_axil_rdata <= seq_src_stride;
SEQ_REG_DST_STRIDE: s_axil_rdata <= seq_dst_stride;
default: s_axil_rdata <= 32'd0;
endcase
end else if (rd_ch < PORTS) begin
if (rd_ch < PORTS) begin
case (rd_reg)
6'h00: s_axil_rdata <= ch_src_addr[rd_ch];
6'h04: s_axil_rdata <= ch_dst_addr[rd_ch];
@@ -303,18 +257,12 @@ module snix_axil_cdma_mux #(
// ==========================================
// Register File Write Logic
// ==========================================
assign dma_finish = (|ch_done) | seq_done_flag;
assign dma_finish = |ch_done;
always_ff @(posedge clk) begin
if (!rst_n) begin
ch_req <= '0;
ch_done <= '0;
seq_src_base <= 32'h0;
seq_dst_base <= 32'h0;
seq_groups <= 32'h0;
seq_mat_base <= 32'h1f50_0000;
seq_src_stride <= 32'd128;
seq_dst_stride <= 32'd192;
for (int i=0; i<PORTS; i++) begin
ch_src_addr[i] <= '0; ch_dst_addr[i] <= '0;
ch_len[i] <= '0; ch_tag[i] <= '0; ch_ctrl[i] <= '0;
@@ -330,16 +278,7 @@ module snix_axil_cdma_mux #(
end
// 2. Process CPU Writes
if (do_write && wr_seq_reg) begin
case (wr_seq_off)
SEQ_REG_SRC_BASE: if (!seq_busy) seq_src_base <= apply_wstrb(seq_src_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_DST_BASE: if (!seq_busy) seq_dst_base <= apply_wstrb(seq_dst_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_GROUPS: if (!seq_busy) seq_groups <= apply_wstrb(seq_groups, s_axil_wdata, s_axil_wstrb);
SEQ_REG_MAT_BASE: if (!seq_busy) seq_mat_base <= apply_wstrb(seq_mat_base, s_axil_wdata, s_axil_wstrb);
SEQ_REG_SRC_STRIDE: if (!seq_busy) seq_src_stride <= apply_wstrb(seq_src_stride, s_axil_wdata, s_axil_wstrb);
SEQ_REG_DST_STRIDE: if (!seq_busy) seq_dst_stride <= apply_wstrb(seq_dst_stride, s_axil_wdata, s_axil_wstrb);
endcase
end else if (do_write && wr_ch < PORTS) begin
if (do_write && wr_ch < PORTS) begin
case (wr_reg)
6'h00: if (!ch_req[wr_ch]) ch_src_addr[wr_ch] <= apply_wstrb(ch_src_addr[wr_ch], s_axil_wdata, s_axil_wstrb);
6'h04: if (!ch_req[wr_ch]) ch_dst_addr[wr_ch] <= apply_wstrb(ch_dst_addr[wr_ch], s_axil_wdata, s_axil_wstrb);
@@ -461,57 +400,39 @@ module snix_axil_cdma_mux #(
logic ep_arready;
logic ep_rready;
// Hardware matmul loop sequencer state. The sequencer uses the endpoint
// path below, so matmul register/memory traffic does not enter the AXI bus.
typedef enum logic [4:0] {
SQ_IDLE,
SQ_CLEAR,
SQ_LOAD,
SQ_LOAD_WAIT,
SQ_WAIT_DONE,
SQ_STORE_START,
SQ_STORE,
SQ_DONE
} seq_state_t;
logic ext_active;
logic ext_start_pulse;
logic [1:0] ext_mode_r;
logic [ADDR_WIDTH-1:0] ext_src_r;
logic [ADDR_WIDTH-1:0] ext_dst_r;
logic [31:0] ext_bytes_r;
logic [3:0] ext_ep_id_r;
logic [3:0] ext_ep_bank_r;
logic [7:0] ext_ep_word_off_r;
seq_state_t seq_state;
logic [31:0] seq_group_idx;
logic [31:0] seq_load_idx;
logic [31:0] seq_store_idx;
logic seq_compute_bank;
logic seq_ep_owner;
logic seq_ep_start;
logic [1:0] seq_ep_mode;
logic [31:0] seq_ep_src;
logic [31:0] seq_ep_dst;
logic [31:0] seq_ep_bytes;
logic seq_ep_bank;
wire use_seq_engine = 1'b0;
wire use_ep_engine = ((state == RUN) && (engine_mode != MODE_MEM2MEM)) || seq_ep_owner;
wire select_seq_ep = seq_ep_owner || seq_ep_start;
wire use_ep_engine = ((state == RUN) && (engine_mode != MODE_MEM2MEM)) || ext_active || ext_start_pulse;
wire select_ext_ep = ext_active || ext_start_pulse;
// Dynamic routing to the engine based on current active channel
assign engine_src = select_seq_ep ? seq_ep_src : ch_src_addr[cur_ch];
assign engine_dst = select_seq_ep ? seq_ep_dst : ch_dst_addr[cur_ch];
assign engine_bytes = select_seq_ep ? seq_ep_bytes : ch_len[cur_ch];
assign engine_src = select_ext_ep ? ext_src_r : ch_src_addr[cur_ch];
assign engine_dst = select_ext_ep ? ext_dst_r : ch_dst_addr[cur_ch];
assign engine_bytes = select_ext_ep ? ext_bytes_r : ch_len[cur_ch];
assign engine_len = ch_ctrl[cur_ch][13:6];
assign engine_size = ch_ctrl[cur_ch][5:3];
assign engine_mode = select_seq_ep ? seq_ep_mode : ch_mode[cur_ch][1:0];
assign engine_ep_bank = select_seq_ep ? {3'b000, seq_ep_bank} : ch_ep_cfg[cur_ch][3:0];
assign engine_ep_word_off = select_seq_ep ? 8'd0 : ch_ep_cfg[cur_ch][15:8];
assign engine_ep_id = select_seq_ep ? 4'd0 : ch_ep_cfg[cur_ch][19:16];
assign engine_mode = select_ext_ep ? ext_mode_r : ch_mode[cur_ch][1:0];
assign engine_ep_bank = select_ext_ep ? ext_ep_bank_r : ch_ep_cfg[cur_ch][3:0];
assign engine_ep_word_off = select_ext_ep ? ext_ep_word_off_r : ch_ep_cfg[cur_ch][15:8];
assign engine_ep_id = select_ext_ep ? ext_ep_id_r : ch_ep_cfg[cur_ch][19:16];
assign engine_done = (engine_mode == MODE_MEM2MEM) ? mm2mm_done : ep_done;
assign mm2mm_start = engine_start && (engine_mode == MODE_MEM2MEM);
assign ep_start = seq_ep_start || (engine_start && (engine_mode != MODE_MEM2MEM));
assign ep_start = ext_start_pulse || (engine_start && (engine_mode != MODE_MEM2MEM));
assign core_awready = (!use_seq_engine && !use_ep_engine) && mm2mm_awready;
assign core_wready = (!use_seq_engine && !use_ep_engine) && mm2mm_wready;
assign core_arready = (!use_seq_engine && !use_ep_engine) && mm2mm_arready;
assign ep_awready = (!use_seq_engine && use_ep_engine) && mm2mm_awready;
assign ep_wready = (!use_seq_engine && use_ep_engine) && mm2mm_wready;
assign ep_arready = (!use_seq_engine && use_ep_engine) && mm2mm_arready;
assign core_awready = (!use_ep_engine) && mm2mm_awready;
assign core_wready = (!use_ep_engine) && mm2mm_wready;
assign core_arready = (!use_ep_engine) && mm2mm_arready;
assign ep_awready = use_ep_engine && mm2mm_awready;
assign ep_wready = use_ep_engine && mm2mm_wready;
assign ep_arready = use_ep_engine && mm2mm_arready;
assign mm2mm_awid = use_ep_engine ? ep_awid : core_awid;
assign mm2mm_awaddr = use_ep_engine ? ep_awaddr : core_awaddr;
@@ -558,7 +479,7 @@ module snix_axil_cdma_mux #(
case (state)
IDLE: begin
if (seq_busy) begin
if (ext_req_valid || ext_active) begin
state <= IDLE;
end else for (int i = 0; i < PORTS; i++) begin
logic [CH_BITS:0] check_ch_ext;
@@ -639,133 +560,40 @@ module snix_axil_cdma_mux #(
);
// ==========================================
// Direct matmul endpoint sequencer
// Generic external endpoint requester
// ==========================================
wire [31:0] seq_src_addr_for_load = seq_src_base + (seq_load_idx * seq_src_stride);
wire [31:0] seq_dst_addr_for_store = seq_dst_base + (seq_store_idx * seq_dst_stride);
wire seq_loaded_bank = seq_load_idx[0];
assign ext_req_ready = !ext_active && (state == IDLE);
always_ff @(posedge clk) begin
if (!rst_n) begin
seq_state <= SQ_IDLE;
seq_busy <= 1'b0;
seq_done_flag <= 1'b0;
seq_group_idx <= '0;
seq_load_idx <= '0;
seq_store_idx <= '0;
seq_compute_bank <= 1'b0;
seq_ep_owner <= 1'b0;
seq_ep_start <= 1'b0;
seq_ep_mode <= MODE_MEM2EP;
seq_ep_src <= '0;
seq_ep_dst <= '0;
seq_ep_bytes <= '0;
seq_ep_bank <= 1'b0;
mat_start_valid <= 1'b0;
mat_start_bank <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
ext_active <= 1'b0;
ext_start_pulse <= 1'b0;
ext_req_done <= 1'b0;
ext_mode_r <= MODE_MEM2EP;
ext_src_r <= '0;
ext_dst_r <= '0;
ext_bytes_r <= '0;
ext_ep_id_r <= '0;
ext_ep_bank_r <= '0;
ext_ep_word_off_r <= '0;
end else begin
seq_ep_start <= 1'b0;
mat_start_valid <= 1'b0;
mat_done_clear <= 1'b0;
mat_crc_clear <= 1'b0;
ext_start_pulse <= 1'b0;
ext_req_done <= 1'b0;
if (seq_ep_start)
seq_ep_owner <= 1'b1;
else if (seq_ep_owner && ep_done)
seq_ep_owner <= 1'b0;
if (seq_done_clear_req)
seq_done_flag <= 1'b0;
case (seq_state)
SQ_IDLE: begin
seq_busy <= 1'b0;
if (seq_start_req && (seq_groups != 32'd0)) begin
seq_busy <= 1'b1;
seq_done_flag <= 1'b0;
seq_group_idx <= 32'd0;
seq_load_idx <= 32'd0;
seq_store_idx <= 32'd0;
seq_compute_bank <= 1'b0;
mat_crc_clear <= 1'b1;
mat_done_clear <= 1'b1;
seq_state <= SQ_CLEAR;
end
end
SQ_CLEAR: begin
seq_state <= SQ_LOAD;
end
SQ_LOAD: begin
if (!seq_ep_owner && !seq_ep_start) begin
seq_ep_mode <= MODE_MEM2EP;
seq_ep_src <= seq_src_addr_for_load;
seq_ep_dst <= '0;
seq_ep_bytes <= MAT_AB_BYTES;
seq_ep_bank <= seq_loaded_bank;
seq_ep_start <= 1'b1;
seq_state <= SQ_LOAD_WAIT;
end
end
SQ_LOAD_WAIT: begin
if (seq_ep_owner && ep_done) begin
mat_start_valid <= 1'b1;
mat_start_bank <= seq_ep_bank;
seq_load_idx <= seq_load_idx + 32'd1;
if ((seq_load_idx + 32'd1) < seq_groups && (seq_load_idx == 32'd0)) begin
seq_state <= SQ_LOAD;
end else begin
seq_state <= SQ_WAIT_DONE;
end
end
end
SQ_WAIT_DONE: begin
if (mat_done) begin
mat_done_clear <= 1'b1;
seq_state <= SQ_STORE_START;
end
end
SQ_STORE_START: begin
if (!seq_ep_owner && !seq_ep_start) begin
seq_ep_mode <= MODE_EP2MEM;
seq_ep_src <= '0;
seq_ep_dst <= seq_dst_addr_for_store;
seq_ep_bytes <= MAT_C_BYTES;
seq_ep_bank <= seq_compute_bank;
seq_ep_start <= 1'b1;
seq_state <= SQ_STORE;
end
end
SQ_STORE: begin
if (seq_ep_owner && ep_done) begin
seq_store_idx <= seq_store_idx + 32'd1;
seq_group_idx <= seq_group_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
seq_state <= SQ_LOAD;
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
if (ext_req_valid && ext_req_ready) begin
ext_active <= 1'b1;
ext_start_pulse <= 1'b1;
ext_mode_r <= ext_req_mode;
ext_src_r <= ext_req_src;
ext_dst_r <= ext_req_dst;
ext_bytes_r <= ext_req_bytes;
ext_ep_id_r <= ext_req_ep_id;
ext_ep_bank_r <= ext_req_ep_bank;
ext_ep_word_off_r <= ext_req_ep_word_off;
end else if (ext_active && ep_done) begin
ext_active <= 1'b0;
ext_req_done <= 1'b1;
end
end
end