From 09fc1aeb44c77a59eba5a919b7e189ca98ea2cde Mon Sep 17 00:00:00 2001 From: FallenSigh Date: Wed, 1 Jul 2026 20:15:55 +0800 Subject: [PATCH] Add CDMA endpoint path for matmul transfers --- rtl/ip/cdma/snix_axil_cdma_mux.sv | 309 ++++++++++++++++++++++-- rtl/ip/matmul/matmul_axi_slave.v | 72 +++++- rtl/soc_top.v | 74 ++++-- sdk/software/examples/asm/dma.h | 12 +- sdk/software/examples/asm/user-sample.c | 28 ++- 5 files changed, 439 insertions(+), 56 deletions(-) diff --git a/rtl/ip/cdma/snix_axil_cdma_mux.sv b/rtl/ip/cdma/snix_axil_cdma_mux.sv index ba82421..12255f3 100644 --- a/rtl/ip/cdma/snix_axil_cdma_mux.sv +++ b/rtl/ip/cdma/snix_axil_cdma_mux.sv @@ -93,6 +93,23 @@ module snix_axil_cdma_mux #( input logic [USER_WIDTH-1:0] mm2mm_ruser, input logic mm2mm_rvalid, output logic mm2mm_rready, + + // ========================================== + // Local endpoint interface + // ========================================== + output logic ep_wr_valid, + output logic [3:0] ep_wr_id, + output logic [3:0] ep_wr_bank, + output logic [7:0] ep_wr_word_addr, + output logic [31:0] ep_wr_data, + input logic ep_wr_ready, + + output logic ep_rd_valid, + output logic [3:0] ep_rd_id, + output logic [3:0] ep_rd_bank, + output logic [7:0] ep_rd_word_addr, + input logic [31:0] ep_rd_data, + input logic ep_rd_ready, // Global Interrupt (OR'd from all channels) output logic dma_finish @@ -102,6 +119,9 @@ module snix_axil_cdma_mux #( // Local Parameters & Utilities // ========================================== localparam int CH_BITS = $clog2(PORTS); + localparam logic [1:0] MODE_MEM2MEM = 2'd0; + localparam logic [1:0] MODE_MEM2EP = 2'd1; + localparam logic [1:0] MODE_EP2MEM = 2'd2; // Function to safely apply WSTRB to 32-bit registers function automatic logic [31:0] apply_wstrb( @@ -125,6 +145,8 @@ module snix_axil_cdma_mux #( logic [31:0] ch_len [PORTS]; logic [31:0] ch_tag [PORTS]; logic [31:0] ch_ctrl [PORTS]; + logic [31:0] ch_mode [PORTS]; + logic [31:0] ch_ep_cfg [PORTS]; logic [PORTS-1:0] ch_req; // Pending requests (Busy) logic [PORTS-1:0] ch_done; // Completion flags @@ -205,6 +227,8 @@ module snix_axil_cdma_mux #( 6'h0C: s_axil_rdata <= ch_tag[rd_ch]; 6'h10: s_axil_rdata <= ch_ctrl[rd_ch]; 6'h14: s_axil_rdata <= {30'd0, ch_done[rd_ch], ch_req[rd_ch]}; + 6'h18: s_axil_rdata <= ch_mode[rd_ch]; + 6'h1C: s_axil_rdata <= ch_ep_cfg[rd_ch]; default: s_axil_rdata <= 32'd0; endcase end else begin @@ -228,6 +252,7 @@ module snix_axil_cdma_mux #( for (int i=0; i 32'd4) ? (ep_bytes_left - 32'd4) : 32'd0; + if (mm2mm_rlast) + ep_state <= EP_DONE; + end + end + + EP_AW: begin + if (ep_awvalid && ep_awready) + ep_state <= EP_WRITE; + end + + EP_WRITE: begin + if (ep_wvalid && ep_wready) begin + ep_word_addr_r <= ep_word_addr_r + 8'd1; + ep_bytes_left <= (ep_bytes_left > 32'd4) ? (ep_bytes_left - 32'd4) : 32'd0; + if (ep_wlast) + ep_state <= EP_BRESP; + end + end + + EP_BRESP: begin + if (mm2mm_bvalid && ep_bready) + ep_state <= EP_DONE; + end + + EP_DONE: begin + ep_done <= 1'b1; + ep_state <= EP_IDLE; + end + + default: ep_state <= EP_IDLE; + endcase + end + end + + assign ep_arid = '0; + assign ep_araddr = ep_axi_addr; + assign ep_arlen = ep_axi_len; + assign ep_arsize = 3'd2; + assign ep_arburst = 2'b01; + assign ep_arlock = 1'b0; + assign ep_arcache = 4'b0; + assign ep_arprot = 3'b0; + assign ep_arqos = 4'b0; + assign ep_aruser = '0; + assign ep_arvalid = (ep_state == EP_AR); + assign ep_rready = (ep_state == EP_READ) && ep_wr_ready; + + assign ep_wr_valid = (ep_state == EP_READ) && mm2mm_rvalid && ep_mode_mem2ep; + assign ep_wr_id = engine_ep_id; + assign ep_wr_bank = engine_ep_bank; + assign ep_wr_word_addr = ep_word_addr_r; + assign ep_wr_data = mm2mm_rdata[31:0]; + + assign ep_awid = '0; + assign ep_awaddr = ep_axi_addr; + assign ep_awlen = ep_axi_len; + assign ep_awsize = 3'd2; + assign ep_awburst = 2'b01; + assign ep_awlock = 1'b0; + assign ep_awcache = 4'b0; + assign ep_awprot = 3'b0; + assign ep_awqos = 4'b0; + assign ep_awuser = '0; + assign ep_awvalid = (ep_state == EP_AW); + assign ep_wdata = ep_rd_data; + assign ep_wstrb = {{(DATA_WIDTH/8){1'b1}}}; + assign ep_wlast = (ep_bytes_left <= 32'd4) && ep_wvalid; + assign ep_wuser = '0; + assign ep_wvalid = (ep_state == EP_WRITE) && ep_mode_ep2mem && ep_rd_ready; + assign ep_bready = (ep_state == EP_BRESP); + + assign ep_rd_valid = (ep_state == EP_WRITE) && ep_mode_ep2mem && ep_wready; + assign ep_rd_id = engine_ep_id; + assign ep_rd_bank = engine_ep_bank; + assign ep_rd_word_addr = ep_word_addr_r; + +endmodule diff --git a/rtl/ip/matmul/matmul_axi_slave.v b/rtl/ip/matmul/matmul_axi_slave.v index 7f05a7c..557c7f5 100644 --- a/rtl/ip/matmul/matmul_axi_slave.v +++ b/rtl/ip/matmul/matmul_axi_slave.v @@ -80,6 +80,21 @@ module matmul_axi_slave ( output reg s_axi_rvalid, input s_axi_rready, + // CDMA local endpoint port + input ep_wr_valid, + input [3:0] ep_wr_id, + input [3:0] ep_wr_bank, + input [7:0] ep_wr_word_addr, + input [31:0] ep_wr_data, + output ep_wr_ready, + + input ep_rd_valid, + input [3:0] ep_rd_id, + input [3:0] ep_rd_bank, + input [7:0] ep_rd_word_addr, + output reg [31:0] ep_rd_data, + output ep_rd_ready, + // Interrupt output (active high level, pulsed by calc_done) output intr ); @@ -115,6 +130,33 @@ module matmul_axi_slave ( reg [31:0] b1_b [0:15]; reg [65:0] b1_c [0:15]; + assign ep_wr_ready = 1'b1; + assign ep_rd_ready = 1'b1; + + wire [3:0] ep_wr_lo_idx = ep_wr_word_addr[3:0]; + wire [3:0] ep_wr_hi_idx = ep_wr_word_addr[3:0]; + wire [7:0] ep_rd_elem_raw = ep_rd_word_addr / 8'd3; + wire [7:0] ep_rd_part_raw = ep_rd_word_addr % 8'd3; + wire [3:0] ep_rd_elem = ep_rd_elem_raw[3:0]; + wire [1:0] ep_rd_part = ep_rd_part_raw[1:0]; + wire [65:0] ep_rd_c0 = b0_c[ep_rd_elem]; + wire [65:0] ep_rd_c1 = b1_c[ep_rd_elem]; + + always @(*) begin + ep_rd_data = 32'b0; + if (ep_rd_word_addr < 8'd48) begin + if (ep_rd_bank[0] == 1'b0) begin + if (ep_rd_part == 2'd0) ep_rd_data = ep_rd_c0[31:0]; + else if (ep_rd_part == 2'd1) ep_rd_data = ep_rd_c0[63:32]; + else ep_rd_data = {30'b0, ep_rd_c0[65:64]}; + end else begin + if (ep_rd_part == 2'd0) ep_rd_data = ep_rd_c1[31:0]; + else if (ep_rd_part == 2'd1) ep_rd_data = ep_rd_c1[63:32]; + else ep_rd_data = {30'b0, ep_rd_c1[65:64]}; + end + end + end + function [31:0] apply_wstrb; input [31:0] old_value; input [31:0] new_value; @@ -134,10 +176,12 @@ module matmul_axi_slave ( reg [31:0] crc32_table [0:255]; reg [31:0] crc_reg; - wire [31:0] crc_stream_data = s_axi_rdata; - wire crc_stream_valid = (r_state == R_DATA) && s_axi_rvalid && s_axi_rready && - ((r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) || - (r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0))); + wire [31:0] crc_stream_data = ep_rd_valid ? ep_rd_data : s_axi_rdata; + wire crc_axi_valid = (r_state == R_DATA) && s_axi_rvalid && s_axi_rready && + ((r_offset >= ADDR_B0_C && r_offset < (ADDR_B0_C + 12'h0C0)) || + (r_offset >= ADDR_B1_C && r_offset < (ADDR_B1_C + 12'h0C0))); + wire crc_ep_valid = ep_rd_valid && ep_rd_ready && (ep_rd_word_addr < 8'd48); + wire crc_stream_valid = crc_axi_valid || crc_ep_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])]; @@ -318,6 +362,24 @@ module matmul_axi_slave ( done <= 1'b0; error <= 1'b0; end else begin + if (ep_wr_valid && ep_wr_ready) begin + if (ep_wr_bank[0] == 1'b0) begin + if (ep_wr_word_addr < 8'd16) + b0_a[ep_wr_lo_idx] <= ep_wr_data; + else if (ep_wr_word_addr < 8'd32) + b0_b[ep_wr_hi_idx] <= ep_wr_data; + else + error <= 1'b1; + end else begin + if (ep_wr_word_addr < 8'd16) + b1_a[ep_wr_lo_idx] <= ep_wr_data; + else if (ep_wr_word_addr < 8'd32) + b1_b[ep_wr_hi_idx] <= ep_wr_data; + else + error <= 1'b1; + end + end + if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0; if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0; @@ -604,4 +666,4 @@ module matmul_axi_slave ( assign intr = done; -endmodule \ No newline at end of file +endmodule diff --git a/rtl/soc_top.v b/rtl/soc_top.v index 8ca2c1a..4bbf491 100644 --- a/rtl/soc_top.v +++ b/rtl/soc_top.v @@ -1474,10 +1474,23 @@ mlkem_axi_slave u_mlkem_axi_slave ( .intr (mlkem_intr) ); -//slave 7 - matmul accelerator -matmul_axi_slave u_matmul_axi_slave ( - .clk (sys_clk), - .resetn (sys_resetn), +//slave 7 - matmul accelerator +wire dma_ep_wr_valid; +wire [3:0] dma_ep_wr_id; +wire [3:0] dma_ep_wr_bank; +wire [7:0] dma_ep_wr_word_addr; +wire [31:0] dma_ep_wr_data; +wire dma_ep_wr_ready; +wire dma_ep_rd_valid; +wire [3:0] dma_ep_rd_id; +wire [3:0] dma_ep_rd_bank; +wire [7:0] dma_ep_rd_word_addr; +wire [31:0] dma_ep_rd_data; +wire dma_ep_rd_ready; + +matmul_axi_slave u_matmul_axi_slave ( + .clk (sys_clk), + .resetn (sys_resetn), .s_axi_awid (axiOut_7_awid ), .s_axi_awaddr (axiOut_7_awaddr ), @@ -1516,11 +1529,25 @@ matmul_axi_slave u_matmul_axi_slave ( .s_axi_rid (axiOut_7_rid ), .s_axi_rdata (axiOut_7_rdata ), .s_axi_rresp (axiOut_7_rresp ), - .s_axi_rlast (axiOut_7_rlast ), - .s_axi_rvalid (axiOut_7_rvalid), - .s_axi_rready (axiOut_7_rready), - .intr (matmul_intr) -); + .s_axi_rlast (axiOut_7_rlast ), + .s_axi_rvalid (axiOut_7_rvalid), + .s_axi_rready (axiOut_7_rready), + + .ep_wr_valid (dma_ep_wr_valid), + .ep_wr_id (dma_ep_wr_id), + .ep_wr_bank (dma_ep_wr_bank), + .ep_wr_word_addr(dma_ep_wr_word_addr), + .ep_wr_data (dma_ep_wr_data), + .ep_wr_ready (dma_ep_wr_ready), + .ep_rd_valid (dma_ep_rd_valid), + .ep_rd_id (dma_ep_rd_id), + .ep_rd_bank (dma_ep_rd_bank), + .ep_rd_word_addr(dma_ep_rd_word_addr), + .ep_rd_data (dma_ep_rd_data), + .ep_rd_ready (dma_ep_rd_ready), + + .intr (matmul_intr) +); wire [31:0] cdma_s_awaddr; wire [2:0] cdma_s_awprot; @@ -1683,12 +1710,25 @@ snix_axil_cdma_mux #( .mm2mm_rdata (dma_m_rdata), .mm2mm_rresp (dma_m_rresp), .mm2mm_rlast (dma_m_rlast), - .mm2mm_ruser (1'b0), - .mm2mm_rvalid (dma_m_rvalid), - .mm2mm_rready (dma_m_rready), + .mm2mm_ruser (1'b0), + .mm2mm_rvalid (dma_m_rvalid), + .mm2mm_rready (dma_m_rready), + + .ep_wr_valid (dma_ep_wr_valid), + .ep_wr_id (dma_ep_wr_id), + .ep_wr_bank (dma_ep_wr_bank), + .ep_wr_word_addr (dma_ep_wr_word_addr), + .ep_wr_data (dma_ep_wr_data), + .ep_wr_ready (dma_ep_wr_ready), + .ep_rd_valid (dma_ep_rd_valid), + .ep_rd_id (dma_ep_rd_id), + .ep_rd_bank (dma_ep_rd_bank), + .ep_rd_word_addr (dma_ep_rd_word_addr), + .ep_rd_data (dma_ep_rd_data), + .ep_rd_ready (dma_ep_rd_ready), + + // 全局中断输出 + .dma_finish (dma_finish) +); - // 全局中断输出 - .dma_finish (dma_finish) -); - -endmodule \ No newline at end of file +endmodule diff --git a/sdk/software/examples/asm/dma.h b/sdk/software/examples/asm/dma.h index 5c60bcd..86dfc34 100644 --- a/sdk/software/examples/asm/dma.h +++ b/sdk/software/examples/asm/dma.h @@ -9,7 +9,9 @@ typedef struct { volatile u32 TAG; // 0x0C: software tag (ignored by HW) volatile u32 CTRL; // 0x10: control (burst config + start) volatile u32 STATUS; // 0x14: status (busy, done) - volatile u32 RESV[10]; // 0x18 ~ 0x3C: padding to 0x40 bytes + volatile u32 MODE; // 0x18: 0=mem2mem, 1=mem2ep, 2=ep2mem + volatile u32 EP_CFG; // 0x1C: [3:0]=bank, [15:8]=word offset, [19:16]=endpoint id + volatile u32 RESV[8]; // 0x20 ~ 0x3C: padding to 0x40 bytes } dma_ch_regs_t; // DMA 控制器基地址 @@ -21,9 +23,15 @@ typedef struct { #define CTRL_BURST_SIZE(x) (((x) & 0x7) << 3) // Bits [5:3]: AXI AxSIZE (0=1B, 1=2B, 2=4B, 3=8B) #define CTRL_BURST_LEN(x) (((x) & 0xFF) << 6) // Bits [13:6]: AXI AxLEN (0=1 beat, 15=16 beats) +#define DMA_MODE_MEM2MEM 0 +#define DMA_MODE_MEM2EP 1 +#define DMA_MODE_EP2MEM 2 +#define DMA_EP_CFG(id, bank, word_off) \ + ((((id) & 0xF) << 16) | (((word_off) & 0xFF) << 8) | ((bank) & 0xF)) + // STATUS 寄存器位定义 #define STATUS_BUSY_BIT (1 << 0) #define STATUS_DONE_BIT (1 << 1) void dma_start_transfer(int ch_id, u32 src, u32 dst, u32 bytes, u32 tag); -void dma_wait_polling(int ch_id); \ No newline at end of file +void dma_wait_polling(int ch_id); diff --git a/sdk/software/examples/asm/user-sample.c b/sdk/software/examples/asm/user-sample.c index 3653892..76a5ce8 100644 --- a/sdk/software/examples/asm/user-sample.c +++ b/sdk/software/examples/asm/user-sample.c @@ -63,10 +63,6 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L; #define MATMUL_CTRL (MATMUL_BASE_UNCACHED + 0x000) #define MATMUL_STATUS (MATMUL_BASE_UNCACHED + 0x004) -#define MATMUL_PHYS_B0_AB (MATMUL_BASE_PHYS + 0x100) -#define MATMUL_PHYS_B0_C (MATMUL_BASE_PHYS + 0x180) -#define MATMUL_PHYS_B1_AB (MATMUL_BASE_PHYS + 0x300) -#define MATMUL_PHYS_B1_C (MATMUL_BASE_PHYS + 0x380) #define CTRL_START_B0 0x1 #define CTRL_START_B1 0x2 @@ -77,6 +73,7 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L; /* ─── Pre-computed DMA burst control word ──────────────────────────── */ #define DMA_CTRL_VAL (CTRL_BURST_SIZE(2) | CTRL_BURST_LEN(63) | CTRL_START_BIT) +#define MATMUL_EP_ID 0 /* ═══════════════════════════════════════════════════════════════════ */ int main(void) @@ -93,9 +90,6 @@ int main(void) unsigned int crc; int g, bank; - // Ping-Pong Register Address Arrays (Physical for DMA) - unsigned int phys_bank_AB[2] = {MATMUL_PHYS_B0_AB, MATMUL_PHYS_B1_AB}; - unsigned int phys_bank_C[2] = {MATMUL_PHYS_B0_C, MATMUL_PHYS_B1_C}; unsigned int ctrl_start[2] = {CTRL_START_B0, CTRL_START_B1}; /* ── Start marker (must be first output) ──────────────────── */ @@ -111,8 +105,10 @@ int main(void) // DMA Ch0: Load group 0 A+B (128 bytes) → IP Bank 0 ch0->SRC_ADDR = EXTRAM_PHYS_AB(0); - ch0->DST_ADDR = phys_bank_AB[0]; + ch0->DST_ADDR = 0; ch0->LENGTH = 128; + ch0->MODE = DMA_MODE_MEM2EP; + ch0->EP_CFG = DMA_EP_CFG(MATMUL_EP_ID, 0, 0); ch0->CTRL = DMA_CTRL_VAL; while (!(ch0->STATUS & STATUS_DONE_BIT)) {} ch0->STATUS = STATUS_DONE_BIT; @@ -123,8 +119,10 @@ int main(void) // Pre-fire: DMA Ch0 load group 1 → Bank 1 (overlaps with IP compute) if (MATMUL_GROUP_NUM > 1) { ch0->SRC_ADDR = EXTRAM_PHYS_AB(1); - ch0->DST_ADDR = phys_bank_AB[1]; + ch0->DST_ADDR = 0; ch0->LENGTH = 128; + ch0->MODE = DMA_MODE_MEM2EP; + ch0->EP_CFG = DMA_EP_CFG(MATMUL_EP_ID, 1, 0); ch0->CTRL = DMA_CTRL_VAL; } @@ -157,9 +155,11 @@ int main(void) } // 3. Start DMA Ch1 store: group (g-1) result → ExtRAM - ch1->SRC_ADDR = phys_bank_C[prev_bank]; + ch1->SRC_ADDR = 0; ch1->DST_ADDR = EXTRAM_PHYS_C(g - 1); ch1->LENGTH = 192; + ch1->MODE = DMA_MODE_EP2MEM; + ch1->EP_CFG = DMA_EP_CFG(MATMUL_EP_ID, prev_bank, 0); ch1->CTRL = DMA_CTRL_VAL; // 4. Wait for current DMA Ch0 load (group g → cur_bank, pre-fired in iteration g-1) @@ -174,8 +174,10 @@ int main(void) if (g < MATMUL_GROUP_NUM - 1) { int next_bank = bank ^ 1; ch0->SRC_ADDR = EXTRAM_PHYS_AB(g + 1); - ch0->DST_ADDR = phys_bank_AB[next_bank]; + ch0->DST_ADDR = 0; ch0->LENGTH = 128; + ch0->MODE = DMA_MODE_MEM2EP; + ch0->EP_CFG = DMA_EP_CFG(MATMUL_EP_ID, next_bank, 0); ch0->CTRL = DMA_CTRL_VAL; } @@ -195,9 +197,11 @@ int main(void) while (!(ch1->STATUS & STATUS_DONE_BIT)) {} ch1->STATUS = STATUS_DONE_BIT; - ch1->SRC_ADDR = phys_bank_C[(MATMUL_GROUP_NUM - 1) % 2]; + ch1->SRC_ADDR = 0; ch1->DST_ADDR = EXTRAM_PHYS_C(MATMUL_GROUP_NUM - 1); ch1->LENGTH = 192; + ch1->MODE = DMA_MODE_EP2MEM; + ch1->EP_CFG = DMA_EP_CFG(MATMUL_EP_ID, (MATMUL_GROUP_NUM - 1) % 2, 0); ch1->CTRL = DMA_CTRL_VAL; while (!(ch1->STATUS & STATUS_DONE_BIT)) {} ch1->STATUS = STATUS_DONE_BIT;