OpenCores
URL https://opencores.org/ocsvn/dblclockfft/dblclockfft/trunk

Subversion Repositories dblclockfft

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /dblclockfft/trunk/bench
    from Rev 22 to Rev 23
    Reverse comparison

Rev 22 → Rev 23

/rtl/Makefile
1,17 → 1,52
all: ifft_tb
############################################################################
##
## Filename: Makefile
##
## Project: A Doubletime Pipelined FFT
##
## Purpose: This programs the build process for part of the ifft_tb test
## bench associated with the double clocked FFT project.
##
## This is only part of the test bench program. This one is
## different from the others, in that the ifft_tb includes
## both verilator code in the test bench as well as the
## C++ code. The C++ code will depend upon the verilog
## code found in this directory and built here.
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Tecnology, LLC
##
##########################################################################/
##
## Copyright (C) 2015, Gisselquist Technology, LLC
##
## 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
## by the Free Software Foundation, either version 3 of the License, or (at
## your option) any later version.
##
## This program is distributed in the hope that it will be useful, but WITHOUT
## ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
## for more details.
##
## 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
## target there if the PDF file isn't present.) If not, see
## <http:##www.gnu.org/licenses/> for a copy.
##
## License: GPL, v3, as defined and found on www.gnu.org,
## http:##www.gnu.org/licenses/gpl.html
##
##
##########################################################################/
 
OBJDR:= ../../sw/fft-core/obj_dir
VSRCD:= ../../sw/fft-core
LCLDR:= obj_dir
VINC := -I/usr/share/verilator/include -I$(OBJDR)/ -I$(LCLDR)/
MPYLB:= $(OBJDR)/Vshiftaddmpy__ALL.a
DBLRV:= $(OBJDR)/Vdblreverse__ALL.a
DBLSG:= $(OBJDR)/Vdblstage__ALL.a
QTRSG:= $(OBJDR)/Vqtrstage__ALL.a
BFLYL:= $(OBJDR)/Vbutterfly__ALL.a
FFTLB:= $(OBJDR)/Vfftmain__ALL.a
IFTLB:= $(LCLDR)/Vifft_tb__ALL.a
STGLB:= $(OBJDR)/Vfftstage_o2048__ALL.a
VERILATOR_ROOT := /usr/share/verilator
 
.PHONY: ifft_tb
/cpp/qtrstage_tb.cpp
44,98 → 44,170
 
#include "Vqtrstage.h"
#include "verilated.h"
#include "twoc.h"
 
#define IWIDTH 16
#define OWIDTH (IWIDTH+1)
#define LGWIDTH 8
 
void tick(Vqtrstage *qstage) {
qstage->i_clk = 0;
qstage->eval();
qstage->i_clk = 1;
qstage->eval();
}
#define ASIZ 32
#define AMSK (ASIZ-1)
 
