Add CDMA matmul sequencer

This commit is contained in:
2026-07-01 21:59:57 +08:00
parent 2080a700e9
commit dd8d9c8f5f
4 changed files with 625 additions and 345 deletions

View File

@@ -18,6 +18,19 @@ typedef struct {
#define CDMA_MUX_BASE 0xbf300000
#define DMA_CH(i) ((volatile dma_ch_regs_t*)(CDMA_MUX_BASE + (i) * 0x40))
typedef struct {
volatile u32 CTRL; // 0x200: bit0 start
volatile u32 STATUS; // 0x204: bit0 busy, bit1 done (W1C)
volatile u32 SRC_BASE; // 0x208
volatile u32 DST_BASE; // 0x20C
volatile u32 GROUPS; // 0x210
volatile u32 MAT_BASE; // 0x214
volatile u32 SRC_STRIDE; // 0x218
volatile u32 DST_STRIDE; // 0x21C
} dma_seq_regs_t;
#define DMA_SEQ ((volatile dma_seq_regs_t*)(CDMA_MUX_BASE + 0x200))
// CTRL 寄存器位定义
#define CTRL_START_BIT (1 << 0)
#define CTRL_BURST_SIZE(x) (((x) & 0x7) << 3) // Bits [5:3]: AXI AxSIZE (0=1B, 1=2B, 2=4B, 3=8B)
@@ -33,5 +46,9 @@ typedef struct {
#define STATUS_BUSY_BIT (1 << 0)
#define STATUS_DONE_BIT (1 << 1)
#define SEQ_START_BIT (1 << 0)
#define SEQ_BUSY_BIT (1 << 0)
#define SEQ_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);

View File

@@ -82,6 +82,7 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L;
#define MATMUL_CTRL (MATMUL_BASE_UNCACHED + 0x000)
#define MATMUL_STATUS (MATMUL_BASE_UNCACHED + 0x004)
#define MATMUL_BASE_PHYS_FOR_DMA MATMUL_BASE_PHYS
#define CTRL_START_B0 0x1
#define CTRL_START_B1 0x2
@@ -100,132 +101,26 @@ int main(void)
if (MATMUL_GROUP_NUM <= 0) return 0;
/* ── Hot-path local volatile pointers (one-time addr calc) ──────── */
volatile unsigned int *mat_status = (volatile unsigned int *)MATMUL_STATUS;
volatile unsigned int *mat_ctrl = (volatile unsigned int *)MATMUL_CTRL;
volatile unsigned int *mat_crc = (volatile unsigned int *)MATMUL_CRC;
volatile dma_ch_regs_t *ch0 = DMA_CH(0);
volatile dma_ch_regs_t *ch1 = DMA_CH(1);
volatile dma_seq_regs_t *seq = DMA_SEQ;
unsigned int crc;
unsigned int cycle_start, cycle_end, cycles, time_us;
int g, bank;
unsigned int ctrl_start[2] = {CTRL_START_B0, CTRL_START_B1};
/* ── Start marker (must be first output) ──────────────────── */
uart_puts("MATMUL_START\r\n");
cycle_start = get_clock_count();
// Reset IP state
*mat_status = STATUS_DONE | STATUS_ERROR;
*mat_crc = 0;
/* ═══════════════════════════════════════════════════════════════
* PROLOGUE: Load group 0 → Bank 0, start IP, pre-fire group 1
* ═══════════════════════════════════════════════════════════════ */
// DMA Ch0: Load group 0 A+B (128 bytes) → IP Bank 0
ch0->SRC_ADDR = EXTRAM_PHYS_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;
// Start IP Bank 0 (group 0)
*mat_ctrl = ctrl_start[0];
// 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 = 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;
}
/* ═══════════════════════════════════════════════════════════════
* MAIN LOOP: Fully-pipelined — pre-fire DMA load at loop tail
*
* At iteration g:
* IP is computing group (g-1) on prev_bank
* Ch0 loaded group g to cur_bank (pre-fired in iteration g-1)
*
* Pipeline:
* Ch0: | load g+1 | | load g+2 |
* Ch1: | store g-1 | | store g |
* IP : | compute g | | compute g+1 |
* ═══════════════════════════════════════════════════════════════ */
bank = 1; // cur_bank for iteration g=1; prev_bank = bank ^ 1
for (g = 1; g < MATMUL_GROUP_NUM; g++) {
int cur_bank = bank;
int prev_bank = bank ^ 1;
// 1. Wait for previous IP computation (group g-1 on prev_bank)
while (!(*mat_status & STATUS_DONE)) {}
*mat_status = STATUS_DONE;
// 2. Ensure previous DMA Ch1 store is done (group g-2)
if (g > 1) {
while (!(ch1->STATUS & STATUS_DONE_BIT)) {}
ch1->STATUS = STATUS_DONE_BIT;
}
// 3. Start DMA Ch1 store: group (g-1) result → ExtRAM
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)
while (!(ch0->STATUS & STATUS_DONE_BIT)) {}
ch0->STATUS = STATUS_DONE_BIT;
// 5. Start IP computation for current group on cur_bank
*mat_ctrl = ctrl_start[cur_bank];
// ★ 6. PRE-FIRE: DMA Ch0 load next group (g+1) → next_bank
// This runs CONCURRENTLY with IP computation started in step 5!
if (g < MATMUL_GROUP_NUM - 1) {
int next_bank = bank ^ 1;
ch0->SRC_ADDR = EXTRAM_PHYS_AB(g + 1);
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;
}
// Toggle bank for next iteration
bank ^= 1;
}
/* ═══════════════════════════════════════════════════════════════
* EPILOGUE: Flush the final group
* ═══════════════════════════════════════════════════════════════ */
// Wait for last IP computation
while (!(*mat_status & STATUS_DONE)) {}
*mat_status = STATUS_DONE;
// Wait for previous DMA store and start/complete final store
while (!(ch1->STATUS & STATUS_DONE_BIT)) {}
ch1->STATUS = STATUS_DONE_BIT;
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;
seq->STATUS = SEQ_DONE_BIT;
seq->SRC_BASE = EXTRAM_PHYS_AB(0);
seq->DST_BASE = EXTRAM_PHYS_C(0);
seq->GROUPS = MATMUL_GROUP_NUM;
seq->MAT_BASE = MATMUL_BASE_PHYS_FOR_DMA;
seq->SRC_STRIDE = 128;
seq->DST_STRIDE = 192;
seq->CTRL = SEQ_START_BIT;
while (!(seq->STATUS & SEQ_DONE_BIT)) {}
seq->STATUS = SEQ_DONE_BIT;
cycle_end = get_clock_count();
cycles = cycle_end - cycle_start;
time_us = cycles / (CORE_CLOCKS_PER_SEC / 1000000UL);