/** * matmul_test - ExtRAM-based flow test for matmul_axi_slave IP * * Reads source matrices from ExtRAM, computes C = A x B via the IP, * writes results back to ExtRAM. Designed to work with matmul_flow_tb.v. * * Data layout in ExtRAM (matches testbench & generate_matmul_testdata.py): * SRC_BASE = 0 (word offset) * DST_BASE = SRC_BASE + N_GROUPS * 32 * Group i: A_i @ SRC_BASE + i*32 + 0 (16 words) * B_i @ SRC_BASE + i*32 + 16 (16 words) * C_i @ DST_BASE + i*48 (48 words, 3 per element) * * Register map (byte offsets from MATMUL_BASE = 0x1f500000): * 0x000 CTRL [W] bit0=1 starts computation * 0x004 STATUS [R] bit2=error, bit1=done, bit0=busy * 0x008 SRC_BASE [R/W] unused (IP has no DMA yet) * 0x00c DST_BASE [R/W] unused * 0x010 GROUP_NUM [R/W] unused * 0x020 A_BASE [R/W] 16 words of matrix A (row-major) * 0x060 B_BASE [R/W] 16 words of matrix B (row-major) * 0x0a0 C_BASE [R] 48 words of result C (3 words per element) */ #include #include /* ─── BSP globals (required by common.mk / picolibc) ─────────────── */ unsigned long UART_BASE = 0xbf000000; unsigned long CONFREG_TIMER_BASE = 0xbf20f100; unsigned long CONFREG_CLOCKS_PER_SEC = 50000000L; unsigned long CORE_CLOCKS_PER_SEC = 33000000L; /* ─── Memory layout ──────────────────────────────────────────────── */ #define EXTRAM_BASE 0x1c400000 /* ExtRAM: bit22=1 in RAM controller */ #define SRC_BASE 0 /* word offset — source A/B matrices */ #define N_GROUPS 10 /* must match testbench default */ #define DST_BASE (SRC_BASE + N_GROUPS * 32) /* result region start */ /* ─── MATMUL IP register map ─────────────────────────────────────── */ #define MATMUL_BASE 0x1f500000 #define MATMUL_CTRL (MATMUL_BASE + 0x000) #define MATMUL_STATUS (MATMUL_BASE + 0x004) #define MATMUL_A_BASE (MATMUL_BASE + 0x020) #define MATMUL_B_BASE (MATMUL_BASE + 0x060) #define MATMUL_C_BASE (MATMUL_BASE + 0x0a0) /* CTRL bits */ #define CTRL_START 0x1 /* STATUS bits */ #define STATUS_BUSY 0x1 #define STATUS_DONE 0x2 #define STATUS_ERROR 0x4 /* ─── Convenience macros ─────────────────────────────────────────── */ #define REG_WR(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val)) #define REG_RD(addr) (*(volatile uint32_t *)(addr)) /* ─── Read N words from IP register space ────────────────────────── */ static void read_ip(uint32_t base, volatile uint32_t *dst, int n) { int i; for (i = 0; i < n; i++) dst[i] = REG_RD(base + i * 4); } /* ─── Write N words to IP register space ─────────────────────────── */ static void write_ip(uint32_t base, const volatile uint32_t *src, int n) { int i; for (i = 0; i < n; i++) REG_WR(base + i * 4, src[i]); } /* ─── Wait until IP is done, return 0 on success, -1 on error ────── */ static int wait_done(void) { while (1) { uint32_t status = REG_RD(MATMUL_STATUS); if (status & STATUS_ERROR) { printf("[ERROR] matmul IP error (status=0x%08lx)\n", (unsigned long)status); return -1; } if (status & STATUS_DONE) return 0; } } /* ─── Main ────────────────────────────────────────────────────────── */ int main(void) { volatile uint32_t *extram = (volatile uint32_t *)EXTRAM_BASE; uint32_t a_buf[16], b_buf[16], c_buf[48]; int g, pass = 0, fail = 0; printf("\n===== MATMUL ExtRAM Flow Test =====\n"); printf("ExtRAM base: 0x%08lx\n", (unsigned long)EXTRAM_BASE); printf("Groups: %d SRC_BASE=%d DST_BASE=%d\n", N_GROUPS, SRC_BASE, DST_BASE); printf("====================================\n"); for (g = 0; g < N_GROUPS; g++) { int i; printf("\n--- Group %d ---\n", g); /* 1. Read A[16] and B[16] from ExtRAM source region */ printf(" Reading A/B from ExtRAM...\n"); for (i = 0; i < 16; i++) { a_buf[i] = extram[SRC_BASE + g * 32 + i]; b_buf[i] = extram[SRC_BASE + g * 32 + 16 + i]; } /* 2. Write A and B to IP registers */ printf(" Loading A/B into IP...\n"); write_ip(MATMUL_A_BASE, a_buf, 16); write_ip(MATMUL_B_BASE, b_buf, 16); /* 3. Clear stale done / error flags */ REG_WR(MATMUL_STATUS, STATUS_DONE | STATUS_ERROR); /* 4. Start computation */ printf(" Starting computation...\n"); REG_WR(MATMUL_CTRL, CTRL_START); /* 5. Wait for done (poll STATUS) */ if (wait_done() != 0) { printf(" Group %d: FAIL (IP error)\n", g); fail++; /* zero-fill result area so testbench clearly sees failure */ for (i = 0; i < 48; i++) c_buf[i] = 0; } else { /* 6. Read result C[48] from IP */ printf(" Reading C from IP...\n"); read_ip(MATMUL_C_BASE, c_buf, 48); printf(" Group %d: OK\n", g); pass++; } /* 7. Write result C to ExtRAM result region */ for (i = 0; i < 48; i++) extram[DST_BASE + g * 48 + i] = c_buf[i]; } /* ── Final report ─────────────────────────────────────────── */ printf("\n============================\n"); printf("RESULTS: %d passed, %d failed\n", pass, fail); printf("============================\n"); /* Signal completion to testbench via UART */ printf("MATMUL_DONE\n"); return 0; }