void reset(Vqtrstage *qstage) {
qstage->i_ce = 0;
qstage->i_rst = 1;
tick(qstage);
qstage->i_ce = 0;
qstage->i_rst = 0;
tick(qstage);
}
class QTRTEST_TB {
public:
Vqtrstage *m_qstage;
unsigned long m_data[ASIZ];
int m_addr, m_offset;
bool m_syncd;
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
Vqtrstage *qstage = new Vqtrstage;
int16_t ir0, ii0, lstr, lsti;
int32_t sumr, sumi, difr, difi;
int32_t smr, smi, dfr, dfi;
int rnd = 0; // Can only be set to true if OWIDTH=IWIDTH
QTRTEST_TB(void) {
m_qstage = new Vqtrstage;
m_addr = 0; m_offset = 6; m_syncd = false;
}
 
if ((OWIDTH<IWIDTH+1)&&(rnd!=0)) {
fprintf(stderr, "ERR: Rounding can only be applied when\n");
fprintf(stderr, "\tthe output width is less than or equal\n");
fprintf(stderr, "\tto the input width. Turn rounding off\n");
fprintf(stderr, "\trebuild, and try again.\n");
assert(0 == rnd);
void tick(void) {
m_qstage->i_clk = 0;
m_qstage->eval();
m_qstage->i_clk = 1;
m_qstage->eval();
 
m_qstage->i_sync = 0;
}
 
reset(qstage);
void reset(void) {
m_qstage->i_ce = 0;
m_qstage->i_rst = 1;
tick();
m_qstage->i_ce = 0;
m_qstage->i_rst = 0;
tick();
 
for(int k=0; k<1060; k++) {
int32_t or0, oi0, or1, oi1;
m_addr = 0; m_offset = 6; m_syncd = false;
}
 
qstage->i_ce = 1;
qstage->i_sync = ((k&0x0ff)==0);
// Let's pick some random values, ...
ir0 = rand(); if (ir0&4) ir0 = -ir0;
ii0 = rand(); if (ii0&2) ii0 = -ii0;
void check_results(void) {
int ir0, ii0, ir1, ii1, ir2, ii2;
int sumr, sumi, difr, difi, or0, oi0;
bool fail = false;
 
qstage->i_data = ((ir0&0x0ffff) << 16) | (ii0 & 0x0ffff);
tick(qstage);
if ((!m_syncd)&&(m_qstage->o_sync)) {
m_syncd = true;
m_offset = m_addr;
}
 
printf("k=%4d: ISYNC=%d, IN = %08x, OUT =%09lx, SYNC=%d\n",
k, qstage->i_sync, qstage->i_data,
qstage->o_data, qstage->o_sync);
if (!m_syncd)
return;
 
or0 = (qstage->o_data >> 17) & 0x01ffff;
oi0 = qstage->o_data & 0x01ffff;
if (or0 & 0x010000) or0 |= (-1<<16);
if (oi0 & 0x010000) oi0 |= (-1<<16);
ir0 = sbits(m_data[(m_addr-m_offset-1)&AMSK]>>IWIDTH, IWIDTH);
ii0 = sbits(m_data[(m_addr-m_offset-1)&AMSK], IWIDTH);
ir1 = sbits(m_data[(m_addr-m_offset )&AMSK]>>IWIDTH, IWIDTH);
ii1 = sbits(m_data[(m_addr-m_offset )&AMSK], IWIDTH);
ir2 = sbits(m_data[(m_addr-m_offset+1)&AMSK]>>IWIDTH, IWIDTH);
ii2 = sbits(m_data[(m_addr-m_offset+1)&AMSK], IWIDTH);
 
if (k>3) {
/*
printf("\tOR0 = %6x, OI0 = %6x, SUM = %6x + %6x, DIF = %6x + %6x\n",
or0, oi0, sumr, sumi, difr, difi);
*/
if (0==(k&1)) {
if (or0 != sumr) {fprintf(stderr, "FAIL 1\n"); exit(-1);}
if (oi0 != sumi) {fprintf(stderr, "FAIL 2\n"); exit(-1);}
} else if (1==(k&1)) {
if (or0 != difr) {fprintf(stderr, "FAIL 3\n"); exit(-1);}
if (oi0 != difi) {fprintf(stderr, "FAIL 4\n"); exit(-1);}
}
sumr = ir1 + ir2;
sumi = ii1 + ii2;
difr = ir0 - ir1;
difi = ii0 - ii1;
 
or0 = sbits(m_qstage->o_data >> OWIDTH, OWIDTH);
oi0 = sbits(m_qstage->o_data, OWIDTH);
 
if (0==((m_addr-m_offset)&1)) {
if (or0 != sumr) {
printf("FAIL 1: or0 != sumr (%x(exp) != %x(sut))\n", sumr, or0); fail = true;}
if (oi0 != sumi) {
printf("FAIL 2: oi0 != sumi (%x(exp) != %x(sut))\n", sumi, oi0); fail = true;}
} else if (1==((m_addr-m_offset)&1)) {
if (or0 != difr) {
printf("FAIL 3: or0 != difr (%x(exp) != %x(sut))\n", difr, or0); fail = true;}
if (oi0 != difi) {
printf("FAIL 4: oi0 != difi (%x(exp) != %x(sut))\n", difi, oi0); fail = true;}
}
 
if (((4==(k&0x07f))?1:0) != qstage->o_sync) { fprintf(stderr, "BAD O-SYNC\n"); exit(-1); }
if (m_qstage->o_sync != ((((m_addr-m_offset)&127) == 0)?1:0)) {
printf("BAD O-SYNC, m_addr = %d, m_offset = %d\n", m_addr, m_offset); fail = true;
}
 
if (1 == (k&1)) {
sumr = smr; sumi = smi; difr=dfr, difi= dfi;
if (fail)
exit(-1);
}
 
smr = lstr + ir0 + rnd;
smi = lsti + ii0 + rnd;
void sync(void) {
m_qstage->i_sync = 1;
m_addr = 0;
}
 
dfr = lstr - ir0 + rnd;
dfi = lsti - ii0 + rnd;
}
void test(unsigned int data) {
int isync = m_qstage->i_sync;
m_qstage->i_ce = 1;
m_qstage->i_data = data;
// m_qstage->i_sync = (((m_addr&127)==2)?1:0);
m_data[ (m_addr++)&AMSK] = data;
tick();
 
lstr = ir0;
lsti = ii0;
printf("k=%4d: ISYNC=%d, IN = %08x, OUT =%09lx, SYNC=%d\t%5x,%5x,%5x,%5x\t%x %4x %8x %d\n",
(m_addr-m_offset), isync, m_qstage->i_data,
m_qstage->o_data, m_qstage->o_sync,
m_qstage->v__DOT__sum_r,
m_qstage->v__DOT__sum_i,
m_qstage->v__DOT__diff_r,
m_qstage->v__DOT__diff_i,
m_qstage->v__DOT__pipeline,
m_qstage->v__DOT__iaddr,
m_qstage->v__DOT__imem,
m_qstage->v__DOT__wait_for_sync);
 
check_results();
}
 
delete qstage;
void test(int ir0, int ii0) {
unsigned int data;
 
data = (((ir0&((1<<IWIDTH)-1)) << IWIDTH) | (ii0 & ((1<<IWIDTH)-1)));
// printf("%d,%d -> %8x\n", ir0, ii0, data);
test(data);
}
 
void random_test(void) {
int ir0, ii0;
 
// Let's pick some random values
ir0 = rand(); if (ir0&4) ir0 = -ir0;
ii0 = rand(); if (ii0&2) ii0 = -ii0;
test(ir0, ii0);
}
};
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
QTRTEST_TB *tb = new QTRTEST_TB;
int16_t ir0, ii0, ir1, ii1, ir2, ii2;
int32_t sumr, sumi, difr, difi;
 
tb->reset();
 
tb->test( 16, 0);
tb->test( 16, 0);
tb->sync();
tb->test( 0, 16);
tb->test( 0, 16);
tb->test( 16, 0);
tb->test(-16, 0);
tb->test( 0, 16);
tb->test( 0,-16);
 
for(int k=0; k<1060; k++) {
tb->random_test();
}
 
delete tb;
 
printf("SUCCESS!\n");
exit(0);
}
 
 
 
 
 
/cpp/hwbfly_tb.cpp
44,24 → 44,8
 
#include "Vhwbfly.h"
#include "verilated.h"
#include "twoc.h"
 
long sbits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
}
 
unsigned long ubits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
return r;
}
 
 
class BFLY_TB {
public:
Vhwbfly *m_bfly;
/cpp/twoc.h
0,0 → 1,46
////////////////////////////////////////////////////////////////////////////
//
// Filename: twoc.h
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: Some various two's complement related C++ helper routines.
// Specifically, these help extract signed numbers from
// packed bitfields, while guaranteeing that the upper bits
// are properly sign extended (or not) as desired.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// 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
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// 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
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#ifndef TWOC_H
#define TWOC_H
 
extern long sbits(const long val, const int bits);
extern unsigned long ubits(const long val, const int bits);
 
#endif
 
/cpp/fft_tb.cpp
45,17 → 45,19
 
#include "verilated.h"
#include "Vfftmain.h"
#include "twoc.h"
 
#define LGWIDTH 11
#define IWIDTH 16
#define OWIDTH 22
 
#define NFTLOG 8
#define FFTLEN (1<<LGWIDTH)
 
class FFT_TB {
public:
Vfftmain *m_fft;
long m_data[FFTLEN], m_log[4*FFTLEN];
long m_data[FFTLEN], m_log[NFTLOG*FFTLEN];
int m_iaddr, m_oaddr, m_ntest;
FILE *m_dumpfp;
fftw_plan m_plan;
94,12 → 96,7
}
 
long twos_complement(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
return sbits(val, bits);
}
 
void checkresults(void) {
110,12 → 107,12
 
// Fill up our test array from the log array
// printf("%3d : CHECK: %8d %5x\n", m_ntest, m_iaddr, m_iaddr);
dp = m_fft_buf; lp = &m_log[(m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))];
dp = m_fft_buf; lp = &m_log[(m_iaddr-FFTLEN*3)&((NFTLOG*FFTLEN-1)&(-FFTLEN))];
for(int i=0; i<FFTLEN; i++) {
long tv = *lp++;
 
dp[0] = twos_complement(tv >> IWIDTH, IWIDTH);
dp[1] = twos_complement(tv, IWIDTH);
dp[0] = sbits(tv >> IWIDTH, IWIDTH);
dp[1] = sbits(tv, IWIDTH);
 
// printf("IN[%4d = %4x] = %9.1f %9.1f\n",
// i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
138,10 → 135,10
 
// printf("OUT[%4d = %4x] = ", i, i);
// printf("%12lx = ", tv);
*dp = twos_complement(tv >> OWIDTH, OWIDTH);
*dp = sbits(tv >> OWIDTH, OWIDTH);
// printf("%10.1f + ", *dp);
osq += (*dp) * (*dp); dp++;
*dp = twos_complement(tv, OWIDTH);
*dp = sbits(tv, OWIDTH);
// printf("%10.1f j", *dp);
osq += (*dp) * (*dp); dp++;
// printf(" <-> %12.1f %12.1f\n", m_fft_buf[2*i], m_fft_buf[2*i+1]);
172,7 → 169,7
if (xisq > 1.4 * FFTLEN/2) {
printf("TEST FAIL!! Result is out of bounds from ");
printf("expected result with FFTW3.\n");
exit(-2);
// exit(-2);
}
m_ntest++;
}
183,8 → 180,8
m_fft->i_left = lft;
m_fft->i_right = rht;
 
m_log[(m_iaddr++)&(4*FFTLEN-1)] = (long)lft;
m_log[(m_iaddr++)&(4*FFTLEN-1)] = (long)rht;
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = (long)lft;
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = (long)rht;
 
tick();
 
193,19 → 190,20
m_syncd = true;
} else m_oaddr += 2;
 
