Line 45... |
Line 45... |
|
|
#include "verilated.h"
|
#include "verilated.h"
|
#include "Vfftmain.h"
|
#include "Vfftmain.h"
|
#include "twoc.h"
|
#include "twoc.h"
|
|
|
#define LGWIDTH 11
|
#include "fftsize.h"
|
#define IWIDTH 16
|
|
// #define OWIDTH 16
|
|
#define OWIDTH 22
|
|
|
|
#define NFTLOG 8
|
#define IWIDTH FFT_IWIDTH
|
|
#define OWIDTH FFT_OWIDTH
|
|
#define LGWIDTH FFT_LGWIDTH
|
|
|
|
#if (IWIDTH > 16)
|
|
typedef unsigned long ITYP;
|
|
#else
|
|
typedef unsigned int ITYP;
|
|
#endif
|
|
|
|
#if (OWIDTH > 16)
|
|
typedef unsigned long OTYP;
|
|
#else
|
|
typedef unsigned int OTYP;
|
|
#endif
|
|
|
|
#define NFTLOG 16
|
#define FFTLEN (1<<LGWIDTH)
|
#define FFTLEN (1<<LGWIDTH)
|
|
|
|
#ifdef FFT_SKIPS_BIT_REVERSE
|
|
#define APPLY_BITREVERSE_LOCALLY
|
|
#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++) {
|
Line 69... |
Line 86... |
}
|
}
|
|
|
class FFT_TB {
|
class FFT_TB {
|
public:
|
public:
|
Vfftmain *m_fft;
|
Vfftmain *m_fft;
|
long m_data[FFTLEN], m_log[NFTLOG*FFTLEN];
|
OTYP m_data[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;
|
|
|
FFT_TB(void) {
|
FFT_TB(void) {
|
m_fft = new Vfftmain;
|
m_fft = new Vfftmain;
|
m_iaddr = m_oaddr = 0;
|
m_iaddr = m_oaddr = 0;
|
m_dumpfp = NULL;
|
m_dumpfp = NULL;
|
Line 87... |
Line 106... |
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;
|
}
|
}
|
|
|
void tick(void) {
|
void tick(void) {
|
|
if ((!m_fft->i_ce)||(m_fft->i_rst))
|
|
printf("TICK(%s,%s)\n",
|
|
(m_fft->i_rst)?"RST":" ",
|
|
(m_fft->i_ce)?"CE":" ");
|
m_fft->i_clk = 0;
|
m_fft->i_clk = 0;
|
m_fft->eval();
|
m_fft->eval();
|
m_fft->i_clk = 1;
|
m_fft->i_clk = 1;
|
m_fft->eval();
|
m_fft->eval();
|
|
|
|
m_tickcount++;
|
|
|
/*
|
/*
|
int nrpt = (rand()&0x01f) + 1;
|
int nrpt = (rand()&0x01f) + 1;
|
m_fft->i_ce = 0;
|
m_fft->i_ce = 0;
|
for(int i=0; i<nrpt; i++) {
|
for(int i=0; i<nrpt; i++) {
|
m_fft->i_clk = 0;
|
m_fft->i_clk = 0;
|
Line 116... |
Line 143... |
m_fft->i_rst = 0;
|
m_fft->i_rst = 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;
|
}
|
}
|
|
|
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;
|
long *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
|
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++) {
|
long tv = *lp++;
|
ITYP tv = *lp++;
|
|
|
dp[0] = sbits(tv >> IWIDTH, IWIDTH);
|
dp[0] = sbits((long)tv >> IWIDTH, IWIDTH);
|
dp[1] = sbits(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]);
|
Line 153... |
Line 183... |
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 vout
|
// Let's load up the output we received into double valued
|
|
// 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);
|
Line 171... |
Line 202... |
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 (wt == 0.0) scale = 1.0;
|
if (fabs(scale) <= 1./4./FFTLEN)
|
|
scale = 2./(FFTLEN);
|
|
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)) {
|
Line 205... |
Line 238... |
// exit(-2);
|
// exit(-2);
|
}
|
}
|
m_ntest++;
|
m_ntest++;
|
}
|
}
|
|
|
bool test(int lft, int 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_rst = 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)] = (long)lft;
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = lft;
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = (long)rht;
|
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = rht;
|
|
|
tick();
|
tick();
|
|
|
if (m_fft->o_sync) {
|
if (m_fft->o_sync) {
|
if (!m_syncd) {
|
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;
|
m_logbase = m_iaddr;
|
} // else printf("RESYNC AT %lx\n", m_fft->m_tickcount);
|
} else printf("RESYNC AT %lx\n", m_tickcount);
|
m_oaddr &= (-1<<LGWIDTH);
|
m_oaddr &= (-1<<LGWIDTH);
|
m_syncd = true;
|
|
} else m_oaddr += 2;
|
} else m_oaddr += 2;
|
|
|
printf("%8x,%5d: %08x,%08x -> %011lx,%011lx",
|
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);
|
printf( // "\t%011lx,%011lx"
|
|
"\t%3x"
|
|
"\t%011lx,%011lx" // w_e128, w_o128
|
|
// "\t%011lx,%011lx" // w_e4, w_o4
|
|
// "\t%06x,%06x"
|
|
// "\t%06x,%06x"
|
|
// "\t%011lx,%06x,%06x"
|
|
"\t%011lx,%06x,%06x" // ob_a, ob_b_r, ob_b_i
|
|
"\t%06x,%06x,%06x,%06x", // o_out_xx
|
|
// "\t%011lx,%011lx"
|
|
m_fft->v__DOT__revstage__DOT__iaddr,
|
|
m_fft->v__DOT__w_e128,
|
|
m_fft->v__DOT__w_o128,
|
|
// m_fft->v__DOT__w_e4,
|
|
// m_fft->v__DOT__w_o4,
|
|
// m_fft->v__DOT__stage_e512__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e512__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e256__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e256__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e128__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e128__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e64__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e64__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e32__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e32__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e16__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e16__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e8__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_e8__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_o8__DOT__ib_a,
|
|
// m_fft->v__DOT__stage_o8__DOT__ib_b,
|
|
// m_fft->v__DOT__stage_e4__DOT__sum_r,
|
|
// m_fft->v__DOT__stage_e4__DOT__sum_i,
|
|
// m_fft->v__DOT__stage_o4__DOT__sum_r,
|
|
// m_fft->v__DOT__stage_o4__DOT__sum_i,
|
|
// m_fft->v__DOT__stage_e4__DOT__ob_a,
|
|
// m_fft->v__DOT__stage_e4__DOT__ob_b_r,
|
|
// m_fft->v__DOT__stage_e4__DOT__ob_b_i,
|
|
m_fft->v__DOT__stage_o4__DOT__ob_a,
|
|
m_fft->v__DOT__stage_o4__DOT__ob_b_r,
|
|
m_fft->v__DOT__stage_o4__DOT__ob_b_i,
|
|
m_fft->v__DOT__stage_2__DOT__o_out_0r,
|
|
m_fft->v__DOT__stage_2__DOT__o_out_0i,
|
|
m_fft->v__DOT__stage_2__DOT__o_out_1r,
|
|
m_fft->v__DOT__stage_2__DOT__o_out_1i);
|
|
/*
|
/*
|
printf(" DBG:%c%c:%08x [%6d,%6d]",
|
printf(" %011lx,%011lx", m_fft->v__DOT__w_e2048,
|
(m_fft->o_dbg&(1l<<33))?'T':' ',
|
m_fft->v__DOT__w_o2048);
|
(m_fft->o_dbg&(1l<<32))?'C':' ',
|
|
(unsigned)(m_fft->o_dbg&((-1l<<32)-1)),
|
printf(" BF(%d,%11x,%11x,%11lx -> %d,%03x,%8x,%8x)", // %d,%11x,%11x)",
|
((int)(m_fft->o_dbg))>>16,
|
m_fft->v__DOT__stage_o2048__DOT__ib_sync,
|
(((unsigned)(m_fft->o_dbg&0x0ffff))
|
m_fft->v__DOT__stage_o2048__DOT__ib_a,
|
|((m_fft->o_dbg&0x08000)?(-1<<16):0)));
|
m_fft->v__DOT__stage_o2048__DOT__ib_b,
|
|
m_fft->v__DOT__stage_o2048__DOT__ib_c,
|
|
m_fft->v__DOT__stage_o2048__DOT__ob_sync,
|
|
m_fft->v__DOT__stage_o2048__DOT__oB,
|
|
m_fft->v__DOT__stage_o2048__DOT__bfly__DOT__rnd_left_r,
|
|
m_fft->v__DOT__stage_o2048__DOT__bfly__DOT__rnd_right_r);
|
*/
|
*/
|
printf(" %s%s%s%s%s%s%s %s%s\n",
|
|
// m_fft->v__DOT__br_o_left,
|
#ifndef APPLY_BITREVERSE_LOCALLY
|
// m_fft->v__DOT__br_o_right,
|
printf(" [%3x]%s", m_fft->v__DOT__revstage__DOT__iaddr,
|
// (m_fft->v__DOT__w_s2048)?"S":"-",
|
(m_fft->v__DOT__br_sync)?"S"
|
// (m_fft->v__DOT__w_s1024)?"S":"-",
|
:((m_fft->v__DOT__r_br_started)?".":"x"));
|
// (m_fft->v__DOT__w_s512)?"S":"-",
|
#endif
|
// (m_fft->v__DOT__w_s256)?"S":"-",
|
|
(m_fft->v__DOT__w_s128)?"S":"-",
|
printf(" ");
|
(m_fft->v__DOT__w_s64)?"S":"-",
|
#if (FFT_SIZE>=2048)
|
(m_fft->v__DOT__w_s32)?"S":"-",
|
printf("%s", (m_fft->v__DOT__w_s2048)?"S":"-");
|
(m_fft->v__DOT__w_s16)?"S":"-",
|
#endif
|
(m_fft->v__DOT__w_s8)?"S":"-",
|
#if (FFT_SIZE>1024)
|
(m_fft->v__DOT__w_s4)?"S":"-",
|
printf("%s", (m_fft->v__DOT__w_s1024)?"S":"-");
|
(m_fft->v__DOT__br_sync)?"S":((m_fft->v__DOT__r_br_started)?".":"x"),
|
#endif
|
|
#if (FFT_SIZE>512)
|
|
printf("%s", (m_fft->v__DOT__w_s512)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>256)
|
|
printf("%s", (m_fft->v__DOT__w_s256)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>128)
|
|
printf("%s", (m_fft->v__DOT__w_s128)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>64)
|
|
printf("%s", (m_fft->v__DOT__w_s64)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>32)
|
|
printf("%s", (m_fft->v__DOT__w_s32)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>16)
|
|
printf("%s", (m_fft->v__DOT__w_s16)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>8)
|
|
printf("%s", (m_fft->v__DOT__w_s8)?"S":"-");
|
|
#endif
|
|
#if (FFT_SIZE>4)
|
|
printf("%s", (m_fft->v__DOT__w_s4)?"S":"-");
|
|
#endif
|
|
|
|
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;
|
Line 310... |
Line 331... |
|
|
return (m_fft->o_sync);
|
return (m_fft->o_sync);
|
}
|
}
|
|
|
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) {
|
int ilft, irht, ilft_r, ilft_i, irht_r, irht_i;
|
ITYP ilft, irht, ilft_r, ilft_i, irht_r, irht_i;
|
|
|
ilft_r = (int)(lft_r) & ((1<<IWIDTH)-1);
|
ilft_r = (ITYP)(lft_r) & ((1<<IWIDTH)-1);
|
ilft_i = (int)(lft_i) & ((1<<IWIDTH)-1);
|
ilft_i = (ITYP)(lft_i) & ((1<<IWIDTH)-1);
|
irht_r = (int)(rht_r) & ((1<<IWIDTH)-1);
|
irht_r = (ITYP)(rht_r) & ((1<<IWIDTH)-1);
|
irht_i = (int)(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;
|
|
|
return test(ilft, irht);
|
return test(ilft, irht);
|
}
|
}
|
|
|
double rdata(int addr) {
|
double rdata(int addr) {
|
int index = addr & (FFTLEN-1);
|
int index = addr & (FFTLEN-1);
|
|
|
// index = bitrev(LGWIDTH, index);
|
#ifdef APPLY_BITREVERSE_LOCALLY
|
|
index = bitrev(LGWIDTH, index);
|
|
#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);
|
|
|
// index = bitrev(LGWIDTH, index);
|
#ifdef APPLY_BITREVERSE_LOCALLY
|
|
index = bitrev(LGWIDTH, index);
|
|
#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;
|
Line 371... |
Line 396... |
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->reset();
|
fft->reset();
|
|
|
|
{
|
|
int ftlen = FFTLEN;
|
|
fwrite(&ftlen, 1, sizeof(int), fpout);
|
|
}
|
fft->dump(fpout);
|
fft->dump(fpout);
|
|
|
// 1.
|
// 1.
|
fft->test(0.0, 0.0, 32767.0, 0.0);
|
fft->test(0.0, 0.0, 32767.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);
|
|
|
|
// 2. Try placing a pulse at the very end location
|
|
for(int k=0; k<FFTLEN/2; k++) {
|
|
double cl, cr, sl, sr, W;
|
|
W = - 2.0 * M_PI / FFTLEN * (1);
|
|
cl = cos(W * (2*k )) * 16383.0;
|
|
sl = sin(W * (2*k )) * 16383.0;
|
|
cr = cos(W * (2*k+1)) * 16383.0;
|
|
sr = sin(W * (2*k+1)) * 16383.0;
|
|
fft->test(cl, sl, cr, sr);
|
|
}
|
|
|
// 2.
|
// 2.
|
fft->test(32767.0, 0.0, 32767.0, 0.0);
|
fft->test(32767.0, 0.0, 32767.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);
|
|
|