Fix CRC32 table entry 187
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
/**
|
||||
* user-sample - CIC-IEC 2026 Stage 3 Evaluation Program
|
||||
*
|
||||
* (UPDATED FOR PING-PONG BUFFER ARCHITECTURE)
|
||||
* (ULTIMATE PERFORMANCE DMA + PING-PONG BUFFER ARCHITECTURE)
|
||||
*
|
||||
* Reads N groups of 4x4 unsigned matrix multiplications from ExtRAM,
|
||||
* computes C = A x B via the hardware matmul IP using Ping-Pong buffering,
|
||||
* writes results back, computes CRC32 over the result region, and outputs
|
||||
* the required identifiers.
|
||||
* Utilizes true DMA transfers (Channel 0 for memory->IP, Channel 1 for IP->memory)
|
||||
* perfectly overlapped with Hardware IP computation to achieve Zero-Wait execution.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common_func.h>
|
||||
#include <confreg_time.h>
|
||||
#include <dma.h>
|
||||
|
||||
/* ─── Configurable group count (default 10 for fast local testing) ─── */
|
||||
#ifndef MATMUL_GROUP_NUM
|
||||
#define MATMUL_GROUP_NUM 5000
|
||||
@@ -25,32 +29,33 @@ unsigned long CORE_CLOCKS_PER_SEC = 33000000L;
|
||||
|
||||
/* ─── Memory layout ────────────────────────────────────────────────── */
|
||||
#define EXTRAM_BASE_PHYS 0x1c400000
|
||||
#define EXTRAM_BASE (0xA0000000 | (EXTRAM_BASE_PHYS & 0x1FFFFFFF))
|
||||
#define EXTRAM_BASE_UNCACHED (0xA0000000 | (EXTRAM_BASE_PHYS & 0x1FFFFFFF))
|
||||
|
||||
#define SRC_BASE 0
|
||||
#define DST_BASE (SRC_BASE + MATMUL_GROUP_NUM * 32)
|
||||
#define SRC_BASE_WORDS 0
|
||||
#define DST_BASE_WORDS (SRC_BASE_WORDS + MATMUL_GROUP_NUM * 32)
|
||||
#define RESULT_WORDS (MATMUL_GROUP_NUM * 48)
|
||||
#define RESULT_BYTES (RESULT_WORDS * 4)
|
||||
|
||||
/* ExtRAM Physical Addresses for DMA */
|
||||
#define EXTRAM_PHYS_AB(g) (EXTRAM_BASE_PHYS + (SRC_BASE_WORDS * 4) + (g) * 128)
|
||||
#define EXTRAM_PHYS_C(g) (EXTRAM_BASE_PHYS + (DST_BASE_WORDS * 4) + (g) * 192)
|
||||
|
||||
/* ─── MATMUL IP registers (Ping-Pong Memory Map) ──────────────────── */
|
||||
#define MATMUL_BASE 0xbf500000
|
||||
#define MATMUL_CTRL (MATMUL_BASE + 0x000)
|
||||
#define MATMUL_STATUS (MATMUL_BASE + 0x004)
|
||||
#define MATMUL_BASE_PHYS 0x1f500000
|
||||
#define MATMUL_BASE_UNCACHED 0xbf500000
|
||||
|
||||
// Bank 0 Memory Space
|
||||
#define MATMUL_B0_A (MATMUL_BASE + 0x100)
|
||||
#define MATMUL_B0_B (MATMUL_BASE + 0x140)
|
||||
#define MATMUL_B0_C (MATMUL_BASE + 0x180)
|
||||
// CPU Control & Status Registers
|
||||
#define MATMUL_CTRL (MATMUL_BASE_UNCACHED + 0x000)
|
||||
#define MATMUL_STATUS (MATMUL_BASE_UNCACHED + 0x004)
|
||||
|
||||
// Bank 1 Memory Space
|
||||
#define MATMUL_B1_A (MATMUL_BASE + 0x300)
|
||||
#define MATMUL_B1_B (MATMUL_BASE + 0x340)
|
||||
#define MATMUL_B1_C (MATMUL_BASE + 0x380)
|
||||
// DMA Physical Addresses for IP Space
|
||||
// (A and B are contiguous: A is 0x100~0x13F, B is 0x140~0x17F. Total 128 bytes)
|
||||
#define MATMUL_PHYS_B0_AB (MATMUL_BASE_PHYS + 0x100)
|
||||
#define MATMUL_PHYS_B0_C (MATMUL_BASE_PHYS + 0x180) // 192 bytes
|
||||
#define MATMUL_PHYS_B1_AB (MATMUL_BASE_PHYS + 0x300)
|
||||
#define MATMUL_PHYS_B1_C (MATMUL_BASE_PHYS + 0x380)
|
||||
|
||||
// Control & Status Bit Masks
|
||||
#define CTRL_START_B0 0x1
|
||||
#define CTRL_START_B1 0x2
|
||||
#define STATUS_BUSY 0x1
|
||||
#define STATUS_DONE 0x2
|
||||
#define STATUS_ERROR 0x4
|
||||
|
||||
@@ -94,40 +99,26 @@ static const uint32_t crc32_table[256] = {
|
||||
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
/* ─── Read N words from IP register space ─────────────────────────── */
|
||||
static void read_ip(uint32_t base, volatile uint32_t *dst, int n)
|
||||
{
|
||||
for (int 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)
|
||||
{
|
||||
for (int i = 0; i < n; i++)
|
||||
REG_WR(base + i * 4, src[i]);
|
||||
}
|
||||
|
||||
/* ─── Poll IP STATUS until done and clear it (W1C) ────────────────── */
|
||||
static void wait_and_clear_done(void)
|
||||
static void wait_matmul_done(void)
|
||||
{
|
||||
uint32_t status;
|
||||
do {
|
||||
status = REG_RD(MATMUL_STATUS);
|
||||
} while (!(status & (STATUS_DONE | STATUS_ERROR)));
|
||||
|
||||
// Write 1 to Clear the DONE bit so it's ready for the next interrupt/poll
|
||||
// Write 1 to Clear the DONE bit
|
||||
REG_WR(MATMUL_STATUS, STATUS_DONE);
|
||||
}
|
||||
|
||||
/* ─── CRC32 over ExtRAM result region (little-endian byte stream) ─── */
|
||||
/* ─── CRC32 over ExtRAM result region ─────────────────────────────── */
|
||||
static uint32_t compute_crc32(volatile uint32_t *extram)
|
||||
{
|
||||
uint32_t crc = 0xFFFFFFFF;
|
||||
uint32_t i, w;
|
||||
|
||||
for (i = 0; i < RESULT_WORDS; i++) {
|
||||
w = extram[DST_BASE + i];
|
||||
w = extram[DST_BASE_WORDS + i];
|
||||
crc = crc32_table[(crc ^ (w & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ ((w >> 8) & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ ((w >> 16) & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
@@ -141,86 +132,94 @@ int main(void)
|
||||
{
|
||||
if (MATMUL_GROUP_NUM <= 0) return 0;
|
||||
|
||||
volatile uint32_t *extram = (volatile uint32_t *)EXTRAM_BASE;
|
||||
uint32_t a_buf[16], b_buf[16], c_buf[48];
|
||||
volatile uint32_t *extram = (volatile uint32_t *)EXTRAM_BASE_UNCACHED;
|
||||
uint32_t crc;
|
||||
int g, i;
|
||||
int g;
|
||||
|
||||
// Ping-Pong Buffer Register Addresses
|
||||
uint32_t bank_A[2] = {MATMUL_B0_A, MATMUL_B1_A};
|
||||
uint32_t bank_B[2] = {MATMUL_B0_B, MATMUL_B1_B};
|
||||
uint32_t bank_C[2] = {MATMUL_B0_C, MATMUL_B1_C};
|
||||
// Ping-Pong Register Address Arrays (Physical for DMA)
|
||||
uint32_t phys_bank_AB[2] = {MATMUL_PHYS_B0_AB, MATMUL_PHYS_B1_AB};
|
||||
uint32_t phys_bank_C[2] = {MATMUL_PHYS_B0_C, MATMUL_PHYS_B1_C};
|
||||
|
||||
// IP Control Command Arrays
|
||||
uint32_t ctrl_start[2] = {CTRL_START_B0, CTRL_START_B1};
|
||||
int cur_bank = 0;
|
||||
|
||||
/* ── Start marker (must be first output) ──────────────────── */
|
||||
printf("MATMUL_START\n");
|
||||
crc = 0xFFFFFFFF;
|
||||
|
||||
/* ── Prologue: Load and Start the very first group ────────── */
|
||||
for (i = 0; i < 16; i++) {
|
||||
a_buf[i] = extram[SRC_BASE + 0 * 32 + i];
|
||||
b_buf[i] = extram[SRC_BASE + 0 * 32 + 16 + i];
|
||||
}
|
||||
write_ip(bank_A[0], a_buf, 16);
|
||||
write_ip(bank_B[0], b_buf, 16);
|
||||
unsigned int tick_start = get_ns();
|
||||
|
||||
// Clear any pending statuses before starting
|
||||
// 清理寄存器状态
|
||||
REG_WR(MATMUL_STATUS, STATUS_DONE | STATUS_ERROR);
|
||||
|
||||
/* ── Prologue: 第0组数据初始化 ────────────────────────── */
|
||||
// DMA Ch0: 从 ExtRAM 将 Group 0 的 A、B (128 bytes) 搬入 IP 的 Bank 0
|
||||
dma_start_transfer(0, EXTRAM_PHYS_AB(0), phys_bank_AB[0], 128, 10);
|
||||
dma_wait_polling(0); // 必须等待首个数据加载完成
|
||||
|
||||
// 启动 IP Bank 0 计算
|
||||
REG_WR(MATMUL_CTRL, ctrl_start[0]);
|
||||
|
||||
/* ── Main Loop: Pipelined Execution ───────────────────────── */
|
||||
/* ── Main Loop: 硬件完全流水线 (Overlapped Execution) ──── */
|
||||
// 在 g 循环中:
|
||||
// IP 正在计算 prev_bank (g-1)
|
||||
// DMA_CH0 正在加载 cur_bank (g)
|
||||
// DMA_CH1 正在写回 prev_prev_bank (g-2)
|
||||
for (g = 1; g < MATMUL_GROUP_NUM; g++) {
|
||||
cur_bank = g % 2;
|
||||
int cur_bank = g % 2;
|
||||
int prev_bank = (g - 1) % 2;
|
||||
int finished_g = g - 1;
|
||||
|
||||
// 1. Prepare/Load data for the NEXT group into the idle bank
|
||||
// (This happens concurrently while hardware calculates the previous group)
|
||||
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];
|
||||
// 1. 发起加载下一组数据的 DMA 传输 (Channel 0: Memory -> IP)
|
||||
dma_start_transfer(0, EXTRAM_PHYS_AB(g), phys_bank_AB[cur_bank], 128, 10);
|
||||
|
||||
// 2. 等待上一组在 IP 中的计算完成
|
||||
wait_matmul_done();
|
||||
|
||||
// 3. 确保上一次的结果写回 (Channel 1) 已经空闲
|
||||
if (g > 1) {
|
||||
dma_wait_polling(1);
|
||||
}
|
||||
write_ip(bank_A[cur_bank], a_buf, 16);
|
||||
write_ip(bank_B[cur_bank], b_buf, 16);
|
||||
|
||||
// 2. Wait for the PREVIOUS group hardware calculation to finish
|
||||
wait_and_clear_done();
|
||||
// 4. 发起写回刚才计算完成的结果 (Channel 1: IP -> Memory)
|
||||
dma_start_transfer(1, phys_bank_C[prev_bank], EXTRAM_PHYS_C(g - 1), 192, 20);
|
||||
|
||||
// 3. Immediately start the current bank to keep hardware busy
|
||||
// 5. 确保当前要计算的输入数据 (Channel 0) 已经加载完毕
|
||||
dma_wait_polling(0);
|
||||
|
||||
// 6. 立即启动当前组在 IP 中的计算
|
||||
REG_WR(MATMUL_CTRL, ctrl_start[cur_bank]);
|
||||
|
||||
// 4. Read the PREVIOUS group's result and write to memory
|
||||
read_ip(bank_C[prev_bank], c_buf, 48);
|
||||
for (i = 0; i < 48; i++) {
|
||||
uint32_t w = c_buf[i];
|
||||
crc = crc32_table[(crc ^ (w & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ ((w >> 8) & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ ((w >> 16) & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ (w >> 24) ) & 0xFF] ^ (crc >> 8);
|
||||
extram[DST_BASE + finished_g * 48 + i] = w;
|
||||
// 调试输出逻辑 (通过无缓存指针直接从内存读取刚刚 DMA 写回的数据)
|
||||
// 注意:因为 Channel 1 刚启动,需要等它搬运完才能打印 C[0..2]
|
||||
if (g - 1 == 1) { // 也就是当刚刚计算完 Group 1 并发起 DMA 后
|
||||
dma_wait_polling(1); // 强制等一下,供打印使用
|
||||
printf("DBG C[0..2]=%08lx %08lx %08lx\n",
|
||||
(unsigned long)extram[DST_BASE_WORDS + 1 * 48 + 0],
|
||||
(unsigned long)extram[DST_BASE_WORDS + 1 * 48 + 1],
|
||||
(unsigned long)extram[DST_BASE_WORDS + 1 * 48 + 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if (finished_g == 0) {
|
||||
/* ── Epilogue: 收尾最后一组 ───────────────────────────── */
|
||||
wait_matmul_done(); // 等待最后一次计算完成
|
||||
dma_wait_polling(1); // 确保之前的 DMA CH1 空闲
|
||||
|
||||
// DMA CH1 将最后一组结果写回
|
||||
dma_start_transfer(1, phys_bank_C[(MATMUL_GROUP_NUM - 1) % 2], EXTRAM_PHYS_C(MATMUL_GROUP_NUM - 1), 192, 20);
|
||||
dma_wait_polling(1); // 必须等待最后一组写回完成
|
||||
|
||||
unsigned int tick_end = get_ns();
|
||||
|
||||
// 检查测试输出要求
|
||||
printf("DBG wrote C[0]=%08lx @ ExtRAM[%d]\n",
|
||||
(unsigned long)extram[DST_BASE], DST_BASE);
|
||||
}
|
||||
}
|
||||
(unsigned long)extram[DST_BASE_WORDS], DST_BASE_WORDS);
|
||||
|
||||
/* ── Epilogue: Wait for and read the very last group ──────── */
|
||||
wait_and_clear_done();
|
||||
read_ip(bank_C[cur_bank], c_buf, 48);
|
||||
for (i = 0; i < 48; i++) {
|
||||
uint32_t w = c_buf[i];
|
||||
crc = crc32_table[(crc ^ (w & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ ((w >> 8) & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ ((w >> 16) & 0xFF)) & 0xFF] ^ (crc >> 8);
|
||||
crc = crc32_table[(crc ^ (w >> 24) ) & 0xFF] ^ (crc >> 8);
|
||||
extram[DST_BASE + (MATMUL_GROUP_NUM - 1) * 48 + i] = w;
|
||||
}
|
||||
printf("\n--- Performance Data ---\n");
|
||||
unsigned int total_time = tick_end - tick_start;
|
||||
printf("Matmul %d groups total time: %u ns (%.3f ms)\n",
|
||||
MATMUL_GROUP_NUM, total_time, (float)total_time / 1000000.0);
|
||||
|
||||
/* ── Finalize CRC32 ──────────────────────────────────────── */
|
||||
crc ^= 0xFFFFFFFF;
|
||||
/* ── CRC32 over result region ─────────────────────────────── */
|
||||
crc = compute_crc32(extram);
|
||||
|
||||
/* ── Final markers ────────────────────────────────────────── */
|
||||
printf("MATMUL_CRC32=%08lx\n", (unsigned long)crc);
|
||||
|
||||
Reference in New Issue
Block a user