//
|
//
|
// Filename: fft_tb.cpp
|
// Filename: fft_tb.cpp
|
//
|
//
|
// Project: A Doubletime Pipelined FFT
|
// Project: A Doubletime Pipelined FFT
|
//
|
//
|
// Purpose: A test-bench for the main program, fftmain.v, of the double
|
// Purpose: A test-bench for the main program, fftmain.v, of the double
|
// clocked FFT. This file may be run autonomously (when
|
// clocked FFT. This file may be run autonomously (when
|
// fully functional). If so, the last line output will either
|
// fully functional). If so, the last line output will either read
|
// read "SUCCESS" on success, or some other failure message
|
// "SUCCESS" on success, or some other failure message otherwise.
|
// otherwise.
|
|
//
|
//
|
// This file depends upon verilator to both compile, run, and
|
// This file depends upon verilator to both compile, run, and therefore
|
// therefore test fftmain.v
|
// test fftmain.v
|
//
|
//
|
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
// Copyright (C) 2015,2018, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// modify it under the terms of the GNU General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
//
|
//
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// This program is distributed in the hope that it will be useful, but WITHOUT
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
// for more details.
|
// for more details.
|
//
|
//
|
// You should have received a copy of the GNU General Public License along
|
// You should have received a copy of the GNU General Public License along
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// with this program. (It's in the $(ROOT)/doc directory, run make with no
|
// target there if the PDF file isn't present.) If not, see
|
// target there if the PDF file isn't present.) If not, see
|
// <http://www.gnu.org/licenses/> for a copy.
|
// <http://www.gnu.org/licenses/> for a copy.
|
//
|
//
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// License: GPL, v3, as defined and found on www.gnu.org,
|
// http://www.gnu.org/licenses/gpl.html
|
// http://www.gnu.org/licenses/gpl.html
|
//
|
//
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
#include <stdio.h>
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
#include <math.h>
|
#include <math.h>
|
#include <fftw3.h>
|
#include <fftw3.h>
|
|
|
#include "verilated.h"
|
#include "verilated.h"
|
|
#include "verilated_vcd_c.h"
|
#include "Vfftmain.h"
|
#include "Vfftmain.h"
|
#include "twoc.h"
|
#include "twoc.h"
|
|
|
#include "fftsize.h"
|
#include "fftsize.h"
|
|
|
|
|
#ifdef NEW_VERILATOR
|
#ifdef NEW_VERILATOR
|
#define VVAR(A) fftmain__DOT_ ## A
|
#define VVAR(A) fftmain__DOT_ ## A
|
#else
|
#else
|
#define VVAR(A) v__DOT_ ## A
|
#define VVAR(A) v__DOT_ ## A
|
#endif
|
#endif
|
|
|
|
#ifdef DBLCLKFFT
|
#define revstage_iaddr VVAR(_revstage__DOT__iaddr)
|
#define revstage_iaddr VVAR(_revstage__DOT__iaddr)
|
|
#else
|
|
#define revstage_iaddr VVAR(_revstage__DOT__wraddr)
|
|
#endif
|
#define br_sync VVAR(_br_sync)
|
#define br_sync VVAR(_br_sync)
|
#define br_started VVAR(_r_br_started)
|
#define br_started VVAR(_r_br_started)
|
#define w_s2048 VVAR(_w_s2048)
|
#define w_s2048 VVAR(_w_s2048)
|
#define w_s1024 VVAR(_w_s1024)
|
#define w_s1024 VVAR(_w_s1024)
|
#define w_s512 VVAR(_w_s512)
|
#define w_s512 VVAR(_w_s512)
|
#define w_s256 VVAR(_w_s256)
|
#define w_s256 VVAR(_w_s256)
|
#define w_s128 VVAR(_w_s128)
|
#define w_s128 VVAR(_w_s128)
|
#define w_s64 VVAR(_w_s64)
|
#define w_s64 VVAR(_w_s64)
|
#define w_s32 VVAR(_w_s32)
|
#define w_s32 VVAR(_w_s32)
|
#define w_s16 VVAR(_w_s16)
|
#define w_s16 VVAR(_w_s16)
|
#define w_s8 VVAR(_w_s8)
|
#define w_s8 VVAR(_w_s8)
|
#define w_s4 VVAR(_w_s4)
|
#define w_s4 VVAR(_w_s4)
|
|
|
|
|
#define IWIDTH FFT_IWIDTH
|
#define IWIDTH FFT_IWIDTH
|
#define OWIDTH FFT_OWIDTH
|
#define OWIDTH FFT_OWIDTH
|
#define LGWIDTH FFT_LGWIDTH
|
#define LGWIDTH FFT_LGWIDTH
|
|
|
#if (IWIDTH > 16)
|
#if (IWIDTH > 16)
|
typedef unsigned long ITYP;
|
typedef unsigned long ITYP;
|
#else
|
#else
|
typedef unsigned int ITYP;
|
typedef unsigned int ITYP;
|
#endif
|
#endif
|
|
|
#if (OWIDTH > 16)
|
#if (OWIDTH > 16)
|
typedef unsigned long OTYP;
|
typedef unsigned long OTYP;
|
#else
|
#else
|
typedef unsigned int OTYP;
|
typedef unsigned int OTYP;
|
#endif
|
#endif
|
|
|
#define NFTLOG 16
|
#define NFTLOG 16
|
#define FFTLEN (1<<LGWIDTH)
|
#define FFTLEN (1<<LGWIDTH)
|
|
|
#ifdef FFT_SKIPS_BIT_REVERSE
|
#ifdef FFT_SKIPS_BIT_REVERSE
|
#define APPLY_BITREVERSE_LOCALLY
|
#define APPLY_BITREVERSE_LOCALLY
|
#endif
|
#endif
|
|
|
unsigned long bitrev(const int nbits, const unsigned long vl) {
|
unsigned long bitrev(const int nbits, const unsigned long vl) {
|
unsigned long r = 0;
|
unsigned long r = 0;
|
unsigned long val = vl;
|
unsigned long val = vl;
|
|
|
for(int k=0; k<nbits; k++) {
|
for(int k=0; k<nbits; k++) {
|
r<<= 1;
|
r<<= 1;
|
r |= (val & 1);
|
r |= (val & 1);
|
val >>= 1;
|
val >>= 1;
|
}
|
}
|
|
|
return r;
|
return r;
|
}
|
}
|
|
|
class FFT_TB {
|
class FFT_TB {
|
public:
|
public:
|
Vfftmain *m_fft;
|
Vfftmain *m_fft;
|
OTYP m_data[FFTLEN];
|
OTYP m_data[FFTLEN];
|
ITYP m_log[NFTLOG*FFTLEN];
|
ITYP m_log[NFTLOG*FFTLEN];
|
int m_iaddr, m_oaddr, m_ntest, m_logbase;
|
int m_iaddr, m_oaddr, m_ntest, m_logbase;
|
FILE *m_dumpfp;
|
FILE *m_dumpfp;
|
fftw_plan m_plan;
|
fftw_plan m_plan;
|
double *m_fft_buf;
|
double *m_fft_buf;
|
bool m_syncd;
|
bool m_syncd;
|
unsigned long m_tickcount;
|
unsigned long m_tickcount;
|
|
VerilatedVcdC* m_trace;
|
|
|
FFT_TB(void) {
|
FFT_TB(void) {
|
m_fft = new Vfftmain;
|
m_fft = new Vfftmain;
|
|
Verilated::traceEverOn(true);
|
m_iaddr = m_oaddr = 0;
|
m_iaddr = m_oaddr = 0;
|
m_dumpfp = NULL;
|
m_dumpfp = NULL;
|
|
|
m_fft_buf = (double *)fftw_malloc(sizeof(fftw_complex)*(FFTLEN));
|
m_fft_buf = (double *)fftw_malloc(sizeof(fftw_complex)*(FFTLEN));
|
m_plan = fftw_plan_dft_1d(FFTLEN, (fftw_complex *)m_fft_buf,
|
m_plan = fftw_plan_dft_1d(FFTLEN, (fftw_complex *)m_fft_buf,
|
(fftw_complex *)m_fft_buf,
|
(fftw_complex *)m_fft_buf,
|
FFTW_FORWARD, FFTW_MEASURE);
|
FFTW_FORWARD, FFTW_MEASURE);
|
m_syncd = false;
|
m_syncd = false;
|
m_ntest = 0;
|
m_ntest = 0;
|
|
}
|
|
|
m_tickcount = 0l;
|
~FFT_TB(void) {
|
|
closetrace();
|
|
delete m_fft;
|
|
m_fft = NULL;
|
|
}
|
|
|
|
virtual void opentrace(const char *vcdname) {
|
|
if (!m_trace) {
|
|
m_trace = new VerilatedVcdC;
|
|
m_fft->trace(m_trace, 99);
|
|
m_trace->open(vcdname);
|
|
}
|
|
}
|
|
|
|
virtual void closetrace(void) {
|
|
if (m_trace) {
|
|
m_trace->close();
|
|
delete m_trace;
|
|
m_trace = NULL;
|
|
}
|
}
|
}
|
|
|
void tick(void) {
|
void tick(void) {
|
if ((!m_fft->i_ce)||(m_fft->i_rst))
|
m_tickcount++;
|
|
if (m_fft->i_reset)
|
printf("TICK(%s,%s)\n",
|
printf("TICK(%s,%s)\n",
|
(m_fft->i_rst)?"RST":" ",
|
(m_fft->i_reset)?"RST":" ",
|
(m_fft->i_ce)?"CE":" ");
|
(m_fft->i_ce)?"CE":" ");
|
|
|
m_fft->i_clk = 0;
|
m_fft->i_clk = 0;
|
m_fft->eval();
|
m_fft->eval();
|
|
if (m_trace)
|
|
m_trace->dump((vluint64_t)(10*m_tickcount-2));
|
m_fft->i_clk = 1;
|
m_fft->i_clk = 1;
|
m_fft->eval();
|
m_fft->eval();
|
|
if (m_trace)
|
|
m_trace->dump((vluint64_t)(10*m_tickcount));
|
|
m_fft->i_clk = 0;
|
|
m_fft->eval();
|
|
if (m_trace) {
|
|
m_trace->dump((vluint64_t)(10*m_tickcount+5));
|
|
m_trace->flush();
|
|
}
|
|
}
|
|
|
m_tickcount++;
|
void cetick(void) {
|
|
int ce = m_fft->i_ce, nkce;
|
|
tick();
|
|
|
/*
|
nkce = (rand()&1);
|
int nrpt = (rand()&0x01f) + 1;
|
#ifdef FFT_CKPCE
|
m_fft->i_ce = 0;
|
nkce += FFT_CKPCE;
|
for(int i=0; i<nrpt; i++) {
|
#endif
|
m_fft->i_clk = 0;
|
if ((ce)&&(nkce>0)) {
|
m_fft->eval();
|
m_fft->i_ce = 0;
|
m_fft->i_clk = 1;
|
for(int kce=1; kce < nkce; kce++)
|
m_fft->eval();
|
tick();
|
}
|
}
|
*/
|
|
|
m_fft->i_ce = ce;
|
}
|
}
|
|
|
void reset(void) {
|
void reset(void) {
|
m_fft->i_ce = 0;
|
m_fft->i_ce = 0;
|
m_fft->i_rst = 1;
|
m_fft->i_reset = 1;
|
tick();
|
tick();
|
m_fft->i_rst = 0;
|
m_fft->i_reset = 0;
|
tick();
|
tick();
|
|
|
m_iaddr = m_oaddr = m_logbase = 0;
|
m_iaddr = m_oaddr = m_logbase = 0;
|
m_syncd = false;
|
m_syncd = false;
|
m_tickcount = 0l;
|
m_tickcount = 0l;
|
}
|
}
|
|
|
long twos_complement(const long val, const int bits) {
|
long twos_complement(const long val, const int bits) {
|
return sbits(val, bits);
|
return sbits(val, bits);
|
}
|
}
|
|
|
void checkresults(void) {
|
void checkresults(void) {
|
double *dp, *sp; // Complex array
|
double *dp, *sp; // Complex array
|
double vout[FFTLEN*2];
|
double vout[FFTLEN*2];
|
double isq=0.0, osq = 0.0;
|
double isq=0.0, osq = 0.0;
|
ITYP *lp;
|
ITYP *lp;
|
|
|
// Fill up our test array from the log array
|
// Fill up our test array from the log array
|
printf("%3d : CHECK: %8d %5x m_log[-%x=%x]\n", m_ntest, m_iaddr, m_iaddr,
|
printf("%3d : CHECK: %8d %5x m_log[-%x=%x]\n", m_ntest, m_iaddr, m_iaddr,
|
m_logbase, (m_iaddr-m_logbase)&((NFTLOG*FFTLEN-1)&(-FFTLEN)));
|
m_logbase, (m_iaddr-m_logbase)&((NFTLOG*FFTLEN-1)&(-FFTLEN)));
|
|
|
// Convert our logged data into doubles, in an FFT buffer
|
// Convert our logged data into doubles, in an FFT buffer
|
dp = m_fft_buf; lp = &m_log[(m_iaddr-m_logbase)&((NFTLOG*FFTLEN-1)&(-FFTLEN))];
|
dp = m_fft_buf; lp = &m_log[(m_iaddr-m_logbase)&((NFTLOG*FFTLEN-1)&(-FFTLEN))];
|
for(int i=0; i<FFTLEN; i++) {
|
for(int i=0; i<FFTLEN; i++) {
|
ITYP tv = *lp++;
|
ITYP tv = *lp++;
|
|
|
dp[0] = sbits((long)tv >> IWIDTH, IWIDTH);
|
dp[0] = sbits((long)tv >> IWIDTH, IWIDTH);
|
dp[1] = sbits((long)tv, IWIDTH);
|
dp[1] = sbits((long)tv, IWIDTH);
|
|
|
// printf("IN[%4d = %4x] = %9.1f %9.1f\n",
|
// printf("IN[%4d = %4x] = %9.1f %9.1f\n",
|
// i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
|
// i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
|
// i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
|
// i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
|
// dp[0], dp[1]);
|
// dp[0], dp[1]);
|
dp += 2;
|
dp += 2;
|
}
|
}
|
|
|
// Let's measure ... are we the zero vector? If not, how close?
|
// Let's measure ... are we the zero vector? If not, how close?
|
dp = m_fft_buf;
|
dp = m_fft_buf;
|
for(int i=0; i<FFTLEN*2; i++) {
|
for(int i=0; i<FFTLEN*2; i++) {
|
isq += (*dp) * (*dp); dp++;
|
isq += (*dp) * (*dp); dp++;
|
}
|
}
|
|
|
fftw_execute(m_plan);
|
fftw_execute(m_plan);
|
|
|
// Let's load up the output we received into double valued
|
// Let's load up the output we received into double valued
|
// array vout
|
// array vout
|
dp = vout;
|
dp = vout;
|
for(int i=0; i<FFTLEN; i++) {
|
for(int i=0; i<FFTLEN; i++) {
|
*dp = rdata(i);
|
*dp = rdata(i);
|
osq += (*dp) * (*dp); dp++;
|
osq += (*dp) * (*dp); dp++;
|
*dp = idata(i);
|
*dp = idata(i);
|
osq += (*dp) * (*dp); dp++;
|
osq += (*dp) * (*dp); dp++;
|
}
|
}
|
|
|
|
|
// Let's figure out if there's a scale factor difference ...
|
// Let's figure out if there's a scale factor difference ...
|
double scale = 0.0, wt = 0.0;
|
double scale = 0.0, wt = 0.0;
|
sp = m_fft_buf; dp = vout;
|
sp = m_fft_buf; dp = vout;
|
for(int i=0; i<FFTLEN*2; i++) {
|
for(int i=0; i<FFTLEN*2; i++) {
|
scale += (*sp) * (*dp++);
|
scale += (*sp) * (*dp++);
|
wt += (*sp) * (*sp); sp++;
|
wt += (*sp) * (*sp); sp++;
|
} scale = scale / wt;
|
} scale = scale / wt;
|
|
|
if (fabs(scale) <= 1./4./FFTLEN)
|
if (fabs(scale) <= 1./4./FFTLEN)
|
scale = 2./(FFTLEN);
|
scale = 2./(FFTLEN);
|
else if (wt == 0.0) scale = 1.0;
|
else if (wt == 0.0) scale = 1.0;
|
|
|
double xisq = 0.0;
|
double xisq = 0.0;
|
sp = m_fft_buf; dp = vout;
|
sp = m_fft_buf; dp = vout;
|
|
|
if ((true)&&(m_dumpfp)) {
|
if ((true)&&(m_dumpfp)) {
|
double tmp[FFTLEN*2], nscl;
|
double tmp[FFTLEN*2], nscl;
|
|
|
if (fabs(scale) < 1e-4)
|
if (fabs(scale) < 1e-4)
|
nscl = 1.0;
|
nscl = 1.0;
|
else
|
else
|
nscl = scale;
|
nscl = scale;
|
for(int i=0; i<FFTLEN*2; i++)
|
for(int i=0; i<FFTLEN*2; i++)
|
tmp[i] = m_fft_buf[i] * nscl;
|
tmp[i] = m_fft_buf[i] * nscl;
|
fwrite(tmp, sizeof(double), FFTLEN*2, m_dumpfp);
|
fwrite(tmp, sizeof(double), FFTLEN*2, m_dumpfp);
|
}
|
}
|
|
|
for(int i=0; i<FFTLEN*2; i++) {
|
for(int i=0; i<FFTLEN*2; i++) {
|
double vl = (*sp++) * scale - (*dp++);
|
double vl = (*sp++) * scale - (*dp++);
|
xisq += vl * vl;
|
xisq += vl * vl;
|
}
|
}
|
|
|
printf("%3d : SCALE = %12.6f, WT = %18.1f, ISQ = %15.1f, ",
|
printf("%3d : SCALE = %12.6f, WT = %18.1f, ISQ = %15.1f, ",
|
m_ntest, scale, wt, isq);
|
m_ntest, scale, wt, isq);
|
printf("OSQ = %18.1f, ", osq);
|
printf("OSQ = %18.1f, ", osq);
|
printf("XISQ = %18.1f\n", xisq);
|
printf("XISQ = %18.1f, sqrt = %9.2f\n", xisq, sqrt(xisq));
|
if (xisq > 1.4 * FFTLEN/2) {
|
if (xisq > 1.4 * FFTLEN/2) {
|
printf("TEST FAIL!! Result is out of bounds from ");
|
printf("TEST FAIL!! Result is out of bounds from ");
|
printf("expected result with FFTW3.\n");
|
printf("expected result with FFTW3.\n");
|
// exit(-2);
|
// exit(EXIT_FAILURE);
|
}
|
}
|
m_ntest++;
|
m_ntest++;
|
}
|
}
|
|
|
|
#ifdef DBLCLKFFT
|
bool test(ITYP lft, ITYP rht) {
|
bool test(ITYP lft, ITYP rht) {
|
m_fft->i_ce = 1;
|
m_fft->i_ce = 1;
|
m_fft->i_rst = 0;
|
m_fft->i_reset = 0;
|
m_fft->i_left = lft;
|
m_fft->i_left = lft;
|
m_fft->i_right = rht;
|
m_fft->i_right = rht;
|
|
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = lft;
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = lft;
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = rht;
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = rht;
|
|
|
tick();
|
cetick();
|
|
|
if (m_fft->o_sync) {
|
if (m_fft->o_sync) {
|
if (!m_syncd) {
|
if (!m_syncd) {
|
m_syncd = true;
|
m_syncd = true;
|
printf("ORIGINAL SYNC AT 0x%lx, m_oaddr set to 0x%x\n", m_tickcount, m_oaddr);
|
printf("ORIGINAL SYNC AT 0x%lx, m_oaddr set to 0x%x\n", m_tickcount, m_oaddr);
|
m_logbase = m_iaddr;
|
m_logbase = m_iaddr;
|
} else printf("RESYNC AT %lx\n", m_tickcount);
|
} else printf("RESYNC AT %lx\n", m_tickcount);
|
m_oaddr &= (-1<<LGWIDTH);
|
m_oaddr &= (-1<<LGWIDTH);
|
} else m_oaddr += 2;
|
} else m_oaddr += 2;
|
|
|
printf("%8x,%5d: %08x,%08x -> %011lx,%011lx\t",
|
printf("%8x,%5d: %08x,%08x -> %011lx,%011lx\t",
|
m_iaddr, m_oaddr,
|
m_iaddr, m_oaddr,
|
lft, rht, m_fft->o_left, m_fft->o_right);
|
lft, rht, m_fft->o_left, m_fft->o_right);
|
|
|
#ifndef APPLY_BITREVERSE_LOCALLY
|
#ifndef APPLY_BITREVERSE_LOCALLY
|
printf(" [%3x]%s", m_fft->revstage_iaddr,
|
printf(" [%3x]%s", m_fft->revstage_iaddr,
|
(m_fft->br_sync)?"S"
|
(m_fft->br_sync)?"S"
|
:((m_fft->br_started)?".":"x"));
|
:((m_fft->br_started)?".":"x"));
|
#endif
|
#endif
|
|
|
printf(" ");
|
printf(" ");
|
#if (FFT_SIZE>=2048)
|
#if (FFT_SIZE>=2048)
|
printf("%s", (m_fft->w_s2048)?"S":"-");
|
printf("%s", (m_fft->w_s2048)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>1024)
|
#if (FFT_SIZE>1024)
|
printf("%s", (m_fft->w_s1024)?"S":"-");
|
printf("%s", (m_fft->w_s1024)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>512)
|
#if (FFT_SIZE>512)
|
printf("%s", (m_fft->w_s512)?"S":"-");
|
printf("%s", (m_fft->w_s512)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>256)
|
#if (FFT_SIZE>256)
|
printf("%s", (m_fft->w_s256)?"S":"-");
|
printf("%s", (m_fft->w_s256)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>128)
|
#if (FFT_SIZE>128)
|
printf("%s", (m_fft->w_s128)?"S":"-");
|
printf("%s", (m_fft->w_s128)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>64)
|
#if (FFT_SIZE>64)
|
printf("%s", (m_fft->w_s64)?"S":"-");
|
printf("%s", (m_fft->w_s64)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>32)
|
#if (FFT_SIZE>32)
|
printf("%s", (m_fft->w_s32)?"S":"-");
|
printf("%s", (m_fft->w_s32)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>16)
|
#if (FFT_SIZE>16)
|
printf("%s", (m_fft->w_s16)?"S":"-");
|
printf("%s", (m_fft->w_s16)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>8)
|
#if (FFT_SIZE>8)
|
printf("%s", (m_fft->w_s8)?"S":"-");
|
printf("%s", (m_fft->w_s8)?"S":"-");
|
#endif
|
#endif
|
#if (FFT_SIZE>4)
|
#if (FFT_SIZE>4)
|
printf("%s", (m_fft->w_s4)?"S":"-");
|
printf("%s", (m_fft->w_s4)?"S":"-");
|
#endif
|
#endif
|
|
|
printf(" %s%s\n",
|
printf(" %s%s\n",
|
(m_fft->o_sync)?"\t(SYNC!)":"",
|
(m_fft->o_sync)?"\t(SYNC!)":"",
|
(m_fft->o_left | m_fft->o_right)?" (NZ)":"");
|
(m_fft->o_left | m_fft->o_right)?" (NZ)":"");
|
|
|
m_data[(m_oaddr )&(FFTLEN-1)] = m_fft->o_left;
|
m_data[(m_oaddr )&(FFTLEN-1)] = m_fft->o_left;
|
m_data[(m_oaddr+1)&(FFTLEN-1)] = m_fft->o_right;
|
m_data[(m_oaddr+1)&(FFTLEN-1)] = m_fft->o_right;
|
|
|
if ((m_syncd)&&((m_oaddr&(FFTLEN-1)) == FFTLEN-2)) {
|
if ((m_syncd)&&((m_oaddr&(FFTLEN-1)) == FFTLEN-2)) {
|
dumpwrite();
|
dumpwrite();
|
checkresults();
|
checkresults();
|
}
|
}
|
|
|
return (m_fft->o_sync);
|
return (m_fft->o_sync);
|
}
|
}
|
|
#else
|
|
bool test(ITYP data) {
|
|
m_fft->i_ce = 1;
|
|
m_fft->i_reset = 0;
|
|
m_fft->i_sample = data;
|
|
|
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = data;
|
|
|
|
cetick();
|
|
|
|
if (m_fft->o_sync) {
|
|
if (!m_syncd) {
|
|
m_syncd = true;
|
|
printf("ORIGINAL SYNC AT 0x%lx, m_oaddr set to 0x%x\n", m_tickcount, m_oaddr);
|
|
m_logbase = m_iaddr;
|
|
} else printf("RESYNC AT %lx\n", m_tickcount);
|
|
m_oaddr &= (-1<<LGWIDTH);
|
|
} else m_oaddr += 1;
|
|
|
|
printf("%8x,%5d: %08x -> %011lx\t",
|
|
m_iaddr, m_oaddr, data, m_fft->o_result);
|
|
|
|
#ifndef APPLY_BITREVERSE_LOCALLY
|
|
printf(" [%3x]%s", m_fft->revstage_iaddr,
|
|
(m_fft->br_sync)?"S"
|
|
:((m_fft->br_started)?".":"x"));
|
|
#endif
|
|
|
|
printf(" ");
|
|
#if (FFT_SIZE>=2048)
|
|
printf("%s", (m_fft->w_s2048)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>1024)
|
|
printf("%s", (m_fft->w_s1024)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>512)
|
|
printf("%s", (m_fft->w_s512)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>256)
|
|
printf("%s", (m_fft->w_s256)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>128)
|
|
printf("%s", (m_fft->w_s128)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>64)
|
|
printf("%s", (m_fft->w_s64)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>32)
|
|
printf("%s", (m_fft->w_s32)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>16)
|
|
printf("%s", (m_fft->w_s16)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>8)
|
|
printf("%s", (m_fft->w_s8)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>4)
|
|
printf("%s", (m_fft->w_s4)?"S":"-");
|
|
#endif
|
|
|
|
printf(" %s%s\n",
|
|
(m_fft->o_sync)?"\t(SYNC!)":"",
|
|
(m_fft->o_result)?" (NZ)":"");
|
|
|
|
m_data[(m_oaddr )&(FFTLEN-1)] = m_fft->o_result;
|
|
|
|
if ((m_syncd)&&((m_oaddr&(FFTLEN-1)) == FFTLEN-1)) {
|
|
dumpwrite();
|
|
checkresults();
|
|
}
|
|
|
|
return (m_fft->o_sync);
|
|
}
|
|
#endif
|
|
|
bool test(double lft_r, double lft_i, double rht_r, double rht_i) {
|
bool test(double lft_r, double lft_i, double rht_r, double rht_i) {
|
ITYP ilft, irht, ilft_r, ilft_i, irht_r, irht_i;
|
ITYP ilft, irht, ilft_r, ilft_i, irht_r, irht_i;
|
|
|
ilft_r = (ITYP)(lft_r) & ((1<<IWIDTH)-1);
|
ilft_r = (ITYP)(lft_r) & ((1<<IWIDTH)-1);
|
ilft_i = (ITYP)(lft_i) & ((1<<IWIDTH)-1);
|
ilft_i = (ITYP)(lft_i) & ((1<<IWIDTH)-1);
|
irht_r = (ITYP)(rht_r) & ((1<<IWIDTH)-1);
|
irht_r = (ITYP)(rht_r) & ((1<<IWIDTH)-1);
|
irht_i = (ITYP)(rht_i) & ((1<<IWIDTH)-1);
|
irht_i = (ITYP)(rht_i) & ((1<<IWIDTH)-1);
|
|
|
ilft = (ilft_r << IWIDTH) | ilft_i;
|
ilft = (ilft_r << IWIDTH) | ilft_i;
|
irht = (irht_r << IWIDTH) | irht_i;
|
irht = (irht_r << IWIDTH) | irht_i;
|
|
|
|
#ifdef DBLCLKFFT
|
return test(ilft, irht);
|
return test(ilft, irht);
|
|
#else
|
|
test(ilft);
|
|
return test(irht);
|
|
#endif
|
}
|
}
|
|
|
double rdata(int addr) {
|
double rdata(int addr) {
|
int index = addr & (FFTLEN-1);
|
int index = addr & (FFTLEN-1);
|
|
|
#ifdef APPLY_BITREVERSE_LOCALLY
|
#ifdef APPLY_BITREVERSE_LOCALLY
|
index = bitrev(LGWIDTH, index);
|
index = bitrev(LGWIDTH, index);
|
#endif
|
#endif
|
return (double)sbits(m_data[index]>>OWIDTH, OWIDTH);
|
return (double)sbits(m_data[index]>>OWIDTH, OWIDTH);
|
}
|
}
|
|
|
double idata(int addr) {
|
double idata(int addr) {
|
int index = addr & (FFTLEN-1);
|
int index = addr & (FFTLEN-1);
|
|
|
#ifdef APPLY_BITREVERSE_LOCALLY
|
#ifdef APPLY_BITREVERSE_LOCALLY
|
index = bitrev(LGWIDTH, index);
|
index = bitrev(LGWIDTH, index);
|
#endif
|
#endif
|
return (double)sbits(m_data[index], OWIDTH);
|
return (double)sbits(m_data[index], OWIDTH);
|
}
|
}
|
|
|
void dump(FILE *fp) {
|
void dump(FILE *fp) {
|
m_dumpfp = fp;
|
m_dumpfp = fp;
|
}
|
}
|
|
|
void dumpwrite(void) {
|
void dumpwrite(void) {
|
if (!m_dumpfp)
|
if (!m_dumpfp)
|
return;
|
return;
|
|
|
double *buf;
|
double *buf;
|
|
|
buf = new double[FFTLEN * 2];
|
buf = new double[FFTLEN * 2];
|
for(int i=0; i<FFTLEN; i++) {
|
for(int i=0; i<FFTLEN; i++) {
|
buf[i*2] = rdata(i);
|
buf[i*2] = rdata(i);
|
buf[i*2+1] = idata(i);
|
buf[i*2+1] = idata(i);
|
}
|
}
|
|
|
fwrite(buf, sizeof(double), FFTLEN*2, m_dumpfp);
|
fwrite(buf, sizeof(double), FFTLEN*2, m_dumpfp);
|
delete[] buf;
|
delete[] buf;
|
}
|
}
|
};
|
};
|
|
|
|
|
int main(int argc, char **argv, char **envp) {
|
int main(int argc, char **argv, char **envp) {
|
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
FFT_TB *fft = new FFT_TB;
|
FFT_TB *fft = new FFT_TB;
|
FILE *fpout;
|
FILE *fpout;
|
|
|
fpout = fopen("fft_tb.dbl", "w");
|
fpout = fopen("fft_tb.dbl", "w");
|
if (NULL == fpout) {
|
if (NULL == fpout) {
|
fprintf(stderr, "Cannot write output file, fft_tb.dbl\n");
|
fprintf(stderr, "Cannot write output file, fft_tb.dbl\n");
|
exit(-1);
|
exit(-1);
|
}
|
}
|
|
|
|
fft->opentrace("fft.vcd");
|
fft->reset();
|
fft->reset();
|
|
|
{
|
{
|
int ftlen = FFTLEN;
|
int ftlen = FFTLEN;
|
fwrite(&ftlen, 1, sizeof(int), fpout);
|
fwrite(&ftlen, 1, sizeof(int), fpout);
|
}
|
}
|
fft->dump(fpout);
|
fft->dump(fpout);
|
|
|
// 1.
|
// 1.
|
fft->test(0.0, 0.0, 32767.0, 0.0);
|
double maxv = ((1l<<(IWIDTH-1))-1l);
|
|
fft->test(0.0, 0.0, maxv, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 2. Try placing a pulse at the very end location
|
// 2. Try placing a pulse at the very end location
|
for(int k=0; k<FFTLEN/2; k++) {
|
for(int k=0; k<FFTLEN/2; k++) {
|
double cl, cr, sl, sr, W;
|
double cl, cr, sl, sr, W;
|
W = - 2.0 * M_PI / FFTLEN * (1);
|
W = - 2.0 * M_PI / FFTLEN * (1);
|
cl = cos(W * (2*k )) * 16383.0;
|
cl = cos(W * (2*k )) * (double)((1l<<(IWIDTH-2))-1l);
|
sl = sin(W * (2*k )) * 16383.0;
|
sl = sin(W * (2*k )) * (double)((1l<<(IWIDTH-2))-1l);
|
cr = cos(W * (2*k+1)) * 16383.0;
|
cr = cos(W * (2*k+1)) * (double)((1l<<(IWIDTH-2))-1l);
|
sr = sin(W * (2*k+1)) * 16383.0;
|
sr = sin(W * (2*k+1)) * (double)((1l<<(IWIDTH-2))-1l);
|
fft->test(cl, sl, cr, sr);
|
fft->test(cl, sl, cr, sr);
|
}
|
}
|
|
|
// 2.
|
// 2.
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 3.
|
// 3.
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(32767.0, 0.0, 0.0, 0.0);
|
fft->test(maxv, 0.0, 0.0, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 4.
|
// 4.
|
for(int k=0; k<8; k++)
|
for(int k=0; k<8; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=8; k<FFTLEN/2; k++)
|
for(int k=8; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 5.
|
// 5.
|
if (FFTLEN/2 >= 16) {
|
if (FFTLEN/2 >= 16) {
|
for(int k=0; k<16; k++)
|
for(int k=0; k<16; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=16; k<FFTLEN/2; k++)
|
for(int k=16; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
}
|
}
|
|
|
// 6.
|
// 6.
|
if (FFTLEN/2 >= 32) {
|
if (FFTLEN/2 >= 32) {
|
for(int k=0; k<32; k++)
|
for(int k=0; k<32; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=32; k<FFTLEN/2; k++)
|
for(int k=32; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
}
|
}
|
|
|
// 7.
|
// 7.
|
if (FFTLEN/2 >= 64) {
|
if (FFTLEN/2 >= 64) {
|
for(int k=0; k<64; k++)
|
for(int k=0; k<64; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=64; k<FFTLEN/2; k++)
|
for(int k=64; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
}
|
}
|
|
|
if (FFTLEN/2 >= 128) {
|
if (FFTLEN/2 >= 128) {
|
for(int k=0; k<128; k++)
|
for(int k=0; k<128; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=128; k<FFTLEN/2; k++)
|
for(int k=128; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
}
|
}
|
|
|
if (FFTLEN/2 >= 256) {
|
if (FFTLEN/2 >= 256) {
|
for(int k=0; k<256; k++)
|
for(int k=0; k<256; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=256; k<FFTLEN/2; k++)
|
for(int k=256; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
}
|
}
|
|
|
if (FFTLEN/2 >= 512) {
|
if (FFTLEN/2 >= 512) {
|
for(int k=0; k<256+128; k++)
|
for(int k=0; k<256+128; k++)
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(maxv, 0.0, maxv, 0.0);
|
for(int k=256+128; k<FFTLEN/2; k++)
|
for(int k=256+128; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
}
|
}
|
|
|
/*
|
/*
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
*/
|
*/
|
|
|
#ifndef NO_JUNK
|
#ifndef NO_JUNK
|
// 7.
|
// 7.
|
|
|
// 1 -> 0x0001
|
// 1 -> 0x0001
|
// 2 -> 0x0002
|
// 2 -> 0x0002
|
// 4 -> 0x0004
|
// 4 -> 0x0004
|
// 8 -> 0x0008
|
// 8 -> 0x0008
|
// 16 -> 0x0010
|
// 16 -> 0x0010
|
// 32 -> 0x0020
|
// 32 -> 0x0020
|
// 64 -> 0x0040
|
// 64 -> 0x0040
|
// 128 -> 0x0080
|
// 128 -> 0x0080
|
// 256 -> 0x0100
|
// 256 -> 0x0100
|
// 512 -> 0x0200
|
// 512 -> 0x0200
|
// 1024 -> 0x0400
|
// 1024 -> 0x0400
|
// 2048 -> 0x0800
|
// 2048 -> 0x0800
|
// 4096 -> 0x1000
|
// 4096 -> 0x1000
|
// 8192 -> 0x2000
|
// 8192 -> 0x2000
|
// 16384 -> 0x4000
|
// 16384 -> 0x4000
|
for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
fft->test((double)v,0.0,(double)v,0.0);
|
fft->test((double)v,0.0,(double)v,0.0);
|
// 1 -> 0xffff
|
// 1 -> 0xffff
|
// 2 -> 0xfffe
|
// 2 -> 0xfffe
|
// 4 -> 0xfffc
|
// 4 -> 0xfffc
|
// 8 -> 0xfff8
|
// 8 -> 0xfff8
|
// 16 -> 0xfff0
|
// 16 -> 0xfff0
|
// 32 -> 0xffe0
|
// 32 -> 0xffe0
|
// 64 -> 0xffc0
|
// 64 -> 0xffc0
|
// 128 -> 0xff80
|
// 128 -> 0xff80
|
// 256 -> 0xff00
|
// 256 -> 0xff00
|
// 512 -> 0xfe00
|
// 512 -> 0xfe00
|
// 1024 -> 0xfc00
|
// 1024 -> 0xfc00
|
// 2048 -> 0xf800
|
// 2048 -> 0xf800
|
// 4096 -> 0xf000
|
// 4096 -> 0xf000
|
// 8192 -> 0xe000
|
// 8192 -> 0xe000
|
// 16384 -> 0xc000
|
// 16384 -> 0xc000
|
// 32768 -> 0x8000
|
// 32768 -> 0x8000
|
fft->test(0.0,0.0,16384.0,0.0);
|
fft->test(0.0,0.0,16384.0,0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
for(int v=1; v<=32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
for(int v=1; v<=32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
fft->test(-(double)v,0.0,-(double)v,0.0);
|
fft->test(-(double)v,0.0,-(double)v,0.0);
|
// 1 -> 0x000040 CORRECT!!
|
// 1 -> 0x000040 CORRECT!!
|
// 2 -> 0x000080
|
// 2 -> 0x000080
|
// 4 -> 0x000100
|
// 4 -> 0x000100
|
// 8 -> 0x000200
|
// 8 -> 0x000200
|
// 16 -> 0x000400
|
// 16 -> 0x000400
|
// 32 -> 0x000800
|
// 32 -> 0x000800
|
// 64 -> 0x001000
|
// 64 -> 0x001000
|
// 128 -> 0x002000
|
// 128 -> 0x002000
|
// 256 -> 0x004000
|
// 256 -> 0x004000
|
// 512 -> 0x008000
|
// 512 -> 0x008000
|
// 1024 -> 0x010000
|
// 1024 -> 0x010000
|
// 2048 -> 0x020000
|
// 2048 -> 0x020000
|
// 4096 -> 0x040000
|
// 4096 -> 0x040000
|
// 8192 -> 0x080000
|
// 8192 -> 0x080000
|
// 16384 -> 0x100000
|
// 16384 -> 0x100000
|
for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,(double)v,0.0,(double)v);
|
fft->test(0.0,(double)v,0.0,(double)v);
|
// 1 -> 0x3fffc0
|
// 1 -> 0x3fffc0
|
// 2 -> 0x3fff80
|
// 2 -> 0x3fff80
|
// 4 -> 0x3fff00
|
// 4 -> 0x3fff00
|
// 8 -> 0x3ffe00
|
// 8 -> 0x3ffe00
|
// 16 -> 0x3ffc00
|
// 16 -> 0x3ffc00
|
// 32 -> 0x3ff800
|
// 32 -> 0x3ff800
|
// 64 -> 0x3ff000
|
// 64 -> 0x3ff000
|
// 128 -> 0x3fe000
|
// 128 -> 0x3fe000
|
// 256 -> 0x3fc000
|
// 256 -> 0x3fc000
|
// 512 -> 0x3f8000
|
// 512 -> 0x3f8000
|
// 1024 -> 0x3f0000
|
// 1024 -> 0x3f0000
|
// 2048 -> 0x3e0000
|
// 2048 -> 0x3e0000
|
// 4096 -> 0x3c0000
|
// 4096 -> 0x3c0000
|
// 8192 -> 0x380000
|
// 8192 -> 0x380000
|
// 16384 -> 0x300000
|
// 16384 -> 0x300000
|
for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,-(double)v,0.0,-(double)v);
|
fft->test(0.0,-(double)v,0.0,-(double)v);
|
|
|
// 61. Now, how about the smallest alternating real signal
|
// 61. Now, how about the smallest alternating real signal
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(2.0,0.0,0.0,0.0); // Don't forget to expect a bias!
|
fft->test(2.0,0.0,0.0,0.0); // Don't forget to expect a bias!
|
// 62. Now, how about the smallest alternating imaginary signal
|
// 62. Now, how about the smallest alternating imaginary signal
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,2.0,0.0,0.0); // Don't forget to expect a bias!
|
fft->test(0.0,2.0,0.0,0.0); // Don't forget to expect a bias!
|
// 63. Now, how about the smallest alternating real signal,2nd phase
|
// 63. Now, how about the smallest alternating real signal,2nd phase
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,2.0,0.0); // Don't forget to expect a bias!
|
fft->test(0.0,0.0,2.0,0.0); // Don't forget to expect a bias!
|
// 64.Now, how about the smallest alternating imaginary signal,2nd phase
|
// 64.Now, how about the smallest alternating imaginary signal,2nd phase
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,0.0,0.0,2.0); // Don't forget to expect a bias!
|
fft->test(0.0,0.0,0.0,2.0); // Don't forget to expect a bias!
|
|
|
// 65.
|
// 65.
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(32767.0,0.0,-32767.0,0.0);
|
fft->test(maxv,0.0,-maxv,0.0);
|
// 66.
|
// 66.
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,-32767.0,0.0,32767.0);
|
fft->test(0.0,-maxv,0.0,maxv);
|
// 67.
|
// 67.
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(-32768.0,-32768.0,-32768.0,-32768.0);
|
fft->test(-maxv,-maxv,-maxv,-maxv);
|
// 68.
|
// 68.
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,-32767.0,0.0,32767.0);
|
fft->test(0.0,-maxv,0.0,maxv);
|
// 69.
|
// 69.
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(0.0,32767.0,0.0,-32767.0);
|
fft->test(0.0,maxv,0.0,-maxv);
|
// 70.
|
// 70.
|
for(int k=0; k<FFTLEN/2; k++)
|
for(int k=0; k<FFTLEN/2; k++)
|
fft->test(-32768.0,-32768.0,-32768.0,-32768.0);
|
fft->test(-maxv,-maxv,-maxv,-maxv);
|
|
|
// 71. Now let's go for an impulse (SUCCESS)
|
// 71. Now let's go for an impulse (SUCCESS)
|
fft->test(16384.0, 0.0, 0.0, 0.0);
|
fft->test(16384.0, 0.0, 0.0, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 72. And another one on the next clock (FAILS, ugly)
|
// 72. And another one on the next clock (FAILS, ugly)
|
fft->test(0.0, 0.0, 16384.0, 0.0);
|
fft->test(0.0, 0.0, 16384.0, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 72. And another one on the next clock (FAILS, ugly)
|
// 72. And another one on the next clock (FAILS, ugly)
|
fft->test(0.0, 0.0, 8192.0, 0.0);
|
fft->test(0.0, 0.0, 8192.0, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 72. And another one on the next clock (FAILS, ugly)
|
// 72. And another one on the next clock (FAILS, ugly)
|
fft->test(0.0, 0.0, 512.0, 0.0);
|
fft->test(0.0, 0.0, 512.0, 0.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 73. And an imaginary one on the second clock
|
// 73. And an imaginary one on the second clock
|
fft->test(0.0, 0.0, 0.0, 16384.0);
|
fft->test(0.0, 0.0, 0.0, 16384.0);
|
for(int k=0; k<FFTLEN/2-1; k++)
|
for(int k=0; k<FFTLEN/2-1; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 74. Likewise the next clock
|
// 74. Likewise the next clock
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(16384.0, 0.0, 0.0, 0.0);
|
fft->test(16384.0, 0.0, 0.0, 0.0);
|
for(int k=0; k<FFTLEN/2-2; k++)
|
for(int k=0; k<FFTLEN/2-2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 75. And it's imaginary counterpart
|
// 75. And it's imaginary counterpart
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0, 16384.0, 0.0, 0.0);
|
fft->test(0.0, 16384.0, 0.0, 0.0);
|
for(int k=0; k<FFTLEN/2-2; k++)
|
for(int k=0; k<FFTLEN/2-2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 76. Likewise the next clock
|
// 76. Likewise the next clock
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0, 0.0, 16384.0, 0.0);
|
fft->test(0.0, 0.0, 16384.0, 0.0);
|
for(int k=0; k<FFTLEN/2-2; k++)
|
for(int k=0; k<FFTLEN/2-2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
// 77. And it's imaginary counterpart
|
// 77. And it's imaginary counterpart
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0, 0.0, 0.0, 16384.0);
|
fft->test(0.0, 0.0, 0.0, 16384.0);
|
for(int k=0; k<FFTLEN/2-2; k++)
|
for(int k=0; k<FFTLEN/2-2; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
|
|
// 78. Now let's try some exponentials
|
// 78. Now let's try some exponentials
|
for(int k=0; k<FFTLEN/2; k++) {
|
for(int k=0; k<FFTLEN/2; k++) {
|
double cl, cr, sl, sr, W;
|
double cl, cr, sl, sr, W;
|
W = - 2.0 * M_PI / FFTLEN;
|
W = - 2.0 * M_PI / FFTLEN;
|
cl = cos(W * (2*k )) * 16383.0;
|
cl = cos(W * (2*k )) * 16383.0;
|
sl = sin(W * (2*k )) * 16383.0;
|
sl = sin(W * (2*k )) * 16383.0;
|
cr = cos(W * (2*k+1)) * 16383.0;
|
cr = cos(W * (2*k+1)) * 16383.0;
|
sr = sin(W * (2*k+1)) * 16383.0;
|
sr = sin(W * (2*k+1)) * 16383.0;
|
fft->test(cl, sl, cr, sr);
|
fft->test(cl, sl, cr, sr);
|
}
|
}
|
|
|
// 72.
|
// 72.
|
for(int k=0; k<FFTLEN/2; k++) {
|
for(int k=0; k<FFTLEN/2; k++) {
|
double cl, cr, sl, sr, W;
|
double cl, cr, sl, sr, W;
|
W = - 2.0 * M_PI / FFTLEN * 5;
|
W = - 2.0 * M_PI / FFTLEN * 5;
|
cl = cos(W * (2*k )) * 16383.0;
|
cl = cos(W * (2*k )) * 16383.0;
|
sl = sin(W * (2*k )) * 16383.0;
|
sl = sin(W * (2*k )) * 16383.0;
|
cr = cos(W * (2*k+1)) * 16383.0;
|
cr = cos(W * (2*k+1)) * 16383.0;
|
sr = sin(W * (2*k+1)) * 16383.0;
|
sr = sin(W * (2*k+1)) * 16383.0;
|
fft->test(cl, sl, cr, sr);
|
fft->test(cl, sl, cr, sr);
|
}
|
}
|
|
|
// 73.
|
// 73.
|
for(int k=0; k<FFTLEN/2; k++) {
|
for(int k=0; k<FFTLEN/2; k++) {
|
double cl, cr, sl, sr, W;
|
double cl, cr, sl, sr, W;
|
W = - 2.0 * M_PI / FFTLEN * 8;
|
W = - 2.0 * M_PI / FFTLEN * 8;
|
cl = cos(W * (2*k )) * 8190.0;
|
cl = cos(W * (2*k )) * 8190.0;
|
sl = sin(W * (2*k )) * 8190.0;
|
sl = sin(W * (2*k )) * 8190.0;
|
cr = cos(W * (2*k+1)) * 8190.0;
|
cr = cos(W * (2*k+1)) * 8190.0;
|
sr = sin(W * (2*k+1)) * 8190.0;
|
sr = sin(W * (2*k+1)) * 8190.0;
|
fft->test(cl, sl, cr, sr);
|
fft->test(cl, sl, cr, sr);
|
}
|
}
|
|
|
// 74.
|
// 74.
|
for(int k=0; k<FFTLEN/2; k++) {
|
for(int k=0; k<FFTLEN/2; k++) {
|
double cl, cr, sl, sr, W;
|
double cl, cr, sl, sr, W;
|
W = - 2.0 * M_PI / FFTLEN * 25;
|
W = - 2.0 * M_PI / FFTLEN * 25;
|
cl = cos(W * (2*k )) * 4.0;
|
cl = cos(W * (2*k )) * 4.0;
|
sl = sin(W * (2*k )) * 4.0;
|
sl = sin(W * (2*k )) * 4.0;
|
cr = cos(W * (2*k+1)) * 4.0;
|
cr = cos(W * (2*k+1)) * 4.0;
|
sr = sin(W * (2*k+1)) * 4.0;
|
sr = sin(W * (2*k+1)) * 4.0;
|
fft->test(cl, sl, cr, sr);
|
fft->test(cl, sl, cr, sr);
|
}
|
}
|
#endif
|
#endif
|
// 19.--24. And finally, let's clear out our results / buffer
|
// 19.--24. And finally, let's clear out our results / buffer
|
for(int k=0; k<(FFTLEN/2) * 5; k++)
|
for(int k=0; k<(FFTLEN/2) * 5; k++)
|
fft->test(0.0,0.0,0.0,0.0);
|
fft->test(0.0,0.0,0.0,0.0);
|
|
|
|
|
|
|
fclose(fpout);
|
fclose(fpout);
|
|
|
|
if (!fft->m_syncd) {
|
|
printf("FAIL -- NO SYNC\n");
|
|
goto test_failure;
|
|
}
|
|
|
printf("SUCCESS!!\n");
|
printf("SUCCESS!!\n");
|
exit(0);
|
exit(0);
|
|
test_failure:
|
|
printf("TEST FAILED!!\n");
|
|
exit(0);
|
}
|
}
|
|
|
|
|
|
|