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) { |