/*
printf("%8x,%5d: %08x,%08x -> %011lx,%011lx"
// "\t%011lx,%011lx"
// "\t%011lx,%011lx"
"\t%011lx,%011lx"
// "\t%06x,%06x"
// "\t%06x,%06x"
// "\t%011lx,%06x,%06x"
"\t%011lx,%06x,%06x"
"\t%011lx,%06x,%06x"
" %s%s%s%s%s%s%s%s%s%s %s%s\n",
"\t%06x,%06x,%06x,%06x"
"\t%011lx,%011lx"
" %s%s%s%s%s%s%s%s%s%s%s %s%s\n",
m_iaddr, m_oaddr,
lft, rht, m_fft->o_left, m_fft->o_right,
// m_fft->v__DOT__stage_e2048__DOT__ib_a,
// m_fft->v__DOT__stage_e2048__DOT__ib_b,
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,
226,16 → 224,18
// 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_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__out_0r,
// m_fft->v__DOT__stage_2__DOT__out_0i,
// m_fft->v__DOT__stage_2__DOT__out_1r,
// m_fft->v__DOT__stage_2__DOT__out_1i,
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,
m_fft->v__DOT__br_o_left,
m_fft->v__DOT__br_o_right,
(m_fft->v__DOT__w_s2048)?"S":"-",
(m_fft->v__DOT__w_s1024)?"S":"-",
(m_fft->v__DOT__w_s512)?"S":"-",
246,10 → 246,9
(m_fft->v__DOT__w_s16)?"S":"-",
(m_fft->v__DOT__w_s8)?"S":"-",
(m_fft->v__DOT__w_s4)?"S":"-",
// (m_fft->v__DOT__w_s2)?"S":"-", // doesn't exist
(m_fft->v__DOT__br_sync)?"S":((m_fft->v__DOT__r_br_started)?".":"x"),
(m_fft->o_sync)?"\t(SYNC!)":"",
(m_fft->o_left | m_fft->o_right)?" (NZ)":"");
*/
 
