diff --git a/sdk/software/bsp/drivers/dma.c b/sdk/software/bsp/drivers/dma.c new file mode 100644 index 0000000..551b725 --- /dev/null +++ b/sdk/software/bsp/drivers/dma.c @@ -0,0 +1,37 @@ +#include "dma.h" + +void dma_start_transfer(int ch_id, uint32_t src, uint32_t dst, uint32_t bytes, uint32_t tag) { + volatile dma_ch_regs_t* ch = DMA_CH(ch_id); + + // 检查通道是否空闲 防止覆盖正在运行的任务 + if (ch->STATUS & STATUS_BUSY_BIT) { + // printf("channel %d busy\n", ch_id); + return; // 通道正忙,处理报错或重试 + } + + // 写入基本地址和长度 + ch->SRC_ADDR = src; + ch->DST_ADDR = dst; + ch->LENGTH = bytes; + ch->TAG = tag; // 可选,填入任务ID + + // 置 Burst 属性并触发传输 + // AXI SIZE: 2 (代表 2^2 = 4 Bytes,与 32-bit 数据线匹配) + // AXI LEN: 15 (代表 16 beats 突发传输,最高效) + uint32_t ctrl_val = CTRL_BURST_SIZE(2) | CTRL_BURST_LEN(15); + + // 写入 CTRL 并拉高 Bit 0 (Start) + ch->CTRL = ctrl_val | CTRL_START_BIT; +} + +void dma_wait_polling(int ch_id) { + volatile dma_ch_regs_t* ch = DMA_CH(ch_id); + + // 死等 Done bit 置 1 + while (!(ch->STATUS & STATUS_DONE_BIT)) { + } + + // 清除 Done 标志位 (Write 1 to Clear Bit 1) + // 注意:写 1 清 0 的设计,所以我们对 bit 1 写入 1 + ch->STATUS = STATUS_DONE_BIT; +} \ No newline at end of file diff --git a/sdk/software/bsp/drivers/fft.c b/sdk/software/bsp/drivers/fft.c new file mode 100644 index 0000000..4476886 --- /dev/null +++ b/sdk/software/bsp/drivers/fft.c @@ -0,0 +1,14 @@ +#include "fft.h" +#include "common_func.h" + +void fft_start() { + RegWrite(FFT_CSR_REG, FFT_CTRL_START); +} + +void fft_wait() { + while ((RegRead(FFT_CSR_REG) & FFT_STAT_DONE) == 0) {} +} + +unsigned int fft_get_csr() { + return RegRead(FFT_CSR_REG); +} \ No newline at end of file diff --git a/sdk/software/bsp/include/dma.h b/sdk/software/bsp/include/dma.h new file mode 100644 index 0000000..8187fb9 --- /dev/null +++ b/sdk/software/bsp/include/dma.h @@ -0,0 +1,30 @@ +#pragma once + +#include + + +typedef struct { + volatile uint32_t SRC_ADDR; // 0x00: 源地址 + volatile uint32_t DST_ADDR; // 0x04: 目的地址 + volatile uint32_t LENGTH; // 0x08: 传输总字节数 + volatile uint32_t TAG; // 0x0C: 软件 Tag (硬件不处理,留给软件标记任务用) + volatile uint32_t CTRL; // 0x10: 控制寄存器 (配置 Burst 属性 + 启动) + volatile uint32_t STATUS; // 0x14: 状态寄存器 (Busy, Done) + volatile uint32_t RESV[10]; // 0x18 ~ 0x3C: 保留空间,凑齐 0x40 字节 +} dma_ch_regs_t; + +// DMA 控制器基地址 +#define CDMA_MUX_BASE 0xbf300000 +#define DMA_CH(i) ((volatile dma_ch_regs_t*)(CDMA_MUX_BASE + (i) * 0x40)) + +// 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) +#define CTRL_BURST_LEN(x) (((x) & 0xFF) << 6) // Bits [13:6]: AXI AxLEN (0=1 beat, 15=16 beats) + +// STATUS 寄存器位定义 +#define STATUS_BUSY_BIT (1 << 0) +#define STATUS_DONE_BIT (1 << 1) + +void dma_start_transfer(int ch_id, uint32_t src, uint32_t dst, uint32_t bytes, uint32_t tag); +void dma_wait_polling(int ch_id); \ No newline at end of file diff --git a/sdk/software/bsp/include/fft.h b/sdk/software/bsp/include/fft.h new file mode 100644 index 0000000..dca7dec --- /dev/null +++ b/sdk/software/bsp/include/fft.h @@ -0,0 +1,16 @@ +#pragma once + +#define FFT_BASE 0xbf400000 +#define FFT_IN_RE_BASE (FFT_BASE + 0x1000) +#define FFT_IN_IM_BASE (FFT_BASE + 0x2000) +#define FFT_OUT_RE_BASE (FFT_BASE + 0x3000) +#define FFT_OUT_IM_BASE (FFT_BASE + 0x4000) +#define FFT_CSR_REG (FFT_BASE + 0xF000) +#define FFT_CTRL_START (1 << 4) +#define FFT_STAT_DONE (1 << 1) +#define FFT_STAT_BUSY (1 << 0) +#define FFT_POINT_NUM 1024 + +void fft_start(); +void fft_wait(); +unsigned int fft_get_csr(); \ No newline at end of file diff --git a/sdk/software/examples/dma/Makefile b/sdk/software/examples/dma/Makefile new file mode 100644 index 0000000..62a06cd --- /dev/null +++ b/sdk/software/examples/dma/Makefile @@ -0,0 +1,11 @@ +TARGET = dma + +CFLAGS += -O3 -g + +C_SRCS := $(wildcard ./*.c ) + +OBJDIR = obj +COMMON_DIR = ../../bsp +GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0 +PICOLIBC_DIR=../../../toolchains/picolibc +include ../../bsp/common.mk diff --git a/sdk/software/examples/dma/main.c b/sdk/software/examples/dma/main.c new file mode 100644 index 0000000..60cf57d --- /dev/null +++ b/sdk/software/examples/dma/main.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +// BSP板级支持包所需全局变量 +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; + +// 加上 aligned(64) 是为了防止 DMA 突发传输时跨越缓存行或 AXI 非对齐边界 +uint32_t src_array[64] __attribute__((aligned(64))); +uint32_t dst_array[64] __attribute__((aligned(64))); + +int main(int argc, char** argv) +{ + uint32_t data_len = 64; + uint32_t byte_len = data_len * 4; + + // 虚拟地址转物理地址与无缓存地址 + // 屏蔽掉高 3 位(& 0x1FFFFFFF)即可获得真实的物理地址 + uint32_t phys_src_addr = ((uint32_t)src_array) & 0x1FFFFFFF; + uint32_t phys_dst_addr = ((uint32_t)dst_array) & 0x1FFFFFFF; + + // 或上 0xA0000000 即可获得绕过 Cache 的无缓存(Uncached)指针 + volatile uint32_t *uncached_src = (volatile uint32_t *)(phys_src_addr | 0xA0000000); + volatile uint32_t *uncached_dst = (volatile uint32_t *)(phys_dst_addr | 0xA0000000); + + // CPU 必须通过无缓存指针写入 + for (int i = 0; i < data_len; i++) { + uncached_src[i] = i * i; // 填入 0~63 + uncached_dst[i] = 0xDEADBEEF; // 目的数组填入垃圾值,方便验证是否真的被覆盖 + } + + printf("src_array: %x\n", src_array); + printf("dst_array: %x\n", dst_array); + printf("phys_src_array: %x\n", phys_src_addr); + printf("phys_dst_array: %x\n", phys_dst_addr); + printf("uncached_src: %x\n", uncached_src); + printf("uncached_dst: %x\n", uncached_dst); + + // 配置 DMA:DMA 只需要最纯粹的物理地址 + dma_start_transfer(0, phys_src_addr, phys_dst_addr, byte_len); + dma_wait_polling(0); + + printf("dma passed!\n"); + + // 校验数据:CPU 必须通过无缓存指针读取 + int err = 0; + for (int i = 0; i < data_len; i++) { + uint32_t val = uncached_dst[i]; + printf("%d: %d\n", i, val); + if (val != i * i) { + err++; + } + } + + if (err == 0) { + printf("\nSuccess! Array to Array DMA transfer verified.\n"); + } else { + printf("\nFailed! Found %d errors.\n", err); + } + + return 0; +} \ No newline at end of file diff --git a/sdk/software/examples/dma/result.txt b/sdk/software/examples/dma/result.txt new file mode 100644 index 0000000..7c2ddbd --- /dev/null +++ b/sdk/software/examples/dma/result.txt @@ -0,0 +1,75 @@ +dma_status init = 0 +src_array: 1c080d80 +dst_array: 1c080c80 +phys_src_array: 1c080d80 +phys_dst_array: 1c080c80 +uncached_src: bc080d80 +uncached_dst: bc080c80 +polling... +dma passed! +0: 0 +1: 1 +2: 4 +3: 9 +4: 16 +5: 25 +6: 36 +7: 49 +8: 64 +9: 81 +10: 100 +11: 121 +12: 144 +13: 169 +14: 196 +15: 225 +16: 256 +17: 289 +18: 324 +19: 361 +20: 400 +21: 441 +22: 484 +23: 529 +24: 576 +25: 625 +26: 676 +27: 729 +28: 784 +29: 841 +30: 900 +31: 961 +32: 1024 +33: 1089 +34: 1156 +35: 1225 +36: 1296 +37: 1369 +38: 1444 +39: 1521 +40: 1600 +41: 1681 +42: 1764 +43: 1849 +44: 1936 +45: 2025 +46: 2116 +47: 2209 +48: 2304 +49: 2401 +50: 2500 +51: 2601 +52: 2704 +53: 2809 +54: 2916 +55: 3025 +56: 3136 +57: 3249 +58: 3364 +59: 3481 +60: 3600 +61: 3721 +62: 3844 +63: 3969 + +Success! Array to Array DMA transfer verified. diff --git a/sdk/software/examples/fft/Makefile b/sdk/software/examples/fft/Makefile new file mode 100644 index 0000000..75d724f --- /dev/null +++ b/sdk/software/examples/fft/Makefile @@ -0,0 +1,11 @@ +TARGET = fft + +CFLAGS += -O3 -g + +C_SRCS := $(wildcard ./*.c ) + +OBJDIR = obj +COMMON_DIR = ../../bsp +GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0 +PICOLIBC_DIR=../../../toolchains/picolibc +include ../../bsp/common.mk diff --git a/sdk/software/examples/fft/main.c b/sdk/software/examples/fft/main.c new file mode 100644 index 0000000..7945667 --- /dev/null +++ b/sdk/software/examples/fft/main.c @@ -0,0 +1,156 @@ +#include +#include +#include + +#include +#include +#include + +// BSP板级支持包所需全局变量 +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; + +const float PI = 3.14159265358979323846; + +// 读取定时器的当前Tick +unsigned int get_timer_ticks() { + return RegRead(CONFREG_TIMER_BASE); +} + +// 软件FFT实现 (基2 DIT-FFT 算法) +void sw_fft(float re[], float im[], int n) { + int i, j, k, l; + float tr, ti, ur, ui, wr, wi; + + // 比特翻转 (Bit Reversal) + j = 0; + for (i = 0; i < n - 1; i++) { + if (i < j) { + tr = re[i]; ti = im[i]; + re[i] = re[j]; im[i] = im[j]; + re[j] = tr; im[j] = ti; + } + k = n / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + + // 蝶形运算 (Butterfly Computation) + for (l = 1; l < n; l *= 2) { + ur = 1.0; + ui = 0.0; + wr = cos(PI / l); + wi = -sin(PI / l); + + for (i = 0; i < n; i += 2 * l) { + ur = 1.0; + ui = 0.0; + for (j = 0; j < l; j++) { + int p = i + j; + int q = p + l; + + tr = re[q] * ur - im[q] * ui; + ti = re[q] * ui + im[q] * ur; + + re[q] = re[p] - tr; + im[q] = im[p] - ti; + re[p] += tr; + im[p] += ti; + + float next_ur = ur * wr - ui * wi; + ui = ur * wi + ui * wr; + ur = next_ur; + } + } + } +} + +int main(int argc, char** argv) +{ + unsigned int fft_csr = RegRead(FFT_CSR_REG); + printf("fft_csr = %x\n", fft_csr); + + // 准备测试数据 + float sw_in_re[FFT_POINT_NUM]; + float sw_in_im[FFT_POINT_NUM]; + + for (int i = 0; i < FFT_POINT_NUM; i++) { + float dc_part = 4000.0f; + float f10_part = 8000.0f * cos(2 * PI * 10.0 * i / FFT_POINT_NUM); + float f200_part = 6000.0f * sin(2 * PI * 200.0 * i / FFT_POINT_NUM); + float f400_part = 3000.0f * sin(2 * PI * 400.0 * i / FFT_POINT_NUM); + + sw_in_re[i] = dc_part + f10_part + f200_part + f400_part; + sw_in_im[i] = 0.0f; + } + + unsigned int tick_start, tick_end; + unsigned int hw_time, sw_time; + + // 硬件加速 FFT 测试 + printf("\n--- Starting Hardware FFT ---\n"); + tick_start = get_ns(); + + for (int i = 0; i < FFT_POINT_NUM; i++) { + RegWrite(FFT_IN_RE_BASE + (i * 4), (unsigned int)((int)sw_in_re[i])); + RegWrite(FFT_IN_IM_BASE + (i * 4), 0); + } + + + fft_start(); + fft_wait(); + + tick_end = get_ns(); + + // 如果定时器是递减的,这里可能是 tick_start - tick_end + // 假设定时器是向上递增的: + hw_time = tick_end - tick_start; + + int hw_out_re[FFT_POINT_NUM]; + int hw_out_im[FFT_POINT_NUM]; + for (int i = 0; i < FFT_POINT_NUM; i++) { + hw_out_re[i] = (int)RegRead(FFT_OUT_RE_BASE + (i * 4)); + hw_out_im[i] = (int)RegRead(FFT_OUT_IM_BASE + (i * 4)); + } + + // ========================================== + // 2. 纯软件 FFT 测试 + // ========================================== + printf("--- Starting Software FFT ---\n"); + tick_start = get_ns(); + + sw_fft(sw_in_re, sw_in_im, FFT_POINT_NUM); + + tick_end = get_ns(); + sw_time = tick_end - tick_start; + + + // ========================================== + // 3. 打印对比结果 + // ========================================== + printf("\n--- Performance Comparison ---\n"); + printf("Timer Clock Freq : %lu Hz\n", CONFREG_CLOCKS_PER_SEC); + printf("Hardware FFT Time: %u ns (%.3f ms)\n", hw_time, (float)hw_time / 1000000.0); + printf("Software FFT Time: %u ns (%.3f ms)\n", sw_time, (float)sw_time / 1000000.0); + + if (hw_time > 0) { + printf("Speedup Ratio : %.2fx\n", (float)sw_time / hw_time); + } + + printf("\n--- Verification (Only showing Bins with energy > 10) ---\n"); + for (int i = 0; i < FFT_POINT_NUM; i++) { + if (fabs(hw_out_re[i]) > 10 || fabs(hw_out_im[i]) > 10) { + printf("Bin [%4d] Hz: HW(Re:%6d, Im:%6d) | SW(Re:%6d, Im:%6d)\n", + i, + hw_out_re[i], hw_out_im[i], + (int)sw_in_re[i] / FFT_POINT_NUM, (int)sw_in_im[i] / FFT_POINT_NUM); + } + } + + return 0; +} \ No newline at end of file diff --git a/sdk/software/examples/fft/result.txt b/sdk/software/examples/fft/result.txt new file mode 100644 index 0000000..de30c47 --- /dev/null +++ b/sdk/software/examples/fft/result.txt @@ -0,0 +1,19 @@ +fft_csr = 0 + +--- Starting Hardware FFT --- +--- Starting Software FFT --- + +--- Performance Comparison --- +Timer Clock Freq : 50000000 Hz +Hardware FFT Time: 1695360 ns (1.695 ms) +Software FFT Time: 274547190 ns (274.547 ms) +Speedup Ratio : 161.94x + +--- Verification (Only showing Bins with energy > 10) --- +Bin [ 0] Hz: HW(Re: 4007, Im: 0) | SW(Re: 4000, Im: 0) +Bin [ 10] Hz: HW(Re: 4006, Im: -1) | SW(Re: 3999, Im: 0) +Bin [ 200] Hz: HW(Re: 2, Im: -2994) | SW(Re: 0, Im: -3000) +Bin [ 400] Hz: HW(Re: -5, Im: -1496) | SW(Re: 0, Im: -1499) +Bin [ 624] Hz: HW(Re: -5, Im: 1497) | SW(Re: 0, Im: 1500) +Bin [ 824] Hz: HW(Re: 3, Im: 2994) | SW(Re: 0, Im: 2999) +Bin [1014] Hz: HW(Re: 4007, Im: 0) | SW(Re: 3999, Im: 0) diff --git a/sdk/software/examples/fft_dma/Makefile b/sdk/software/examples/fft_dma/Makefile new file mode 100644 index 0000000..f15dec1 --- /dev/null +++ b/sdk/software/examples/fft_dma/Makefile @@ -0,0 +1,11 @@ +TARGET = fft_dma + +CFLAGS += -O3 -g + +C_SRCS := $(wildcard ./*.c ) + +OBJDIR = obj +COMMON_DIR = ../../bsp +GCC_DIR=../../../toolchains/loongson-gnu-toolchain-8.3-x86_64-loongarch32r-linux-gnusf-v2.0 +PICOLIBC_DIR=../../../toolchains/picolibc +include ../../bsp/common.mk diff --git a/sdk/software/examples/fft_dma/main.c b/sdk/software/examples/fft_dma/main.c new file mode 100644 index 0000000..febd07e --- /dev/null +++ b/sdk/software/examples/fft_dma/main.c @@ -0,0 +1,179 @@ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +// BSP板级支持包所需全局变量 +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; + +const float PI = 3.14159265358979323846; + +// 软件FFT实现 (基2 DIT-FFT 算法) +void sw_fft(float re[], float im[], int n) { + int i, j, k, l; + float tr, ti, ur, ui, wr, wi; + + j = 0; + for (i = 0; i < n - 1; i++) { + if (i < j) { + tr = re[i]; ti = im[i]; + re[i] = re[j]; im[i] = im[j]; + re[j] = tr; im[j] = ti; + } + k = n / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + + for (l = 1; l < n; l *= 2) { + ur = 1.0; + ui = 0.0; + wr = cos(PI / l); + wi = -sin(PI / l); + + for (i = 0; i < n; i += 2 * l) { + ur = 1.0; + ui = 0.0; + for (j = 0; j < l; j++) { + int p = i + j; + int q = p + l; + + tr = re[q] * ur - im[q] * ui; + ti = re[q] * ui + im[q] * ur; + + re[q] = re[p] - tr; + im[q] = im[p] - ti; + re[p] += tr; + im[p] += ti; + + float next_ur = ur * wr - ui * wi; + ui = ur * wi + ui * wr; + ur = next_ur; + } + } + } +} + +// 全局对齐数组:作为 DMA 的源和目的内存 +int32_t hw_in_re_arr[FFT_POINT_NUM] __attribute__((aligned(64))); +int32_t hw_in_im_arr[FFT_POINT_NUM] __attribute__((aligned(64))); +int32_t hw_out_re_arr[FFT_POINT_NUM] __attribute__((aligned(64))); +int32_t hw_out_im_arr[FFT_POINT_NUM] __attribute__((aligned(64))); + +int main(int argc, char** argv) +{ + unsigned int fft_csr = RegRead(FFT_CSR_REG); + printf("fft_csr init = %x\n", fft_csr); + + // 获取外设的纯物理地址 (屏蔽高3位 0x1FFFFFFF) + uint32_t phys_fft_in_re = FFT_IN_RE_BASE & 0x1FFFFFFF; + uint32_t phys_fft_in_im = FFT_IN_IM_BASE & 0x1FFFFFFF; + uint32_t phys_fft_out_re = FFT_OUT_RE_BASE & 0x1FFFFFFF; + uint32_t phys_fft_out_im = FFT_OUT_IM_BASE & 0x1FFFFFFF; + + // 获取内存数组的纯物理地址,并包装为 CPU 使用的无缓存(Uncached)指针 + volatile int32_t *uncached_in_re = (volatile int32_t *)(((uint32_t)hw_in_re_arr & 0x1FFFFFFF) | 0xA0000000); + volatile int32_t *uncached_in_im = (volatile int32_t *)(((uint32_t)hw_in_im_arr & 0x1FFFFFFF) | 0xA0000000); + volatile int32_t *uncached_out_re = (volatile int32_t *)(((uint32_t)hw_out_re_arr & 0x1FFFFFFF) | 0xA0000000); + volatile int32_t *uncached_out_im = (volatile int32_t *)(((uint32_t)hw_out_im_arr & 0x1FFFFFFF) | 0xA0000000); + + // 准备软件 FFT 测试数据 + float sw_in_re[FFT_POINT_NUM]; + float sw_in_im[FFT_POINT_NUM]; + + // 初始化测试波形 + for (int i = 0; i < FFT_POINT_NUM; i++) { + float dc_part = 4000.0f; + float f10_part = 8000.0f * cos(2 * PI * 10.0 * i / FFT_POINT_NUM); + float f200_part = 6000.0f * sin(2 * PI * 200.0 * i / FFT_POINT_NUM); + float f400_part = 3000.0f * sin(2 * PI * 400.0 * i / FFT_POINT_NUM); + + sw_in_re[i] = dc_part + f10_part + f200_part + f400_part; + sw_in_im[i] = 0.0f; + + // 硬件输入需要转为整数存入无缓存内存 + uncached_in_re[i] = (int32_t)sw_in_re[i]; + uncached_in_im[i] = 0; + + // 清理输出内存以防干扰 + uncached_out_re[i] = 0xDEADBEEF; + uncached_out_im[i] = 0xDEADBEEF; + } + + unsigned int tick_start, tick_end; + unsigned int hw_time, sw_time; + + // 硬件加速 FFT 测试 (纯 DMA 搬运) + printf("\n--- Starting Hardware FFT with DMA ---\n"); + tick_start = get_ns(); // 开始计时 + + uint32_t transfer_bytes = FFT_POINT_NUM * 4; // 1024个点 * 4字节 + + // MA 将数据从内存搬运到 FFT 输入外设 + dma_start_transfer(0, ((uint32_t)hw_in_re_arr & 0x1FFFFFFF), phys_fft_in_re, transfer_bytes, 100); + dma_start_transfer(1, ((uint32_t)hw_in_im_arr & 0x1FFFFFFF), phys_fft_in_im, transfer_bytes, 200); + dma_wait_polling(0); + dma_wait_polling(1); + + + // 启动 FFT 并等待计算完成 + fft_start(); + fft_wait(); + + // DMA 将结果从 FFT 输出外设搬回内存 + dma_start_transfer(0, phys_fft_out_re, ((uint32_t)hw_out_re_arr & 0x1FFFFFFF), transfer_bytes, 10); + dma_start_transfer(1, phys_fft_out_im, ((uint32_t)hw_out_im_arr & 0x1FFFFFFF), transfer_bytes, 20); + dma_wait_polling(0); + dma_wait_polling(1); + + + tick_end = get_ns(); // 结束计时 + hw_time = tick_end - tick_start; + + // 纯软件 FFT 测试 + printf("--- Starting Software FFT ---\n"); + tick_start = get_ns(); + + sw_fft(sw_in_re, sw_in_im, FFT_POINT_NUM); + + tick_end = get_ns(); + sw_time = tick_end - tick_start; + + // 打印对比结果 + printf("\n--- Performance Comparison ---\n"); + printf("Timer Clock Freq : %lu Hz\n", CONFREG_CLOCKS_PER_SEC); + printf("Hardware FFT Time: %u ns (%.3f ms)\n", hw_time, (float)hw_time / 1000000.0); + printf("Software FFT Time: %u ns (%.3f ms)\n", sw_time, (float)sw_time / 1000000.0); + + if (hw_time > 0) { + printf("Speedup Ratio : %.2fx\n", (float)sw_time / hw_time); + } + + printf("\n--- Verification (Only showing Bins with energy > 10) ---\n"); + for (int i = 0; i < FFT_POINT_NUM; i++) { + // CPU 通过无缓存指针读取 DMA 搬运回来的结果 + int32_t hw_re = uncached_out_re[i]; + int32_t hw_im = uncached_out_im[i]; + + if (fabs((float)hw_re) > 10 || fabs((float)hw_im) > 10) { + printf("Bin [%4d] Hz: HW(Re:%6d, Im:%6d) | SW(Re:%6d, Im:%6d)\n", + i, + hw_re, hw_im, + (int)sw_in_re[i] / FFT_POINT_NUM, (int)sw_in_im[i] / FFT_POINT_NUM); + } + } + + return 0; +} \ No newline at end of file diff --git a/sdk/software/examples/fft_dma/result.txt b/sdk/software/examples/fft_dma/result.txt new file mode 100644 index 0000000..b36a12b --- /dev/null +++ b/sdk/software/examples/fft_dma/result.txt @@ -0,0 +1,19 @@ +fft_csr init = 0 + +--- Starting Hardware FFT with DMA --- +--- Starting Software FFT --- + +--- Performance Comparison --- +Timer Clock Freq : 50000000 Hz +Hardware FFT Time: 407310 ns (0.407 ms) +Software FFT Time: 274786920 ns (274.787 ms) +Speedup Ratio : 674.64x + +--- Verification (Only showing Bins with energy > 10) --- +Bin [ 0] Hz: HW(Re: 4007, Im: 0) | SW(Re: 4000, Im: 0) +Bin [ 10] Hz: HW(Re: 4006, Im: -1) | SW(Re: 3999, Im: 0) +Bin [ 200] Hz: HW(Re: 2, Im: -2994) | SW(Re: 0, Im: -3000) +Bin [ 400] Hz: HW(Re: -5, Im: -1496) | SW(Re: 0, Im: -1499) +Bin [ 624] Hz: HW(Re: -5, Im: 1497) | SW(Re: 0, Im: 1500) +Bin [ 824] Hz: HW(Re: 3, Im: 2994) | SW(Re: 0, Im: 2999) +Bin [1014] Hz: HW(Re: 4007, Im: 0) | SW(Re: 3999, Im: 0) diff --git a/sdk/software/examples/matmul_test/main.c b/sdk/software/examples/matmul_test/main.c index c6c278e..ee5ae70 100644 --- a/sdk/software/examples/matmul_test/main.c +++ b/sdk/software/examples/matmul_test/main.c @@ -32,7 +32,11 @@ 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 */ +/* 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 */