matmul_test: rewrite for ExtRAM flow, add IP error debug
- Rewrite main.c to read from ExtRAM (0x1c400000), compute via matmul IP, write results back. Matches testbench expectation of 10 groups. - Add in matmul_axi_slave to trace error writes
This commit is contained in:
@@ -251,6 +251,7 @@ always @(posedge clk) begin
|
|||||||
if (wdata_hold[1]) done <= 1'b0;
|
if (wdata_hold[1]) done <= 1'b0;
|
||||||
if (wdata_hold[2]) error <= 1'b0;
|
if (wdata_hold[2]) error <= 1'b0;
|
||||||
end else if ((write_offset != ADDR_CTRL) && (write_offset < ADDR_C_BASE)) begin
|
end else if ((write_offset != ADDR_CTRL) && (write_offset < ADDR_C_BASE)) begin
|
||||||
|
$display("[MATMUL_SLAVE] ERROR: write to unmapped offset=%03x wdata=%08x", write_offset, wdata_hold);
|
||||||
error <= 1'b1;
|
error <= 1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
/**
|
/**
|
||||||
* matmul_test - Standalone test example for matmul_axi_slave IP
|
* matmul_test - ExtRAM-based flow test for matmul_axi_slave IP
|
||||||
*
|
*
|
||||||
* Tests the 4x4 matrix multiplier IP at 0x1f500000 (axiOut_7).
|
* Reads source matrices from ExtRAM, computes C = A x B via the IP,
|
||||||
* Computes C = A x B using register-level access, then verifies
|
* writes results back to ExtRAM. Designed to work with matmul_flow_tb.v.
|
||||||
* against a software reference matmul.
|
|
||||||
*
|
*
|
||||||
* Register map (byte offsets from MATMUL_BASE):
|
* 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
|
* 0x000 CTRL [W] bit0=1 starts computation
|
||||||
* 0x004 STATUS [R] bit2=error, bit1=done, bit0=busy
|
* 0x004 STATUS [R] bit2=error, bit1=done, bit0=busy
|
||||||
* 0x008 SRC_BASE [R/W] source data base address
|
* 0x008 SRC_BASE [R/W] unused (IP has no DMA yet)
|
||||||
* 0x00c DST_BASE [R/W] result data base address
|
* 0x00c DST_BASE [R/W] unused
|
||||||
* 0x010 GROUP_NUM [R/W] number of matrix groups
|
* 0x010 GROUP_NUM [R/W] unused
|
||||||
* 0x020 A_BASE [R/W] 16 words of matrix A (row-major)
|
* 0x020 A_BASE [R/W] 16 words of matrix A (row-major)
|
||||||
* 0x060 B_BASE [R/W] 16 words of matrix B (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)
|
* 0x0a0 C_BASE [R] 48 words of result C (3 words per element)
|
||||||
@@ -25,14 +31,18 @@ unsigned long CONFREG_TIMER_BASE = 0xbf20f100;
|
|||||||
unsigned long CONFREG_CLOCKS_PER_SEC = 50000000L;
|
unsigned long CONFREG_CLOCKS_PER_SEC = 50000000L;
|
||||||
unsigned long CORE_CLOCKS_PER_SEC = 33000000L;
|
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 ─────────────────────────────────────── */
|
/* ─── MATMUL IP register map ─────────────────────────────────────── */
|
||||||
#define MATMUL_BASE 0x1f500000
|
#define MATMUL_BASE 0x1f500000
|
||||||
|
|
||||||
#define MATMUL_CTRL (MATMUL_BASE + 0x000)
|
#define MATMUL_CTRL (MATMUL_BASE + 0x000)
|
||||||
#define MATMUL_STATUS (MATMUL_BASE + 0x004)
|
#define MATMUL_STATUS (MATMUL_BASE + 0x004)
|
||||||
#define MATMUL_SRC_BASE (MATMUL_BASE + 0x008)
|
|
||||||
#define MATMUL_DST_BASE (MATMUL_BASE + 0x00c)
|
|
||||||
#define MATMUL_GROUP_NUM (MATMUL_BASE + 0x010)
|
|
||||||
#define MATMUL_A_BASE (MATMUL_BASE + 0x020)
|
#define MATMUL_A_BASE (MATMUL_BASE + 0x020)
|
||||||
#define MATMUL_B_BASE (MATMUL_BASE + 0x060)
|
#define MATMUL_B_BASE (MATMUL_BASE + 0x060)
|
||||||
#define MATMUL_C_BASE (MATMUL_BASE + 0x0a0)
|
#define MATMUL_C_BASE (MATMUL_BASE + 0x0a0)
|
||||||
@@ -49,91 +59,20 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L;
|
|||||||
#define REG_WR(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
|
#define REG_WR(addr, val) (*(volatile uint32_t *)(addr) = (uint32_t)(val))
|
||||||
#define REG_RD(addr) (*(volatile uint32_t *)(addr))
|
#define REG_RD(addr) (*(volatile uint32_t *)(addr))
|
||||||
|
|
||||||
/* ─── Test data ─────────────────────────────────────────────────────
|
/* ─── Read N words from IP register space ────────────────────────── */
|
||||||
* Test group 0:
|
static void read_ip(uint32_t base, volatile uint32_t *dst, int n)
|
||||||
* A = identity (4x4)
|
|
||||||
* B = diagonal {2, 3, 4, 5}
|
|
||||||
* Expected C = B (since identity * X = X)
|
|
||||||
*
|
|
||||||
* Test group 1:
|
|
||||||
* A = [[1,2,0,0], [0,0,3,0], [0,0,0,4], [0,0,0,0]]
|
|
||||||
* B = [[5,0,0,0], [6,0,0,0], [0,7,0,0], [0,0,8,0]]
|
|
||||||
* Expected C computed by software reference below
|
|
||||||
*
|
|
||||||
* Each A/B is 16 uint32_t, row-major. Unused slots in sub-4x4 matrices
|
|
||||||
* are 0 as specified.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define N_GROUPS 2
|
|
||||||
|
|
||||||
static const uint32_t test_a[N_GROUPS][16] = {
|
|
||||||
/* group 0: identity */
|
|
||||||
{ 1, 0, 0, 0,
|
|
||||||
0, 1, 0, 0,
|
|
||||||
0, 0, 1, 0,
|
|
||||||
0, 0, 0, 1 },
|
|
||||||
/* group 1 */
|
|
||||||
{ 1, 2, 0, 0,
|
|
||||||
0, 0, 3, 0,
|
|
||||||
0, 0, 0, 4,
|
|
||||||
0, 0, 0, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint32_t test_b[N_GROUPS][16] = {
|
|
||||||
/* group 0: diagonal */
|
|
||||||
{ 2, 0, 0, 0,
|
|
||||||
0, 3, 0, 0,
|
|
||||||
0, 0, 4, 0,
|
|
||||||
0, 0, 0, 5 },
|
|
||||||
/* group 1 */
|
|
||||||
{ 5, 0, 0, 0,
|
|
||||||
6, 0, 0, 0,
|
|
||||||
0, 7, 0, 0,
|
|
||||||
0, 0, 8, 0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ─── Software reference matmul ─────────────────────────────────────
|
|
||||||
* Returns the 66-bit result element as two 32-bit halves:
|
|
||||||
* words[0] = result[31:0]
|
|
||||||
* words[1] = result[63:32]
|
|
||||||
* words[2] = result[65:64] (only 2 bits, zero-extended to 32)
|
|
||||||
*/
|
|
||||||
static void matmul_ref_u32(
|
|
||||||
const uint32_t a[16],
|
|
||||||
const uint32_t b[16],
|
|
||||||
uint32_t c_words[48])
|
|
||||||
{
|
|
||||||
int row, col, k;
|
|
||||||
for (row = 0; row < 4; row++) {
|
|
||||||
for (col = 0; col < 4; col++) {
|
|
||||||
uint64_t acc = 0;
|
|
||||||
for (k = 0; k < 4; k++) {
|
|
||||||
acc += (uint64_t)a[row * 4 + k] * (uint64_t)b[k * 4 + col];
|
|
||||||
}
|
|
||||||
int idx = (row * 4 + col) * 3;
|
|
||||||
c_words[idx + 0] = (uint32_t)(acc & 0xFFFFFFFFULL);
|
|
||||||
c_words[idx + 1] = (uint32_t)((acc >> 32) & 0xFFFFFFFFULL);
|
|
||||||
c_words[idx + 2] = (uint32_t)((acc >> 64) & 0x3ULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Write 16 words of matrix data to the IP ────────────────────── */
|
|
||||||
static void write_matrix(uint32_t base_addr, const uint32_t data[16])
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 16; i++) {
|
for (i = 0; i < n; i++)
|
||||||
REG_WR(base_addr + i * 4, data[i]);
|
dst[i] = REG_RD(base + i * 4);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── Read 48 words of result C from the IP ──────────────────────── */
|
/* ─── Write N words to IP register space ─────────────────────────── */
|
||||||
static void read_result(uint32_t c_words[48])
|
static void write_ip(uint32_t base, const volatile uint32_t *src, int n)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 48; i++) {
|
for (i = 0; i < n; i++)
|
||||||
c_words[i] = REG_RD(MATMUL_C_BASE + i * 4);
|
REG_WR(base + i * 4, src[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── Wait until IP is done, return 0 on success, -1 on error ────── */
|
/* ─── Wait until IP is done, return 0 on success, -1 on error ────── */
|
||||||
@@ -142,112 +81,77 @@ static int wait_done(void)
|
|||||||
while (1) {
|
while (1) {
|
||||||
uint32_t status = REG_RD(MATMUL_STATUS);
|
uint32_t status = REG_RD(MATMUL_STATUS);
|
||||||
if (status & STATUS_ERROR) {
|
if (status & STATUS_ERROR) {
|
||||||
printf("[ERROR] matmul IP reports error (status=0x%08lx)\n",
|
printf("[ERROR] matmul IP error (status=0x%08lx)\n",
|
||||||
(unsigned long)status);
|
(unsigned long)status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (status & STATUS_DONE) {
|
if (status & STATUS_DONE)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ─── Verify group result against expected C words ───────────────── */
|
|
||||||
static int verify_group(int group, const uint32_t got[48],
|
|
||||||
const uint32_t expected[48])
|
|
||||||
{
|
|
||||||
int i, errors = 0;
|
|
||||||
for (i = 0; i < 48; i++) {
|
|
||||||
if (got[i] != expected[i]) {
|
|
||||||
if (errors < 8) {
|
|
||||||
int elem = i / 3;
|
|
||||||
int sub = i % 3; /* 0=low, 1=high, 2=overflow */
|
|
||||||
const char *sub_name[] = {"low", "high", "ovf"};
|
|
||||||
printf(" group%d C[%d][%d].%s: got 0x%08lx exp 0x%08lx\n",
|
|
||||||
group, elem / 4, elem % 4, sub_name[sub],
|
|
||||||
(unsigned long)got[i], (unsigned long)expected[i]);
|
|
||||||
}
|
|
||||||
errors++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (errors > 8) {
|
|
||||||
printf(" ... and %d more mismatches\n", errors - 8);
|
|
||||||
}
|
|
||||||
return errors;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ─── Main ────────────────────────────────────────────────────────── */
|
/* ─── Main ────────────────────────────────────────────────────────── */
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
int g, pass_count = 0, fail_count = 0;
|
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 IP Test =====\n");
|
printf("\n===== MATMUL ExtRAM Flow Test =====\n");
|
||||||
printf("Base addr : 0x%08lx\n", (unsigned long)MATMUL_BASE);
|
printf("ExtRAM base: 0x%08lx\n", (unsigned long)EXTRAM_BASE);
|
||||||
printf("Groups : %d\n", N_GROUPS);
|
printf("Groups: %d SRC_BASE=%d DST_BASE=%d\n", N_GROUPS, SRC_BASE, DST_BASE);
|
||||||
printf("===========================\n");
|
printf("====================================\n");
|
||||||
|
|
||||||
/* Write group count */
|
|
||||||
REG_WR(MATMUL_GROUP_NUM, N_GROUPS);
|
|
||||||
|
|
||||||
/* For this register-level example, SRC_BASE / DST_BASE are
|
|
||||||
* informational only (no DMA). Set them to 0. */
|
|
||||||
REG_WR(MATMUL_SRC_BASE, 0);
|
|
||||||
REG_WR(MATMUL_DST_BASE, 0);
|
|
||||||
|
|
||||||
/* ── Run each test group ──────────────────────────────────── */
|
|
||||||
for (g = 0; g < N_GROUPS; g++) {
|
for (g = 0; g < N_GROUPS; g++) {
|
||||||
uint32_t expected_c[48];
|
int i;
|
||||||
uint32_t got_c[48];
|
|
||||||
int errs;
|
|
||||||
|
|
||||||
printf("\n--- Group %d ---\n", g);
|
printf("\n--- Group %d ---\n", g);
|
||||||
printf("Loading A[16] and B[16] into IP...\n");
|
|
||||||
|
|
||||||
write_matrix(MATMUL_A_BASE, test_a[g]);
|
/* 1. Read A[16] and B[16] from ExtRAM source region */
|
||||||
write_matrix(MATMUL_B_BASE, test_b[g]);
|
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];
|
||||||
|
}
|
||||||
|
|
||||||
/* Clear any stale done/error flags */
|
/* 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);
|
REG_WR(MATMUL_STATUS, STATUS_DONE | STATUS_ERROR);
|
||||||
|
|
||||||
printf("Starting computation (CTRL=0x%x)...\n", CTRL_START);
|
/* 4. Start computation */
|
||||||
|
printf(" Starting computation...\n");
|
||||||
REG_WR(MATMUL_CTRL, CTRL_START);
|
REG_WR(MATMUL_CTRL, CTRL_START);
|
||||||
|
|
||||||
printf("Waiting for done...\n");
|
/* 5. Wait for done (poll STATUS) */
|
||||||
if (wait_done() != 0) {
|
if (wait_done() != 0) {
|
||||||
fail_count++;
|
printf(" Group %d: FAIL (IP error)\n", g);
|
||||||
continue;
|
fail++;
|
||||||
}
|
/* zero-fill result area so testbench clearly sees failure */
|
||||||
|
for (i = 0; i < 48; i++) c_buf[i] = 0;
|
||||||
printf("Reading C[48] from IP...\n");
|
|
||||||
read_result(got_c);
|
|
||||||
|
|
||||||
printf("Computing software reference...\n");
|
|
||||||
matmul_ref_u32(test_a[g], test_b[g], expected_c);
|
|
||||||
|
|
||||||
printf("Verifying...\n");
|
|
||||||
errs = verify_group(g, got_c, expected_c);
|
|
||||||
|
|
||||||
if (errs == 0) {
|
|
||||||
printf("Group %d: PASS\n", g);
|
|
||||||
pass_count++;
|
|
||||||
} else {
|
} else {
|
||||||
printf("Group %d: FAIL (%d mismatches)\n", g, errs);
|
/* 6. Read result C[48] from IP */
|
||||||
fail_count++;
|
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 ─────────────────────────────────────────── */
|
/* ── Final report ─────────────────────────────────────────── */
|
||||||
printf("\n============================\n");
|
printf("\n============================\n");
|
||||||
printf("RESULTS: %d passed, %d failed\n", pass_count, fail_count);
|
printf("RESULTS: %d passed, %d failed\n", pass, fail);
|
||||||
if (fail_count == 0) {
|
|
||||||
printf("ALL TESTS PASSED\n");
|
|
||||||
} else {
|
|
||||||
printf("SOME TESTS FAILED\n");
|
|
||||||
}
|
|
||||||
printf("============================\n");
|
printf("============================\n");
|
||||||
|
|
||||||
/* Signal completion to testbench via UART */
|
/* Signal completion to testbench via UART */
|
||||||
printf("MATMUL_DONE\n");
|
printf("MATMUL_DONE\n");
|
||||||
|
|
||||||
return (fail_count == 0) ? 0 : 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user