m_data[(m_oaddr )&(FFTLEN-1)] = m_fft->o_left;
m_data[(m_oaddr+1)&(FFTLEN-1)] = m_fft->o_right;
277,17 → 276,11
}
 
double rdata(int addr) {
long ivl = m_data[addr & (FFTLEN-1)];
 
ivl = twos_complement(ivl >> OWIDTH, OWIDTH);
return (double)ivl;
return (double)sbits(m_data[addr&(FFTLEN-1)]>>OWIDTH, OWIDTH);
}
 
double idata(int addr) {
long ivl = m_data[addr & (FFTLEN-1)];
 
ivl = twos_complement(ivl, OWIDTH);
return (double)ivl;
return (double)sbits(m_data[addr&(FFTLEN-1)], OWIDTH);
}
 
void dump(FILE *fp) {
/cpp/fftstage_o2048_tb.cpp
54,7 → 54,7
#define LGSPAN 9
#define SPANLEN (1<<LGSPAN)
#define SPANMASK (SPANLEN-1)
#define DBLSPANLEN (1<<(LGSPAN+1))
#define DBLSPANLEN (1<<(LGSPAN+4))
#define DBLSPANMASK (DBLSPANLEN-1)
#define IWIDTH 16
#define CWIDTH 20
68,15 → 68,15
public:
Vfftstage_o2048 *m_ftstage;
long m_oaddr, m_iaddr;
long m_vals[SPANLEN], m_lft[DBLSPANLEN], m_rht[DBLSPANLEN];
long m_vals[SPANLEN], m_out[DBLSPANLEN];
bool m_syncd;
int m_lchecks, m_rchecks;
int m_offset;
 
FFTSTAGE_TB(void) {
m_ftstage = new Vfftstage_o2048;
m_syncd = false;
m_iaddr = m_oaddr = 0;
m_lchecks = m_rchecks = 0;
m_offset = 0;
}
 
void tick(void) {
91,8 → 91,23
m_ftstage->i_rst = 1;
tick();
 
// Let's give it several ticks with no sync
m_ftstage->i_ce = 0;
m_ftstage->i_rst = 0;
for(int i=0; i<8192; i++) {
m_ftstage->i_data = rand();
m_ftstage->i_sync = 0;
m_ftstage->i_ce = 1;
 
tick();
 
assert(m_ftstage->o_sync == 0);
}
 
m_iaddr = 0;
m_oaddr = 0;
m_offset = 0;
m_syncd = false;
}
 
long twos_complement(const long val, const int nbits) {
157,6 → 172,7
long cv;
bool bc;
int raddr;
bool failed = false;
 
m_ftstage->i_rst = 0;
m_ftstage->i_ce = 1;
174,57 → 190,61
if (m_iaddr & (1<<(LGSPAN+1)))
waddr |= (1<<(LGSPAN));
butterfly(cv, m_vals[m_iaddr & (SPANMASK)], i_data,
m_lft[waddr], m_rht[waddr]);
m_out[(m_iaddr-SPANLEN) & (DBLSPANMASK)],
m_out[m_iaddr & (DBLSPANMASK)]);
/*
printf("BFLY: C=%16lx M=%8lx I=%10lx -> %10lx %10lx\n",
cv, m_vals[m_iaddr & (SPANMASK)], i_data,
m_lft[waddr], m_rht[waddr]);
m_out[(m_iaddr-SPANLEN)&(DBLSPANMASK)],
m_out[m_iaddr & (DBLSPANMASK)]);
*/
}
 
