






PS Code to test IP
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include <complex.h>
#include <math.h>
#include "xaxidma.h"
#include "xparameters.h"
#include "xtime_l.h"
/* STEPS
* input generation
* dma init
* dma config and polling
* verify outputs
* get execution time
*/
#define N 512
#define LOG2_N 9
void fft512(float complex in[N], float complex out[N]);
void foo()
{
float complex input[N] = {0};
float complex output_ps[N] = {0};
float complex output_pl[N] __attribute__((aligned(32))) = {0};
int i = 0;
/* Input Generation <<< */
for(i = 0; i < N; i++)
{
input[i] = 1;
}
/* >>> */
/* PS Execution <<< */
XTime ps_start, ps_end;
XTime_SetTime(0);
XTime_GetTime(&ps_start);
fft512(input, output_ps);
XTime_GetTime(&ps_end);
/* >>> */
/* PL Execution <<< */
/* DMA Init <<< */
int status;
XAxiDma_Config *dma_config;
XAxiDma dma_instance;
dma_config = XAxiDma_LookupConfig(XPAR_AXI_DMA_0_DEVICE_ID);
status = XAxiDma_CfgInitialize(&dma_instance, dma_config);
if(status != XST_SUCCESS)
{
printf("DMA Config Failed!\n");
return;
}
/* >>> */
/* DMA polling <<< */
XTime pl_start, pl_end;
XTime_GetTime(&pl_start);
Xil_DCacheFlushRange((UINTPTR)input, sizeof(input));
status = XAxiDma_SimpleTransfer(&dma_instance, (UINTPTR)output_pl, sizeof(output_pl), XAXIDMA_DEVICE_TO_DMA);
status = XAxiDma_SimpleTransfer(&dma_instance, (UINTPTR)input, sizeof(input), XAXIDMA_DMA_TO_DEVICE);
// MM2S
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x04) & 0x00000002;
while (status != 0x00000002)
{
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x04) & 0x00000002;
}
// S2MM
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x34) & 0x00000002;
while (status != 0x00000002)
{
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x34) & 0x00000002;
}
Xil_DCacheInvalidateRange((UINTPTR)output_pl, sizeof(output_pl));
XTime_GetTime(&pl_end);
/* >>> */
/* >>> */
/* Verify Outputs <<< */
for(i = 0; i < N; i++)
{
/* printf("%f + %fi\n", crealf(output_pl[i]), cimagf(output_pl[i])); */
if(cabsf(output_ps[i] - output_pl[i]) >= 0.01)
{
printf("Mismatch at (%d)\n", i);
}
}
printf("No Mismatch!\n");
/* >>> */
/* Execution Time <<< */
printf("PS: %f us\n", (float)1.0 * (ps_end - ps_start) / (COUNTS_PER_SECOND / 1000000));
printf("PL: %f us\n", (float)1.0 * (pl_end - pl_start) / (COUNTS_PER_SECOND / 1000000));
/* >>> */
}
int main()
{
init_platform();
foo();
cleanup_platform();
return 0;
}
void fft512(float complex in[N], float complex out[N])
{
// copy input so we can work in-place without touching in[]
memcpy(out, in, N * sizeof(float complex));
// ── 1. Bit-reversal permutation ───────────────────────
for (int i = 0; i < N; i++) {
uint32_t v = (uint32_t)i, r = 0;
for (int b = 0; b < LOG2_N; b++) { r = (r << 1) | (v & 1); v >>= 1; }
if ((int)r > i) {
float complex tmp = out[i]; out[i] = out[r]; out[r] = tmp;
}
}
// ── 2. 9-stage Cooley-Tukey butterfly engine ──────────
for (int s = 1; s <= LOG2_N; s++) {
int half = 1 << (s - 1);
int span = 1 << s;
int step = N >> s;
for (int k = 0; k < N; k += span) {
for (int j = 0; j < half; j++) {
int p = k + j, q = p + half;
float complex W = cexpf(-2.0f * M_PI * j * step / N * I);
float complex t = W * out[q];
out[q] = out[p] - t;
out[p] = out[p] + t;
}
}
}
}

