Add CDMA matmul sequencer
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user