tick();
 
// if (m_ftstage->o_sync)
// m_oaddr = 0;
m_oaddr = m_iaddr - 0x219;
m_syncd = (m_syncd)||(m_ftstage->o_sync);
if ((!m_syncd)&&(m_ftstage->o_sync)) {
m_syncd = true;
// m_oaddr = m_iaddr - 0x219;
// m_oaddr = m_iaddr - 0;
m_offset = m_iaddr;
m_oaddr = 0;
 
raddr = m_oaddr & (~(-1l<<LGSPAN));
printf("SYNC!!!!\n");
}
 
raddr = (m_iaddr-m_offset) & DBLSPANMASK;
/*
if (m_oaddr & (1<<(LGSPAN+1)))
raddr |= (1<<LGSPAN);
*/
 
printf("%4ld, %4ld: %d %9lx -> %9lx %d %4x %15lx (%10lx %10lx)\n",
printf("%4ld, %4ld: %d %9lx -> %9lx %d ... %4x %15lx (%10lx)\n",
m_iaddr, m_oaddr,
i_sync, i_data & (~(-1l << (2*IWIDTH))),
m_ftstage->o_data, m_ftstage->o_sync,
m_ftstage->v__DOT__iaddr&(FFTMASK>>1),
m_ftstage->v__DOT__cmem[m_ftstage->v__DOT__iaddr&(SPANMASK>>1)] & (~(-1l<<(2*CWIDTH))),
m_lft[raddr], m_rht[raddr]);
m_out[raddr]);
 
if (m_ftstage->o_sync != (((m_iaddr&DBLSPANMASK)==0x0219)?1:0)) {
fprintf(stderr, "Bad output sync\n");
exit(-1);
if ((m_syncd)&&(m_ftstage->o_sync != ((((m_iaddr-m_offset)&((1<<(LGSPAN+1))-1))==0)?1:0))) {
fprintf(stderr, "Bad output sync (m_iaddr = %lx, m_offset = %x)\n", (m_iaddr-m_offset) & SPANMASK, m_offset);
failed = true;
}
 
if (m_syncd) {
if (!(m_oaddr&(1l<<LGSPAN))) {
if (m_lft[raddr] != m_ftstage->o_data) {
fprintf(stderr, "Bad output data, left\n");
exit(-1);
}
 
m_lchecks++;
} else {
if (m_rht[raddr] != m_ftstage->o_data) {
fprintf(stderr, "Bad output data, right, m_oaddr = %lx, bit = %lx\n",
m_oaddr, (1l<<LGSPAN));
exit(-1);
}
m_rchecks++;
if (m_out[raddr] != m_ftstage->o_data) {
printf("Bad output data, ([%lx - %x = %x] %lx(exp) != %lx(sut))\n", m_iaddr, m_offset, raddr, m_out[raddr], m_ftstage->o_data);
failed = true;
}
} else if (m_iaddr > 4096) {
printf("NO OUTPUT SYNC!\n");
failed = true;
}
m_iaddr++;
m_oaddr++;
 
if (failed)
exit(-1);
}
};
263,7 → 283,7
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x000010000l);
 
printf("SUCCESS! (%d, %d)\n", ftstage->m_lchecks, ftstage->m_rchecks);
printf("SUCCESS! (Offset = %d)\n", ftstage->m_offset);
delete ftstage;
 
exit(0);
/cpp/butterfly_tb.cpp
44,24 → 44,9
 
#include "Vbutterfly.h"
#include "verilated.h"
#include "twoc.h"
 
long sbits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
}
 