Speedup: ~16.01 times
THIS WAS WITH THE SLOW PS FFT
With the twiddle factors pre computed in PS code:

Speedup: 5.61x
#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include <complex.h>
#include <math.h>
#include "xaxidma.h"
#include "xparameters.h"
#include "xtime_l.h"
#include "tw.h"
/* STEPS
* input generation
* dma init
* dma config and polling
* verify outputs
* get execution time
*/
#define N 512
#define LOG2_N 9
void fft_512(const float complex in[N], float complex out[N]);
void foo()
{
float complex input[N] = {0};
float complex output_ps[N] = {0};
float complex output_pl[N] __attribute__((aligned(32))) = {0};
int i = 0;
/* Input Generation <<< */
for(i = 0; i < N; i++)
{
input[i] = 1;
}
/* >>> */
/* PS Execution <<< */
XTime ps_start, ps_end;
XTime_SetTime(0);
XTime_GetTime(&ps_start);
fft_512(input, output_ps);
XTime_GetTime(&ps_end);
/* >>> */
/* PL Execution <<< */
/* DMA Init <<< */
int status;
XAxiDma_Config *dma_config;
XAxiDma dma_instance;
dma_config = XAxiDma_LookupConfig(XPAR_AXI_DMA_0_DEVICE_ID);
status = XAxiDma_CfgInitialize(&dma_instance, dma_config);
if(status != XST_SUCCESS)
{
printf("DMA Config Failed!\n");
return;
}
/* >>> */
/* DMA polling <<< */
XTime pl_start, pl_end;
XTime_GetTime(&pl_start);
Xil_DCacheFlushRange((UINTPTR)input, sizeof(input));
status = XAxiDma_SimpleTransfer(&dma_instance, (UINTPTR)output_pl, sizeof(output_pl), XAXIDMA_DEVICE_TO_DMA);
status = XAxiDma_SimpleTransfer(&dma_instance, (UINTPTR)input, sizeof(input), XAXIDMA_DMA_TO_DEVICE);
// MM2S
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x04) & 0x00000002;
while (status != 0x00000002)
{
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x04) & 0x00000002;
}
// S2MM
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x34) & 0x00000002;
while (status != 0x00000002)
{
status = XAxiDma_ReadReg(XPAR_AXI_DMA_0_BASEADDR, 0x34) & 0x00000002;
}
Xil_DCacheInvalidateRange((UINTPTR)output_pl, sizeof(output_pl));
XTime_GetTime(&pl_end);
/* >>> */
/* >>> */
/* Verify Outputs <<< */
for(i = 0; i < N; i++)
{
/* printf("%f + %fi\n", crealf(output_pl[i]), cimagf(output_pl[i])); */
if(cabsf(output_ps[i] - output_pl[i]) >= 0.01)
{
printf("Mismatch at (%d)\n", i);
}
}
printf("No Mismatch!\n");
/* >>> */
/* Execution Time <<< */
printf("PS: %f us\n", (float)1.0 * (ps_end - ps_start) / (COUNTS_PER_SECOND / 1000000));
printf("PL: %f us\n", (float)1.0 * (pl_end - pl_start) / (COUNTS_PER_SECOND / 1000000));
/* >>> */
}
int main()
{
init_platform();
foo();
cleanup_platform();
return 0;
}
void fft_512(const float complex in[N], float complex out[N]) {
// ----------------------------------
// Bit-reversal copy (input → output)
// ----------------------------------
for (int i = 0; i < N; i++) {
out[br_lut[i]] = in[i];
}
// ----------------------------------
// FFT (in-place on out[])
// ----------------------------------
for (int s = 1; s <= LOG2_N; s++) {
int m = 1 << s;
int m2 = m >> 1;
int step = N >> s; // twiddle stride
for (int k = 0; k < N; k += m) {
for (int j = 0; j < m2; j++) {
int idx = j * step;
float complex w =
TWIDDLE_ROM[idx].real +
TWIDDLE_ROM[idx].imag * I;
float complex t = w * out[k + j + m2];
float complex u = out[k + j];
out[k + j] = u + t;
out[k + j + m2] = u - t;
}
}
}
}