This repository has been archived on 2026-08-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
ciciec2026/sdk/software/examples/matmul_test/main.c
FallenSigh e35fa5884d Use uncached ExtRAM access (0xBC400000) to bypass CPU data cache
The open-la500 core has USE_CACHE enabled. Writes to 0x1c400000
go to the write-back data cache and never reach the SRAM model
before the testbench checks ExtRAM. Use the 0xA0000000 uncached
segment (same pattern as fft_dma/main.c).
2026-06-24 02:04:40 +08:00

162 lines
6.4 KiB
C

/**
* 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 <stdio.h>
#include <stdint.h>
/* ─── 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 ──────────────────────────────────────────────── */
/* ExtRAM physical: 0x1c400000 (bit22=1 in RAM controller).
* Use uncached segment (0xA0000000) to bypass CPU data cache —
* otherwise writes never reach the SRAM model before testbench checks. */
#define EXTRAM_BASE_PHYS 0x1c400000
#define EXTRAM_BASE (0xA0000000 | (EXTRAM_BASE_PHYS & 0x1FFFFFFF))
#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 0xbf500000
#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;
}