/** * user-sample - CIC-IEC 2026 Stage 3 Evaluation Program * * (ULTIMATE PERFORMANCE DMA + PING-PONG BUFFER ARCHITECTURE) * * Utilizes true DMA transfers (Channel 0 for memory->IP, Channel 1 for IP->memory) * perfectly overlapped with Hardware IP computation to achieve Zero-Wait execution. */ #include #include #include #include #include #include /* ─── Configurable group count (default 10 for fast local testing) ─── */ #ifndef MATMUL_GROUP_NUM #define MATMUL_GROUP_NUM 5000 #endif /* ─── BSP globals ─────────────────────────────────────────────────── */ unsigned long UART_BASE = 0xbf000000; unsigned long CORE_CLOCKS_PER_SEC = 33000000L; /* ─── Memory layout ────────────────────────────────────────────────── */ #define EXTRAM_BASE_PHYS 0x1c400000 #define EXTRAM_BASE_UNCACHED (0xA0000000 | (EXTRAM_BASE_PHYS & 0x1FFFFFFF)) #define SRC_BASE_WORDS 0 #define DST_BASE_WORDS (SRC_BASE_WORDS + MATMUL_GROUP_NUM * 32) #define RESULT_WORDS (MATMUL_GROUP_NUM * 48) /* ExtRAM Physical Addresses for DMA */ #define EXTRAM_PHYS_AB(g) (EXTRAM_BASE_PHYS + (SRC_BASE_WORDS * 4) + (g) * 128) #define EXTRAM_PHYS_C(g) (EXTRAM_BASE_PHYS + (DST_BASE_WORDS * 4) + (g) * 192) /* ─── MATMUL IP registers (Ping-Pong Memory Map) ──────────────────── */ #define MATMUL_BASE_PHYS 0x1f500000 #define MATMUL_BASE_UNCACHED 0xbf500000 // CPU Control & Status Registers #define MATMUL_CTRL (MATMUL_BASE_UNCACHED + 0x000) #define MATMUL_STATUS (MATMUL_BASE_UNCACHED + 0x004) // DMA Physical Addresses for IP Space // (A and B are contiguous: A is 0x100~0x13F, B is 0x140~0x17F. Total 128 bytes) #define MATMUL_PHYS_B0_AB (MATMUL_BASE_PHYS + 0x100) #define MATMUL_PHYS_B0_C (MATMUL_BASE_PHYS + 0x180) // 192 bytes #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 #define STATUS_DONE 0x2 #define STATUS_ERROR 0x4 // Hardware CRC register (offset 0x010 in matmul IP) #define MATMUL_CRC (MATMUL_BASE_UNCACHED + 0x010) /* ─── Convenience macros ──────────────────────────────────────────── */ #define REG_WR(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val)) #define REG_RD(addr) (*(volatile uint32_t *)(addr)) static volatile int matmul_done_flag = 0; static volatile int dma0_done_flag = 0; static volatile int dma1_done_flag = 0; void MATMUL_IntrHandler(void) { matmul_done_flag = 1; REG_WR(MATMUL_STATUS, STATUS_DONE); // W1C: deassert intr } void DMA_IntrHandler(void) { if (DMA_CH(0)->STATUS & STATUS_DONE_BIT) { dma0_done_flag = 1; DMA_CH(0)->STATUS = STATUS_DONE_BIT; } if (DMA_CH(1)->STATUS & STATUS_DONE_BIT) { dma1_done_flag = 1; DMA_CH(1)->STATUS = STATUS_DONE_BIT; } } static void wait_matmul_done_intr(void) { while (!matmul_done_flag) { } matmul_done_flag = 0; } static void wait_dma_done_intr(int ch) { if (ch == 0) { while (!dma0_done_flag) { } dma0_done_flag = 0; } else { while (!dma1_done_flag) { } dma1_done_flag = 0; } } /* ═══════════════════════════════════════════════════════════════════ */ int main(void) { if (MATMUL_GROUP_NUM <= 0) return 0; volatile uint32_t *extram = (volatile uint32_t *)EXTRAM_BASE_UNCACHED; uint32_t crc; int g; // Ping-Pong Register Address Arrays (Physical for DMA) uint32_t phys_bank_AB[2] = {MATMUL_PHYS_B0_AB, MATMUL_PHYS_B1_AB}; uint32_t phys_bank_C[2] = {MATMUL_PHYS_B0_C, MATMUL_PHYS_B1_C}; // IP Control Command Arrays uint32_t ctrl_start[2] = {CTRL_START_B0, CTRL_START_B1}; /* ── Start marker (must be first output) ──────────────────── */ printf("MATMUL_START\n"); // 清理寄存器状态 REG_WR(MATMUL_STATUS, STATUS_DONE | STATUS_ERROR); REG_WR(MATMUL_CRC, 0); // 复位硬件 CRC32 为 0xFFFFFFFF /* ── Prologue: 第0组数据初始化 ────────────────────────── */ // DMA Ch0: 从 ExtRAM 将 Group 0 的 A、B (128 bytes) 搬入 IP 的 Bank 0 dma_start_transfer(0, EXTRAM_PHYS_AB(0), phys_bank_AB[0], 128, 10); wait_dma_done_intr(0); // 启动 IP Bank 0 计算 REG_WR(MATMUL_CTRL, ctrl_start[0]); /* ── Main Loop: 硬件完全流水线 (Overlapped Execution) ──── */ // 在 g 循环中: // IP 正在计算 prev_bank (g-1) // DMA_CH0 正在加载 cur_bank (g) // DMA_CH1 正在写回 prev_prev_bank (g-2) for (g = 1; g < MATMUL_GROUP_NUM; g++) { int cur_bank = g % 2; int prev_bank = (g - 1) % 2; // 1. 发起加载下一组数据的 DMA 传输 (Channel 0: Memory -> IP) dma_start_transfer(0, EXTRAM_PHYS_AB(g), phys_bank_AB[cur_bank], 128, 10); // 2. 等待上一组在 IP 中的计算完成 wait_matmul_done_intr(); // 3. 确保上一次的结果写回 (Channel 1) 已经空闲 if (g > 1) { wait_dma_done_intr(1); } // 4. 发起写回刚才计算完成的结果 (Channel 1: IP -> Memory) dma_start_transfer(1, phys_bank_C[prev_bank], EXTRAM_PHYS_C(g - 1), 192, 20); // 5. 确保当前要计算的输入数据 (Channel 0) 已经加载完毕 wait_dma_done_intr(0); // 6. 立即启动当前组在 IP 中的计算 REG_WR(MATMUL_CTRL, ctrl_start[cur_bank]); } /* ── Epilogue: 收尾最后一组 ───────────────────────────── */ wait_matmul_done_intr(); // 等待最后一次计算完成 wait_dma_done_intr(1); // 确保之前的 DMA CH1 空闲 // DMA CH1 将最后一组结果写回 dma_start_transfer(1, phys_bank_C[(MATMUL_GROUP_NUM - 1) % 2], EXTRAM_PHYS_C(MATMUL_GROUP_NUM - 1), 192, 20); wait_dma_done_intr(1); /* ── Read hardware CRC32 result ──────────────────────────── */ crc = REG_RD(MATMUL_CRC); /* ── Final markers ────────────────────────────────────────── */ printf("MATMUL_CRC32=%08lx\n", (unsigned long)crc); printf("MATMUL_DONE\n"); return 0; }