#include <stdio.h> 
#include <string.h>
#include <math.h>
#include <stdint.h>
#include <common_func.h>
#include <confreg_time.h>

// 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;

#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

#define DMA_BASE          0xbf300000
#define DMA_CTRL          (DMA_BASE + 0x0000)
#define DMA_LEN           (DMA_BASE + 0x0004)
#define DMA_SRC_ADDR      (DMA_BASE + 0x0008)
#define DMA_DST_ADDR      (DMA_BASE + 0x000c)
#define DMA_STATUS        (DMA_BASE + 0x0010)

const float PI = 3.14159265358979323846;

// 加上 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)
{
    unsigned int dma_status = RegRead(DMA_STATUS);
    printf("dma_status init = %x\n", dma_status);

    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 只需要最纯粹的物理地址
    RegWrite(DMA_SRC_ADDR, phys_src_addr);
    RegWrite(DMA_DST_ADDR, phys_dst_addr);
    RegWrite(DMA_LEN, byte_len);
    
    // burst_len = 15(16拍), burst_size = 2(4字节)
    uint32_t burst_len  = 15;   
    uint32_t burst_size = 2;  
    uint32_t ctrl_val = (burst_len << 6) | (burst_size << 3) | 0x01;
    RegWrite(DMA_CTRL, ctrl_val);

    // 等待 DMA 完成
    while ((RegRead(DMA_STATUS) & 0x01) == 0) {
        printf("polling...\n");
    }

    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;
}