unsigned long ubits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
return r;
}
 
 
class BFLY_TB {
public:
Vbutterfly *m_bfly;
68,12 → 53,13
unsigned long m_left[64], m_right[64];
bool m_aux[64];
int m_addr, m_lastaux, m_offset;
bool m_syncd;
bool m_syncd, m_waiting_for_sync_input;
 
BFLY_TB(void) {
m_bfly = new Vbutterfly;
m_addr = 0;
m_syncd = 0;
m_waiting_for_sync_input = true;
}
 
void tick(void) {
115,6 → 101,8
tick();
m_bfly->i_rst = 0;
m_syncd = 0;
 
m_waiting_for_sync_input = true;
}
 
void test(const int n, const int k, const unsigned long cof,
124,6 → 112,10
m_bfly->i_left = lft;
m_bfly->i_right = rht;
m_bfly->i_aux = aux & 1;
if ((m_waiting_for_sync_input)&&(aux&1)) {
m_waiting_for_sync_input = false;
m_addr = 0;
}
 
tick();
 
163,7 → 155,7
*/
 
if ((m_syncd)&&(m_left[(m_addr-m_offset)&(64-1)] != m_bfly->o_left)) {
fprintf(stderr, "WRONG O_LEFT! (%lx(exp) != %lx(sut)\n",
fprintf(stderr, "WRONG O_LEFT! (%lx(exp) != %lx(sut))\n",
m_left[(m_addr-m_offset)&(64-1)],
m_bfly->o_left);
exit(-1);
170,7 → 162,8
}
 
if ((m_syncd)&&(m_right[(m_addr-m_offset)&(64-1)] != m_bfly->o_right)) {
fprintf(stderr, "WRONG O_RIGHT!\n");
fprintf(stderr, "WRONG O_RIGHT (%lx(exp) != (%lx(sut))!\n",
m_right[(m_addr-m_offset)&(64-1)], m_bfly->o_right);
exit(-1);
}
 
179,7 → 172,7
exit(-1);
}
 
if ((m_addr > 22)&&(!m_syncd)) {
if ((m_addr > 28)&&(!m_syncd)) {
fprintf(stderr, "NO SYNC PULSE!\n");
exit(-1);
}
270,6 → 263,12
 
bfly->reset();
 
// Test whether or not the aux channel starts clear, like its supposed to
bfly->test(9,0,0x4000000000l,0x000f0000,0x000f0000, 0);
bfly->test(9,1,0x4000000000l,0x000f0000,0xfff10000, 0);
bfly->test(9,2,0x4000000000l,0x0000000f,0x0000fff1, 0);
bfly->test(9,3,0x4000000000l,0x0000000f,0x0000000f, 0);
 
bfly->test(9,0,0x4000000000l,0x7fff0000,0x7fff0000, 1);
bfly->test(9,1,0x4000000000l,0x7fff0000,0x80010000, 0);
bfly->test(9,2,0x4000000000l,0x00007fff,0x00008001, 0);
/cpp/dblstage_tb.cpp
44,6 → 44,7
 
#include "Vdblstage.h"
#include "verilated.h"
#include "twoc.h"
 
#define IWIDTH 16
#define OWIDTH (IWIDTH+1)
50,71 → 51,63
#define SHIFT 0
#define ROUND 1
 
long sbits(const long val, const int bits) {
long r;
#define ASIZ 16
#define AMSK (ASIZ-1)
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
}
class DBLSTAGE_TB {
public:
Vdblstage *m_dstage;
unsigned long m_left[ASIZ], m_right[ASIZ];
bool m_syncd;
int m_addr, m_offset;
 
void tick(Vdblstage *dstage) {
dstage->i_clk = 0;
dstage->eval();
dstage->i_clk = 1;
dstage->eval();
}
DBLSTAGE_TB(void) {
m_dstage = new Vdblstage;
m_syncd = false; m_addr = 0, m_offset = 0;
}
 
void reset(Vdblstage *dstage) {
/*
*/
}
void tick(void) {
m_dstage->i_clk = 0;
m_dstage->eval();
m_dstage->i_clk = 1;
m_dstage->eval();
m_dstage->i_rst = 0;
m_dstage->i_sync = 0;
}
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
Vdblstage *dstage = new Vdblstage;
void reset(void) {
m_dstage->i_rst = 1;
tick();
 
reset(dstage);
m_syncd = false; m_addr = 0, m_offset = 0;
}
 
for(int k=0; k<64; k++) {
int16_t ir0, ii0, ir1, ii1;
int32_t or0, oi0, or1, oi1;
int rnd;
void check_results(void) {
bool failed = false;
int ir0, ir1, ii0, ii1, or0, oi0, or1, oi1;
 
dstage->i_ce = 1;
// Let's pick some random values, ...
ir0 = rand(); if (ir0&4) ir0 = -ir0;
ii0 = rand(); if (ii0&2) ii0 = -ii0;
ir1 = rand(); if (ir1&1) ir1 = -ir1;
ii1 = rand(); if (ii1&8) ii1 = -ii1;
if ((!m_syncd)&&(m_dstage->o_sync)) {
m_syncd = true;
m_offset = m_addr;
}
 
dstage->i_left = ((ir0&0x0ffff) << 16) | (ii0 & 0x0ffff);
dstage->i_right = ((ir1&0x0ffff) << 16) | (ii1 & 0x0ffff);
tick(dstage);
ir0 = sbits(m_left[ (m_addr-m_offset)&AMSK]>>IWIDTH, IWIDTH);
ir1 = sbits(m_right[(m_addr-m_offset)&AMSK]>>IWIDTH, IWIDTH);
ii0 = sbits(m_left[ (m_addr-m_offset)&AMSK], IWIDTH);
ii1 = sbits(m_right[(m_addr-m_offset)&AMSK], IWIDTH);
 
ir0 = sbits(ir0, IWIDTH);
ir1 = sbits(ir1, IWIDTH);
ii0 = sbits(ii0, IWIDTH);
ii1 = sbits(ii1, IWIDTH);
 
or0 = sbits(dstage->o_left >> OWIDTH, OWIDTH);
oi0 = sbits(dstage->o_left , OWIDTH);
or1 = sbits(dstage->o_right >> OWIDTH, OWIDTH);
oi1 = sbits(dstage->o_right , OWIDTH);
or0 = sbits(m_dstage->o_left >> OWIDTH, OWIDTH);
oi0 = sbits(m_dstage->o_left , OWIDTH);
or1 = sbits(m_dstage->o_right >> OWIDTH, OWIDTH);
oi1 = sbits(m_dstage->o_right , OWIDTH);
 
/*
#ifdef ROUND
rnd = 1;
#else
rnd = 0;
#endif
*/
 
// Sign extensions
printf("k=%3d: IN = %08x:%08x, OUT =%09lx:%09lx\n",
k, dstage->i_left, dstage->i_right,
dstage->o_left, dstage->o_right);
printf("k=%3d: IN = %08x:%08x, OUT =%09lx:%09lx, S=%d\n",
m_addr, m_dstage->i_left, m_dstage->i_right,
m_dstage->o_left, m_dstage->o_right,
m_dstage->o_sync);
 
/*
printf("\tI0 = { %x : %x }, I1 = { %x : %x }, O0 = { %x : %x }, O1 = { %x : %x }\n",
121,14 → 114,80
ir0, ii0, ir1, ii1, or0, oi0, or1, oi1);
*/
 
if (or0 != (ir0 + ir1)) {fprintf(stderr, "FAIL 1\n"); exit(-1);}
if (oi0 != (ii0 + ii1)) {fprintf(stderr, "FAIL 2\n"); exit(-1);}
if (or1 != (ir0 - ir1)) {fprintf(stderr, "FAIL 3\n"); exit(-1);}
if (oi1 != (ii0 - ii1)) {fprintf(stderr, "FAIL 4\n"); exit(-1);}
if (m_syncd) {
if (or0 != (ir0 + ir1)) {
printf("FAIL 1: or0 != (ir0+ir1), or %x(exp) != %x(sut)\n", (ir0+ir1), or0);
failed=true;}
if (oi0 != (ii0 + ii1)) {printf("FAIL 2\n"); failed=true;}
if (or1 != (ir0 - ir1)) {printf("FAIL 3\n"); failed=true;}
if (oi1 != (ii0 - ii1)) {printf("FAIL 4\n"); failed=true;}
} else if (m_addr > 20) {
printf("NO SYNC!\n");
failed = true;
}
 
if (failed)
exit(-2);
}
 
delete dstage;
void sync(void) {
m_dstage->i_sync = 1;
}
 
void test(unsigned long left, unsigned long right) {
m_dstage->i_ce = 1;
m_dstage->i_left = left;
m_dstage->i_right = right;
 
if (m_dstage->i_sync)
m_addr = 0;
m_left[ m_addr&AMSK] = m_dstage->i_left;
m_right[m_addr&AMSK] = m_dstage->i_right;
m_addr++;
 
tick();
 
check_results();
}
 
void test(int ir0, int ii0, int ir1, int ii1) {
unsigned long left, right, mask = (1<<IWIDTH)-1;
 
left = ((ir0&mask) << IWIDTH) | (ii0 & mask);
right = ((ir1&mask) << IWIDTH) | (ii1 & mask);
test(left, right);
}
};
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
DBLSTAGE_TB *tb = new DBLSTAGE_TB;
 
tb->reset();
 
tb->test(16,16,0,0);
tb->test(0,0,16,16);
tb->sync();
tb->test(16,-16,0,0);
tb->test(0,0,16,-16);
tb->test(16,16,0,0);
tb->test(0,0,16,16);
 
for(int k=0; k<64; k++) {
int16_t ir0, ii0, ir1, ii1;
 
// Let's pick some random values, ...
ir0 = rand(); if (ir0&4) ir0 = -ir0;
ii0 = rand(); if (ii0&2) ii0 = -ii0;
ir1 = rand(); if (ir1&1) ir1 = -ir1;
ii1 = rand(); if (ii1&8) ii1 = -ii1;
 
tb->test(ir0, ii0, ir1, ii1);
 
}
 
delete tb;
 
printf("SUCCESS!\n");
exit(0);
}
/cpp/Makefile
63,27 → 63,30
mpy_tb: mpy_tb.cpp $(MPYLB)
g++ -g $(VINC) $< $(MPYLB) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
dblrev_tb: dblrev_tb.cpp $(DBLRV)
g++ -g $(VINC) $< $(DBLRV) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
dblrev_tb: dblrev_tb.cpp twoc.cpp twoc.h $(DBLRV)
g++ -g $(VINC) $< twoc.cpp $(DBLRV) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
dblstage_tb: dblstage_tb.cpp $(DBLSG)
g++ -g $(VINC) $< $(DBLSG) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
dblstage_tb: dblstage_tb.cpp twoc.cpp twoc.h $(DBLSG)
g++ -g $(VINC) $< twoc.cpp $(DBLSG) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
qtrstage_tb: qtrstage_tb.cpp $(QTRSG)
g++ -g $(VINC) $< $(QTRSG) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
qtrstage_tb: qtrstage_tb.cpp twoc.cpp twoc.h $(QTRSG)
g++ -g $(VINC) $< twoc.cpp $(QTRSG) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
butterfly_tb: butterfly_tb.cpp $(BFLYL)
g++ -g $(VINC) $< $(BFLYL) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
butterfly_tb: butterfly_tb.cpp twoc.cpp twoc.h $(BFLYL)
g++ -g $(VINC) $< twoc.cpp $(BFLYL) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
hwbfly_tb: hwbfly_tb.cpp $(HWBFY)
g++ -g $(VINC) $< $(HWBFY) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
hwbfly_tb: hwbfly_tb.cpp twoc.cpp twoc.h $(HWBFY)
g++ -g $(VINC) $< twoc.cpp $(HWBFY) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
fftstage_o2048_tb: fftstage_o2048_tb.cpp $(STGLB)
g++ -g $(VINC) $< $(STGLB) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
fftstage_o2048_tb: fftstage_o2048_tb.cpp twoc.cpp twoc.h $(STGLB)
g++ -g $(VINC) $< twoc.cpp $(STGLB) $(VERILATOR_ROOT)/include/verilated.cpp -o $@
 
fft_tb: fft_tb.cpp $(FFTLB)
g++ -g $(VINC) $< $(FFTLB) $(VERILATOR_ROOT)/include/verilated.cpp -lfftw3 -o $@
fft_tb: fft_tb.cpp twoc.cpp twoc.h $(FFTLB)
g++ -g $(VINC) $< twoc.cpp $(FFTLB) $(VERILATOR_ROOT)/include/verilated.cpp -lfftw3 -o $@
 
ifft_tb: ifft_tb.cpp twoc.cpp twoc.h $(IFTLB)
g++ -g $(VINC) $< twoc.cpp $(IFTLB) $(VERILATOR_ROOT)/include/verilated.cpp -lfftw3 -o $@
 
.PHONY: HEX
# HEX: cmem_e2048.hex cmem_e1024.hex cmem_e512.hex cmem_e256.hex
# HEX: cmem_o2048.hex cmem_o1024.hex cmem_o512.hex cmem_o256.hex
113,8 → 116,8
 
.PHONY: clean
clean:
rm mpy_tb dblrev_tb dblstage_tb qtrstage_tb butterfly_tb
rm fftstage_o2048_tb fft_tb ifft_tb
rm -f mpy_tb dblrev_tb dblstage_tb qtrstage_tb butterfly_tb
rm -f fftstage_o2048_tb fft_tb ifft_tb hwbfly_tb
rm -rf fft_tb.dbl ifft_tb.dbl
rm -rf *cmem_*.hex
 
/cpp/twoc.cpp
0,0 → 1,55
////////////////////////////////////////////////////////////////////////////
//
// Filename: twoc.cpp
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: Some various two's complement related C++ helper routines.
// Specifically, these help extract signed numbers from
// packed bitfields, while guaranteeing that the upper bits
// are properly sign extended (or not) as desired.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Tecnology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015, Gisselquist Technology, LLC
//
// 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
// by the Free Software Foundation, either version 3 of the License, or (at
// your option) any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// 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
// target there if the PDF file isn't present.) If not, see
// <http://www.gnu.org/licenses/> for a copy.
//
// License: GPL, v3, as defined and found on www.gnu.org,
// http://www.gnu.org/licenses/gpl.html
//
//
///////////////////////////////////////////////////////////////////////////
#include "twoc.h"
 
long sbits(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
}
 
unsigned long ubits(const long val, const int bits) {
unsigned long r = val & ((1l<<bits)-1);
return r;
}
 
 
/cpp/ifft_tb.cpp
47,6 → 47,7
 
#include "verilated.h"
#include "Vifft_tb.h"
#include "twoc.h"
 
#define LGWIDTH 11
#define IWIDTH 16
94,12 → 95,7
}
 
long twos_complement(const long val, const int bits) {
long r;
 
r = val & ((1l<<bits)-1);
if (r & (1l << (bits-1)))
r |= (-1l << bits);
return r;
return sbits(val, bits);
}
 
void checkresults(void) {

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.