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 35 to Rev 36
    Reverse comparison

Rev 35 → Rev 36

/cpp/dblrev_tb.cpp File deleted
/cpp/dblstage_tb.cpp File deleted
/cpp/Makefile
6,15 → 6,14
##
## Purpose: This programs the build process for the test benches
## associated with the double clocked FFT project. These
## test benches are designed for the size and arguments of the
## FFT as given by the Makefile in the trunk/sw directory,
## although they shouldn't be too difficult to modify for
## other FFT parameters.
## test benches are designed for the size and arguments of the FFT as
## given by the Makefile in the trunk/sw directory, although they shouldn't
## be too difficult to modify for other FFT parameters.
##
## Please note that running these test benches requires access
## to the *cmem_*.hex files found in trunk/sw/fft-core. I
## usually soft link them into this directory, but such linking
## is not currently part of this makefile or the build scripts.
## Please note that running these test benches requires access to the
## *cmem_*.hex files found in trunk/rtl. I usually soft link
## them into this directory, but such linking is not currently part of
## this makefile or the build scripts.
##
## Creator: Dan Gisselquist, Ph.D.
## Gisselquist Technology, LLC
21,7 → 20,7
##
##########################################################################/
##
## 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
## modify it under the terms of the GNU General Public License as published
43,10 → 42,11
##
##
##########################################################################/
all: mpy_tb dblrev_tb dblstage_tb qtrstage_tb fft_tb test
all: mpy_tb bitreverse_tb hwbfly_tb butterfly_tb fftstage_tb fft_tb
all: qtrstage_tb laststage_tb test
 
OBJDR:= ../../sw/fft-core/obj_dir
VSRCD = ../../sw/fft-core
OBJDR:= ../../rtl/obj_dir
VSRCD = ../../rtl
TBODR:= ../rtl/obj_dir
ifneq ($(VERILATOR_ROOT),)
VERILATOR:=$(VERILATOR_ROOT)/bin/verilator
60,24 → 60,25
VINC := -I$(VROOT)/include -I$(OBJDR)/ -I$(TBODR)/
# MPYLB:= $(OBJDR)/Vshiftaddmpy__ALL.a
MPYLB:= $(OBJDR)/Vlongbimpy__ALL.a
DBLRV:= $(OBJDR)/Vdblreverse__ALL.a
DBLSG:= $(OBJDR)/Vdblstage__ALL.a
BTREV:= $(OBJDR)/Vbitreverse__ALL.a
STAGE:= $(OBJDR)/Vfftstage__ALL.a
QTRSG:= $(OBJDR)/Vqtrstage__ALL.a
LSTSG:= $(OBJDR)/Vlaststage__ALL.a
BFLYL:= $(OBJDR)/Vbutterfly__ALL.a
HWBFY:= $(OBJDR)/Vhwbfly__ALL.a
FFTLB:= $(OBJDR)/Vfftmain__ALL.a
IFTLB:= $(TBODR)/Vifft_tb__ALL.a
STGLB:= $(OBJDR)/Vfftstage_o2048__ALL.a
STGLB:= $(OBJDR)/Vfftstage__ALL.a
VSRCS:= $(VROOT)/include/verilated.cpp $(VROOT)/include/verilated_vcd_c.cpp
 
mpy_tb: mpy_tb.cpp fftsize.h twoc.h $(MPYLB)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(MPYLB) $(VSRCS) -o $@
 
dblrev_tb: dblrev_tb.cpp twoc.cpp twoc.h fftsize.h $(DBLRV)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(DBLRV) $(VSRCS) -o $@
bitreverse_tb: bitreverse_tb.cpp twoc.cpp twoc.h fftsize.h $(BTREV)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(BTREV) $(VSRCS) -o $@
 
dblstage_tb: dblstage_tb.cpp twoc.cpp twoc.h $(DBLSG)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(DBLSG) $(VSRCS) -o $@
laststage_tb: laststage_tb.cpp twoc.cpp twoc.h $(LSTSG)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(LSTSG) $(VSRCS) -o $@
 
qtrstage_tb: qtrstage_tb.cpp twoc.cpp twoc.h $(QTRSG)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(QTRSG) $(VSRCS) -o $@
88,7 → 89,7
hwbfly_tb: hwbfly_tb.cpp twoc.cpp twoc.h $(HWBFY)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(HWBFY) $(VSRCS) -o $@
 
fftstage_o2048_tb: fftstage_o2048_tb.cpp twoc.cpp twoc.h $(STGLB)
fftstage_tb: fftstage_tb.cpp twoc.cpp twoc.h $(STGLB)
g++ -g $(VINC) $(VDEFS) $< twoc.cpp $(STGLB) $(VSRCS) -o $@
 
fft_tb: fft_tb.cpp twoc.cpp twoc.h fftsize.h $(FFTLB)
112,22 → 113,22
ln -s $(VSRCD)/*.hex .
 
.PHONY: test
test: mpy_tb dblrev_tb dblstage_tb qtrstage_tb butterfly_tb fftstage_o2048_tb
test: mpy_tb bitreverse_tb fftstage_tb qtrstage_tb butterfly_tb fftstage_tb
test: fft_tb ifft_tb hwbfly_tb
./mpy_tb
./dblrev_tb
./dblstage_tb
./qtrstage_tb
./bitreverse_tb
./fftstage_tb
echo ./qtrstage_tb
./butterfly_tb
./hwbfly_tb
./fftstage_o2048_tb
./fftstage_tb
./fft_tb
./ifft_tb
 
.PHONY: clean
clean:
rm -f mpy_tb dblrev_tb dblstage_tb qtrstage_tb butterfly_tb
rm -f fftstage_o2048_tb fft_tb ifft_tb hwbfly_tb
rm -f mpy_tb bitreverse_tb fftstage_tb qtrstage_tb butterfly_tb
rm -f fftstage_tb fft_tb ifft_tb hwbfly_tb
rm -rf fft_tb.dbl ifft_tb.dbl
rm -rf *cmem_*.hex
 
/cpp/README.md
0,0 → 1,18
Here are the bench tests for the pipelined FFT. In general, there's a
`*_tb.cpp` file corresponding to every unit within the FFT. Feel free to
try them.
 
Be aware, however, the [fft_tb](fft_tb.cpp) doesn't truly
check for success--I just haven't gotten to the point of verifying that
the FFT result is *close enough* to the right answer in spite of actually
calculating the right answer. Instead, it creates a data file that can be
read in Octave via [fft_tb.m](fft_tb.m). That will show the first test output.
The second and subsequent outputs can be read via `k=k+1;` followed by calling
[plottst](plottst.m).
 
As another note (before I clean things up more), you'll need the `*.hex` files
in the same directory as the one you call [fft_tb](fft_tb.cpp) or
[fftstage_tb](fftstage_tb.cpp) from.
 
I expect the IFFT will work: it's just an FFT with conjugate twiddle factors,
although I haven't fully tested it yet.
/cpp/bitreverse_tb.cpp
0,0 → 1,235
////////////////////////////////////////////////////////////////////////////
//
// Filename: snglbrev_tb.cpp
//
// Project: A General Purpose Pipelined FFT Implementation
//
// Purpose: A test-bench for the bitreversal stage of the pipelined
// FFT. This file may be run autonomously. If so, the last line
// output will either read "SUCCESS" on success, or some other failure
// message otherwise.
//
// This file depends upon verilator to both compile, run, and therefore
// test either snglbrev.v or dblreverse.v--depending on whether or not the
// FFT handles one or two inputs per clock respectively.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2018, 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 "verilated.h"
#include "verilated_vcd_c.h"
 
#include "fftsize.h"
#include "Vbitreverse.h"
 
#define FFTBITS TST_DBLREVERSE_LGSIZE
#define FFTSIZE (1<<(FFTBITS))
#define FFTMASK (FFTSIZE-1)
#define DATALEN (1<<(FFTBITS+1))
#define DATAMSK (DATALEN-1)
#define PAGEMSK (FFTSIZE)
 
#ifdef NEW_VERILATOR
#define VVAR(A) bitreverse__DOT_ ## A
#else
#define VVAR(A) v__DOT_ ## A
#endif
 
typedef Vbitreverse TSTCLASS;
 
#define iaddr VVAR(_wraddr)
#define in_reset VVAR(_in_reset)
 
VerilatedVcdC *trace = NULL;
uint64_t m_tickcount = 0;
 
void tick(TSTCLASS *brev) {
m_tickcount++;
 
brev->i_clk = 0;
brev->eval();
if (trace) trace->dump((uint64_t)(10ul*m_tickcount-2));
brev->i_clk = 1;
brev->eval();
if (trace) trace->dump((uint64_t)(10ul*m_tickcount));
brev->i_clk = 0;
brev->eval();
if (trace) {
trace->dump((uint64_t)(10ul*m_tickcount+5));
trace->flush();
}
 
brev->i_ce = 0;
}
 
void cetick(TSTCLASS *brev) {
brev->i_ce = 1;
tick(brev);
if (rand()&1) {
brev->i_ce = 1;
tick(brev);
}
}
 
void reset(TSTCLASS *brev) {
brev->i_ce = 0;
brev->i_reset = 1;
tick(brev);
brev->i_ce = 0;
brev->i_reset = 0;
tick(brev);
}
 
unsigned long bitrev(const int nbits, const unsigned long vl) {
unsigned long r = 0;
unsigned long val = vl;
 
for(int k=0; k<nbits; k++) {
r <<= 1;
r |= (val & 1);
val >>= 1;
}
 
return r;
}
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
Verilated::traceEverOn(true);
TSTCLASS *brev = new TSTCLASS;
int syncd = 0;
unsigned long datastore[DATALEN], dataidx=0;
const int BREV_OFFSET = 0;
 
trace = new VerilatedVcdC;
brev->trace(trace, 99);
trace->open("bitreverse_tb.vcd");
 
reset(brev);
 
printf("FFTSIZE = %08x\n", FFTSIZE);
printf("FFTMASK = %08x\n", FFTMASK);
printf("DATALEN = %08x\n", DATALEN);
printf("DATAMSK = %08x\n", DATAMSK);
 
for(int k=0; k<4*(FFTSIZE); k++) {
brev->i_ce = 1;
#ifdef DBLCLKFFT
brev->i_in_0 = 2*k;
brev->i_in_1 = 2*k+1;
datastore[(dataidx++)&(DATAMSK)] = brev->i_in_0;
datastore[(dataidx++)&(DATAMSK)] = brev->i_in_1;
#else
brev->i_in = k;
datastore[(dataidx++)&(DATAMSK)] = brev->i_in;
#endif
tick(brev);
 
printf("k=%3d: IN = %6lx, OUT = %6lx, SYNC = %d\t(%2x) %d\n",
k, brev->i_in, brev->o_out, brev->o_sync,
brev->iaddr, brev->in_reset);
 
if ((k>BREV_OFFSET)&&((BREV_OFFSET==(k&FFTMASK))?1:0) != brev->o_sync) {
fprintf(stdout, "FAIL, BAD SYNC (k = %d > %d)\n", k, BREV_OFFSET);
exit(EXIT_FAILURE);
} else if (brev->o_sync) {
syncd = 1;
}
if ((syncd)&&((brev->o_out&FFTMASK) != bitrev(FFTBITS, k-BREV_OFFSET))) {
fprintf(stdout, "FAIL: BITREV.0 of k (%2x) = %2lx, not %2lx\n",
k, brev->o_out, bitrev(FFTBITS, (k-BREV_OFFSET)));
exit(EXIT_FAILURE);
}
}
 
for(int k=0; k<4*(FFTSIZE); k++) {
brev->i_ce = 1;
#ifdef DBLCLKFFT
brev->i_in_0 = rand() & 0x0ffffff;
brev->i_in_1 = rand() & 0x0ffffff;
datastore[(dataidx++)&(DATAMSK)] = brev->i_in_0;
datastore[(dataidx++)&(DATAMSK)] = brev->i_in_1;
#else
brev->i_in = rand() & 0x0ffffff;
datastore[(dataidx++)&(DATAMSK)] = brev->i_in;
#endif
tick(brev);
 
#ifdef DBLCLKFFT
printf("k=%3d: IN = %6lx : %6lx, OUT = %6lx : %6lx, SYNC = %d\n",
k, brev->i_in_0, brev->i_in_1,
brev->o_out_0, brev->o_out_1, brev->o_sync);
#else
printf("k=%3d: IN = %6lx, OUT = %6lx, SYNC = %d\n",
k, brev->i_in, brev->o_out, brev->o_sync);
#endif
 
if (brev->o_sync)
syncd = 1;
#ifdef DBLCLKFFT
if ((syncd)&&(brev->o_out_0 != datastore[(((dataidx-2-FFTSIZE)&PAGEMSK) + bitrev(FFTBITS, (dataidx-FFTSIZE-2)&FFTMASK))])) {
fprintf(stdout, "FAIL: BITREV.0 of k (%2x) = %2lx, not %2lx (expected %lx -> %lx)\n",
k, brev->o_out_0,
datastore[(((dataidx-2-FFTSIZE)&PAGEMSK)
+ bitrev(FFTBITS, (dataidx-FFTSIZE-2)&FFTMASK))],
(dataidx-2)&DATAMSK,
(((dataidx-2)&PAGEMSK)
+ bitrev(FFTBITS, (dataidx-FFTSIZE-2)&FFTMASK)));
// exit(-1);
}
 
if ((syncd)&&(brev->o_out_1 != datastore[(((dataidx-2-FFTSIZE)&PAGEMSK) + bitrev(FFTBITS, (dataidx-FFTSIZE-1)&FFTMASK))])) {
fprintf(stdout, "FAIL: BITREV.1 of k (%2x) = %2lx, not %2lx (expected %lx)\n",
k, brev->o_out_1,
datastore[(((dataidx-2-FFTSIZE)&PAGEMSK)
+ bitrev(FFTBITS, (dataidx-FFTSIZE-1)&FFTMASK))],
(((dataidx-1)&PAGEMSK)
+ bitrev(FFTBITS, (dataidx-FFTSIZE-1)&FFTMASK)));
// exit(-1);
}
#else
if ((syncd)&&(brev->o_out != datastore[
(((dataidx-1-FFTSIZE)&PAGEMSK)
+ bitrev(FFTBITS,
(dataidx-FFTSIZE-1)&FFTMASK))])) {
fprintf(stdout, "FAIL: BITREV.0 of k (%2x) = %2lx, not %2lx (expected %lx -> %lx)\n",
k, brev->o_out,
datastore[(((dataidx-1-FFTSIZE)&PAGEMSK)
+ bitrev(FFTBITS, (dataidx-FFTSIZE-1)&FFTMASK))],
(dataidx-2)&DATAMSK,
(((dataidx-2)&PAGEMSK)
+ bitrev(FFTBITS, (dataidx-FFTSIZE-1)&FFTMASK)));
exit(EXIT_FAILURE);
}
#endif
}
 
delete brev;
 
printf("SUCCESS!\n");
exit(0);
}
/cpp/butterfly_tb.cpp
4,13 → 4,13
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: A test-bench for the butterfly.v subfile of the double
// clocked FFT. This file may be run autonomously. If so,
// the last line output will either read "SUCCESS" on success,
// or some other failure message otherwise.
// Purpose: A test-bench for the butterfly.v subfile of the generic
// pipelined FFT. This file may be run autonomously. If so,
// the last line output will either read "SUCCESS" on success, or some
// other failure message otherwise.
//
// This file depends upon verilator to both compile, run, and
// therefore test butterfly.v
// This file depends upon verilator to both compile, run, and therefore
// test butterfly.v
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
17,7 → 17,7
//
///////////////////////////////////////////////////////////////////////////
//
// 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
// modify it under the terms of the GNU General Public License as published
42,11 → 42,18
#include <stdio.h>
#include <stdint.h>
 
#include "fftsize.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vbutterfly.h"
#include "verilated.h"
#include "twoc.h"
#include "fftsize.h"
 
#ifdef NEW_VERILATOR
#define VVAR(A) butterfly__DOT__ ## A
#else
#define VVAR(A) v__DOT_ ## A
#endif
 
#define IWIDTH TST_BUTTERFLY_IWIDTH
#define CWIDTH TST_BUTTERFLY_CWIDTH
#define OWIDTH TST_BUTTERFLY_OWIDTH
55,24 → 62,55
class BFLY_TB {
public:
Vbutterfly *m_bfly;
VerilatedVcdC *m_trace;
unsigned long m_left[64], m_right[64];
bool m_aux[64];
int m_addr, m_lastaux, m_offset;
bool m_syncd, m_waiting_for_sync_input;
uint64_t m_tickcount;
 
BFLY_TB(void) {
Verilated::traceEverOn(true);
m_trace = NULL;
m_bfly = new Vbutterfly;
m_addr = 0;
m_syncd = 0;
m_tickcount = 0;
m_waiting_for_sync_input = true;
}
 
void opentrace(const char *vcdname) {
if (!m_trace) {
m_trace = new VerilatedVcdC;
m_bfly->trace(m_trace, 99);
m_trace->open(vcdname);
}
}
 
void closetrace(void) {
if (m_trace) {
m_trace->close();
delete m_trace;
m_trace = NULL;
}
}
 
void tick(void) {
m_tickcount++;
 
m_lastaux = m_bfly->o_aux;
m_bfly->i_clk = 0;
m_bfly->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount-2));
m_bfly->i_clk = 1;
m_bfly->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount));
m_bfly->i_clk = 0;
m_bfly->eval();
if (m_trace) {
m_trace->dump((uint64_t)(10ul*m_tickcount+5));
m_trace->flush();
}
 
if ((!m_syncd)&&(m_bfly->o_aux))
m_offset = m_addr;
79,14 → 117,33
m_syncd = (m_syncd) || (m_bfly->o_aux);
}
 
void cetick(void) {
int ce = m_bfly->i_ce, nkce;
 
tick();
 
nkce = (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
 
if ((ce)&&(nkce > 0)) {
m_bfly->i_ce = 0;
for(int kce=0; kce<nkce-1; kce++)
tick();
}
 
m_bfly->i_ce = ce;
}
 
void reset(void) {
m_bfly->i_ce = 0;
m_bfly->i_rst = 1;
m_bfly->i_reset = 1;
m_bfly->i_coef = 0l;
m_bfly->i_left = 0;
m_bfly->i_right = 0;
tick();
m_bfly->i_rst = 0;
m_bfly->i_reset = 0;
m_bfly->i_ce = 1;
//
// Let's run a RESET test here, forcing the whole butterfly
93,19 → 150,18
// to be filled with aux=1. If the reset works right,
// we'll never get an aux=1 output.
//
m_bfly->i_rst = 1;
m_bfly->i_reset = 1;
m_bfly->i_aux = 1;
for(int i=0; i<200; i++) {
m_bfly->i_ce = 1;
tick();
}
m_bfly->i_ce = 1;
for(int i=0; i<200; i++)
cetick();
 
// Now here's the RESET line, so let's see what the test does
m_bfly->i_rst = 1;
m_bfly->i_reset = 1;
m_bfly->i_ce = 1;
m_bfly->i_aux = 1;
tick();
m_bfly->i_rst = 0;
cetick();
m_bfly->i_reset = 0;
m_syncd = 0;
 
m_waiting_for_sync_input = true;
124,41 → 180,42
}
 
m_bfly->i_ce = 1;
tick();
cetick();
 
if ((m_bfly->o_aux)&&(!m_lastaux))
printf("\n");
printf("n,k=%d,%3d: COEF=%010lx, LFT=%08x, RHT=%08x, A=%d, OLFT =%09lx, ORHT=%09lx, AUX=%d\n",
printf("n,k=%d,%3d: COEF=%0*lx, LFT=%0*x, RHT=%0*x, A=%d, OLFT =%0*lx, ORHT=%0*lx, AUX=%d\n",
n,k,
m_bfly->i_coef & (~(-1l<<40)),
m_bfly->i_left,
m_bfly->i_right,
(2*CWIDTH+3)/4, ubits(m_bfly->i_coef, 2*CWIDTH),
(2*IWIDTH+3)/4, m_bfly->i_left,
(2*IWIDTH+3)/4, m_bfly->i_right,
m_bfly->i_aux,
m_bfly->o_left,
m_bfly->o_right,
(2*OWIDTH+3)/4, (long)m_bfly->o_left,
(2*OWIDTH+3)/4, (long)m_bfly->o_right,
m_bfly->o_aux);
 
if ((m_syncd)&&(m_left[(m_addr-m_offset)&(64-1)] != m_bfly->o_left)) {
printf("WRONG O_LEFT! (%lx(exp) != %lx(sut))\n",
printf("WRONG O_LEFT! (%lx(exp) != %lx(sut)\n",
m_left[(m_addr-m_offset)&(64-1)],
m_bfly->o_left);
exit(-1);
(long)m_bfly->o_left);
exit(EXIT_FAILURE);
}
 
if ((m_syncd)&&(m_right[(m_addr-m_offset)&(64-1)] != m_bfly->o_right)) {
printf("WRONG O_RIGHT (%10lx(exp) != (%10lx(sut))!\n",
m_right[(m_addr-m_offset)&(64-1)], m_bfly->o_right);
exit(-1);
printf("WRONG O_RIGHT! (%lx(exp) != %lx(sut))\n",
m_right[(m_addr-m_offset)&(64-1)],
(long)m_bfly->o_right);
exit(EXIT_FAILURE);
}
 
if ((m_syncd)&&(m_aux[(m_addr-m_offset)&(64-1)] != m_bfly->o_aux)) {
printf("FAILED AUX CHANNEL TEST (i.e. the SYNC)\n");
exit(-1);
exit(EXIT_FAILURE);
}
 
if ((m_addr > TST_BUTTERFLY_MPYDELAY+6)&&(!m_syncd)) {
printf("NO SYNC PULSE!\n");
// exit(-1);
exit(EXIT_FAILURE);
}
 
// Now, let's calculate an "expected" result ...
241,6 → 298,18
}
};
 
long gentestword(int w, int al, int ar) {
unsigned long lo, hi, r;
hi = ((unsigned long)(al&0x0c))<<(w-4);
hi += (al&3)-2ul;
 
lo = ((unsigned long)(ar&0x0c))<<(w-4);
lo += (ar&3)-2ul;
 
r = (ubits(hi, w) << w) | (ubits(lo, w));
return r;
}
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
BFLY_TB *bfly = new BFLY_TB;
251,13 → 320,32
 
const int TESTSZ = 256;
 
bfly->opentrace("butterfly.vcd");
 
bfly->reset();
 
// #define ZEROTEST
#define ZEROTEST bfly->test(9,0,0x0000000000l,0x00000000,0x00000000, 0)
// Test whether or not the aux channel starts clear, like its supposed to
 
bfly->test(9,0,0x4000000000l,0x000f0000,0x00000000, 1);
ZEROTEST;
ZEROTEST;
bfly->test(9,0,0x4000000000l,0x00000000,0x000f0000, 0);
ZEROTEST;
ZEROTEST;
bfly->test(9,0,0x4000000000l,0x000f0000,0x000f0000, 0);
ZEROTEST;
ZEROTEST;
bfly->test(9,1,0x4000000000l,0x000f0000,0xfff10000, 0);
ZEROTEST;
ZEROTEST;
bfly->test(9,2,0x4000000000l,0x0000000f,0x0000fff1, 0);
ZEROTEST;
ZEROTEST;
bfly->test(9,3,0x4000000000l,0x0000000f,0x0000000f, 0);
ZEROTEST;
ZEROTEST;
 
bfly->test(9,0,0x4000000000l,0x7fff0000,0x7fff0000, 1);
bfly->test(9,1,0x4000000000l,0x7fff0000,0x80010000, 0);
337,6 → 425,30
bfly->test(n,k, cof, lft, rht, aux);
}
 
int k = TESTSZ;
// Exhaustively test
#if (4*IWIDTH+2*CWIDTH <= 24)
for(int a=0; a<(1<<(2*IWIDTH)); a++)
for(int b=0; b<(1<<(2*IWIDTH)); b++)
for(int c=0; c<(1<<(2*CWIDTH)); c++)
bfly->test(0, k++, c, a, b, 0);
 
printf("Exhaust complete\n");
#else
for(int al=0; al<16; al++)
for(int ar=0; ar<16; ar++)
for(int bl=0; bl<16; bl++)
for(int br=0; br<16; br++)
for(int cl=0; cl<16; cl++)
for(int cr=0; cr<16; cr++) {
long a = gentestword(IWIDTH, al, ar);
long b = gentestword(IWIDTH, bl, br);
long c = gentestword(CWIDTH, cl, cr);
bfly->test(0, k++, c, a, b, 0);
}
printf("Partial exhaust complete\n");
#endif
 
delete bfly;
 
printf("SUCCESS!\n");
/cpp/fft_tb.cpp
5,12 → 5,11
//
// Purpose: A test-bench for the main program, fftmain.v, of the double
// clocked FFT. This file may be run autonomously (when
// fully functional). If so, the last line output will either
// read "SUCCESS" on success, or some other failure message
// otherwise.
// fully functional). If so, the last line output will either read
// "SUCCESS" on success, or some other failure message otherwise.
//
// This file depends upon verilator to both compile, run, and
// therefore test fftmain.v
// This file depends upon verilator to both compile, run, and therefore
// test fftmain.v
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
17,7 → 16,7
//
///////////////////////////////////////////////////////////////////////////
//
// 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
// modify it under the terms of the GNU General Public License as published
40,10 → 39,12
//
///////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fftw3.h>
 
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vfftmain.h"
#include "twoc.h"
 
56,8 → 57,11
#define VVAR(A) v__DOT_ ## A
#endif
 
 
#ifdef DBLCLKFFT
#define revstage_iaddr VVAR(_revstage__DOT__iaddr)
#else
#define revstage_iaddr VVAR(_revstage__DOT__wraddr)
#endif
#define br_sync VVAR(_br_sync)
#define br_started VVAR(_r_br_started)
#define w_s2048 VVAR(_w_s2048)
119,9 → 123,11
double *m_fft_buf;
bool m_syncd;
unsigned long m_tickcount;
VerilatedVcdC* m_trace;
 
FFT_TB(void) {
m_fft = new Vfftmain;
Verilated::traceEverOn(true);
m_iaddr = m_oaddr = 0;
m_dumpfp = NULL;
 
131,39 → 137,75
FFTW_FORWARD, FFTW_MEASURE);
m_syncd = false;
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) {
if ((!m_fft->i_ce)||(m_fft->i_rst))
m_tickcount++;
if (m_fft->i_reset)
printf("TICK(%s,%s)\n",
(m_fft->i_rst)?"RST":" ",
(m_fft->i_reset)?"RST":" ",
(m_fft->i_ce)?"CE":" ");
 
m_fft->i_clk = 0;
m_fft->eval();
if (m_trace)
m_trace->dump((vluint64_t)(10*m_tickcount-2));
m_fft->i_clk = 1;
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();
 
/*
int nrpt = (rand()&0x01f) + 1;
m_fft->i_ce = 0;
for(int i=0; i<nrpt; i++) {
m_fft->i_clk = 0;
m_fft->eval();
m_fft->i_clk = 1;
m_fft->eval();
nkce = (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
if ((ce)&&(nkce>0)) {
m_fft->i_ce = 0;
for(int kce=1; kce < nkce; kce++)
tick();
}
*/
 
m_fft->i_ce = ce;
}
 
void reset(void) {
m_fft->i_ce = 0;
m_fft->i_rst = 1;
m_fft->i_reset = 1;
tick();
m_fft->i_rst = 0;
m_fft->i_reset = 0;
tick();
 
m_iaddr = m_oaddr = m_logbase = 0;
254,18 → 296,19
printf("%3d : SCALE = %12.6f, WT = %18.1f, ISQ = %15.1f, ",
m_ntest, scale, wt, isq);
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) {
printf("TEST FAIL!! Result is out of bounds from ");
printf("expected result with FFTW3.\n");
// exit(-2);
// exit(EXIT_FAILURE);
}
m_ntest++;
}
 
#ifdef DBLCLKFFT
bool test(ITYP lft, ITYP rht) {
m_fft->i_ce = 1;
m_fft->i_rst = 0;
m_fft->i_reset = 0;
m_fft->i_left = lft;
m_fft->i_right = rht;
 
272,7 → 315,7
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = lft;
m_log[(m_iaddr++)&(NFTLOG*FFTLEN-1)] = rht;
 
tick();
cetick();
 
if (m_fft->o_sync) {
if (!m_syncd) {
339,7 → 382,81
 
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) {
ITYP ilft, irht, ilft_r, ilft_i, irht_r, irht_i;
 
351,7 → 468,12
ilft = (ilft_r << IWIDTH) | ilft_i;
irht = (irht_r << IWIDTH) | irht_i;
 
#ifdef DBLCLKFFT
return test(ilft, irht);
#else
test(ilft);
return test(irht);
#endif
}
 
double rdata(int addr) {
405,6 → 527,7
exit(-1);
}
 
fft->opentrace("fft.vcd");
fft->reset();
 
{
414,7 → 537,8
fft->dump(fpout);
 
// 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++)
fft->test(0.0,0.0,0.0,0.0);
 
422,27 → 546,27
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;
cl = cos(W * (2*k )) * (double)((1l<<(IWIDTH-2))-1l);
sl = sin(W * (2*k )) * (double)((1l<<(IWIDTH-2))-1l);
cr = cos(W * (2*k+1)) * (double)((1l<<(IWIDTH-2))-1l);
sr = sin(W * (2*k+1)) * (double)((1l<<(IWIDTH-2))-1l);
fft->test(cl, sl, cr, sr);
}
 
// 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++)
fft->test(0.0,0.0,0.0,0.0);
 
// 3.
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++)
fft->test(0.0,0.0,0.0,0.0);
 
// 4.
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++)
fft->test(0.0,0.0,0.0,0.0);
 
449,7 → 573,7
// 5.
if (FFTLEN/2 >= 16) {
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++)
fft->test(0.0,0.0,0.0,0.0);
}
457,7 → 581,7
// 6.
if (FFTLEN/2 >= 32) {
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++)
fft->test(0.0,0.0,0.0,0.0);
}
465,7 → 589,7
// 7.
if (FFTLEN/2 >= 64) {
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++)
fft->test(0.0,0.0,0.0,0.0);
}
472,7 → 596,7
 
if (FFTLEN/2 >= 128) {
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++)
fft->test(0.0,0.0,0.0,0.0);
}
479,7 → 603,7
 
if (FFTLEN/2 >= 256) {
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++)
fft->test(0.0,0.0,0.0,0.0);
}
486,7 → 610,7
 
if (FFTLEN/2 >= 512) {
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++)
fft->test(0.0,0.0,0.0,0.0);
}
603,22 → 727,22
 
// 65.
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.
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.
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.
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.
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.
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)
fft->test(16384.0, 0.0, 0.0, 0.0);
722,8 → 846,16
 
fclose(fpout);
 
if (!fft->m_syncd) {
printf("FAIL -- NO SYNC\n");
goto test_failure;
}
 
printf("SUCCESS!!\n");
exit(0);
test_failure:
printf("TEST FAILED!!\n");
exit(0);
}
 
 
/cpp/fftstage_tb.cpp
0,0 → 1,369
////////////////////////////////////////////////////////////////////////////////
//
// Filename: fftstage_tb.cpp
//
// Project: A General Purpose Pipelined FFT Implementation
//
// Purpose: A test-bench for a generic FFT stage which has been
// instantiated by fftgen. Without loss of (much) generality,
// we'll examine the 2048 fftstage.v. This file may be run autonomously.
// If so, the last line output will either read "SUCCESS" on success, or
// some other failure message otherwise. Likewise the exit code will
// also indicate success (exit(0)) or failure (anything else).
//
// This file depends upon verilator to both compile, run, and therefore
// test fftstage.v. Also, you'll need to place a copy of the cmem_*2048
// hex file into the directory where you run this test bench.
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2018, 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 "Vfftstage.h"
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "twoc.h"
#include "fftsize.h"
 
 
#ifdef NEW_VERILATOR
#define VVAR(A) fftstage__DOT_ ## A
#else
#define VVAR(A) v__DOT_ ## A
#endif
 
#define cmem VVAR(_cmem)
#define iaddr VVAR(_iaddr)
 
#define FFTBITS (FFT_LGWIDTH)
#define FFTLEN (1<<FFTBITS)
#define FFTSIZE FFTLEN
#define FFTMASK (FFTLEN-1)
#define IWIDTH FFT_IWIDTH
#define CWIDTH 20
#define OWIDTH (FFT_IWIDTH+1)
#define BFLYSHIFT 0
#define LGWIDTH (FFT_LGWIDTH)
#ifdef DBLCLKFFT
#define LGSPAN (LGWIDTH-2)
#else
#define LGSPAN (LGWIDTH-1)
#endif
#define ROUND true
 
#define SPANLEN (1<<LGSPAN)
#define SPANMASK (SPANLEN-1)
#define DBLSPANLEN (1<<(LGSPAN+4))
#define DBLSPANMASK (DBLSPANLEN-1)
 
class FFTSTAGE_TB {
public:
Vfftstage *m_ftstage;
VerilatedVcdC *m_trace;
long m_oaddr, m_iaddr;
long m_vals[SPANLEN], m_out[DBLSPANLEN];
bool m_syncd;
int m_offset;
uint64_t m_tickcount;
 
FFTSTAGE_TB(void) {
Verilated::traceEverOn(true);
m_ftstage = new Vfftstage;
m_syncd = false;
m_iaddr = m_oaddr = 0;
m_offset = 0;
m_tickcount = 0;
}
 
void opentrace(const char *vcdname) {
if (!m_trace) {
m_trace = new VerilatedVcdC;
m_ftstage->trace(m_trace, 99);
m_trace->open(vcdname);
}
}
 
void closetrace(void) {
if (m_trace) {
m_trace->close();
delete m_trace;
m_trace = NULL;
}
}
 
void tick(void) {
m_tickcount++;
 
m_ftstage->i_clk = 0;
m_ftstage->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount-2));
m_ftstage->i_clk = 1;
m_ftstage->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount));
m_ftstage->i_clk = 0;
m_ftstage->eval();
if (m_trace) {
m_trace->dump((uint64_t)(10ul*m_tickcount+5));
m_trace->flush();
}
}
 
void cetick(void) {
int ce = m_ftstage->i_ce, nkce;
 
tick();
nkce = 0; // (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
if ((ce)&&(nkce > 0)) {
m_ftstage->i_ce = 0;
for(int kce = 1; kce < nkce; kce++)
tick();
}
 
m_ftstage->i_ce = ce;
}
 
void reset(void) {
m_ftstage->i_ce = 0;
m_ftstage->i_reset = 1;
tick();
 
// Let's give it several ticks with no sync
m_ftstage->i_ce = 0;
m_ftstage->i_reset = 0;
for(int i=0; i<8192; i++) {
m_ftstage->i_data = rand();
m_ftstage->i_sync = 0;
m_ftstage->i_ce = 1;
 
cetick();
 
assert(m_ftstage->o_sync == 0);
}
 
m_iaddr = 0;
m_oaddr = 0;
m_offset = 0;
m_syncd = false;
}
 
void butterfly(const long cv, const long lft, const long rht,
long &o_lft, long &o_rht) {
long cv_r, cv_i;
long lft_r, lft_i, rht_r, rht_i;
long o_lft_r, o_lft_i, o_rht_r, o_rht_i;
 
cv_r = sbits(cv>>CWIDTH, CWIDTH);
cv_i = sbits(cv, CWIDTH);
 
lft_r = sbits(lft>>IWIDTH, IWIDTH);
lft_i = sbits(lft, IWIDTH);
 
rht_r = sbits(rht>>IWIDTH, IWIDTH);
rht_i = sbits(rht, IWIDTH);
 
o_lft_r = lft_r + rht_r;
o_lft_i = lft_i + rht_i;
 
o_lft_r &= (~(-1l << OWIDTH));
o_lft_i &= (~(-1l << OWIDTH));
 
// o_lft_r >>= 1;
// o_lft_i >>= 1;
o_lft = (o_lft_r << OWIDTH) | (o_lft_i);
 
o_rht_r = (cv_r * (lft_r-rht_r)) - (cv_i * (lft_i-rht_i));
o_rht_i = (cv_r * (lft_i-rht_i)) + (cv_i * (lft_r-rht_r));
 
if (ROUND) {
if (o_rht_r & (1<<(CWIDTH-3)))
o_rht_r += (1<<(CWIDTH-3))-1;
if (o_rht_i & (1<<(CWIDTH-3)))
o_rht_i += (1<<(CWIDTH-3))-1;
}
 
o_rht_r >>= (CWIDTH-2);
o_rht_i >>= (CWIDTH-2);
 
o_rht_r &= (~(-1l << OWIDTH));
o_rht_i &= (~(-1l << OWIDTH));
o_rht = (o_rht_r << OWIDTH) | (o_rht_i);
 
/*
printf("%10lx %10lx %10lx -> %10lx %10lx\n",
cv & ((1l<<(2*CWIDTH))-1l),
lft & ((1l<<(2*IWIDTH))-1l),
rht & ((1l<<(2*IWIDTH))-1l),
o_lft & ((1l<<(2*OWIDTH))-1l),
o_rht & ((1l<<(2*OWIDTH))-1l));
*/
}
 
void test(bool i_sync, long i_data) {
long cv;
bool bc;
int raddr;
bool failed = false;
 
m_ftstage->i_reset = 0;
m_ftstage->i_ce = 1;
m_ftstage->i_sync = i_sync;
i_data &= (~(-1l<<(2*IWIDTH)));
m_ftstage->i_data = i_data;
 
cv = m_ftstage->cmem[m_iaddr & SPANMASK];
bc = m_iaddr & (1<<LGSPAN);
if (!bc)
m_vals[m_iaddr & (SPANMASK)] = i_data;
else {
int waddr = m_iaddr ^ (1<<LGSPAN);
waddr &= (DBLSPANMASK);
if (m_iaddr & (1<<(LGSPAN+1)))
waddr |= (1<<(LGSPAN));
butterfly(cv, m_vals[m_iaddr & (SPANMASK)], i_data,
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_out[(m_iaddr-SPANLEN)&(DBLSPANMASK)],
m_out[m_iaddr & (DBLSPANMASK)]);
*/
}
 
cetick();
 
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;
 
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)\n",
(long)m_iaddr, (long)m_oaddr,
i_sync, (long)(i_data) & (~(-1l << (2*IWIDTH))),
(long)m_ftstage->o_data,
m_ftstage->o_sync,
 
m_ftstage->iaddr&(FFTMASK>>1),
(long)(m_ftstage->cmem[m_ftstage->iaddr&(SPANMASK>>1)]) & (~(-1l<<(2*CWIDTH))),
(long)m_out[raddr]);
 
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_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], (long)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);
}
};
 
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
FFTSTAGE_TB *ftstage = new FFTSTAGE_TB;
 
printf("Expecting : IWIDTH = %d, CWIDTH = %d, OWIDTH = %d\n",
IWIDTH, CWIDTH, OWIDTH);
 
ftstage->opentrace("fftstage.vcd");
ftstage->reset();
 
// Medium real (constant) value ... just for starters
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x00200000l);
// Medium imaginary (constant) value ... just for starters
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x00000020l);
// Medium sine wave, real
for(int k=1; k<FFTSIZE; k+=2) {
long vl;
vl= (long)(cos(2.0 * M_PI * 1.0 / FFTSIZE * k)*(1l<<30) + 0.5);
vl &= (-1l << 16); // Turn off the imaginary bit portion
vl &= (~(-1l << (IWIDTH*2))); // Turn off unused high order bits
ftstage->test((k==1), vl);
}
// Smallest real value
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x00080000l);
// Smallest imaginary value
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x00000001l);
// Largest real value
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x200000000l);
// Largest negative imaginary value
for(int k=1; k<FFTSIZE; k+=2)
ftstage->test((k==1), 0x000010000l);
// Let's try an impulse
for(int k=0; k<FFTSIZE; k+=2)
ftstage->test((k==0), (k==0)?0x020000000l:0l);
// Now, let's clear out the result
for(int k=0; k<FFTSIZE; k+=2)
ftstage->test((k==0), 0x000000000l);
for(int k=0; k<FFTSIZE; k+=2)
ftstage->test((k==0), 0x000000000l);
for(int k=0; k<FFTSIZE; k+=2)
ftstage->test((k==0), 0x000000000l);
for(int k=0; k<FFTSIZE; k+=2)
ftstage->test((k==0), 0x000000000l);
 
printf("SUCCESS! (Offset = %d)\n", ftstage->m_offset);
delete ftstage;
 
exit(0);
}
/cpp/hwbfly_tb.cpp
1,16 → 1,16
////////////////////////////////////////////////////////////////////////////
//
// Filename: butterfly_tb.cpp
// Filename: hwbfly_tb.cpp
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: A test-bench for the butterfly.v subfile of the double
// clocked FFT. This file may be run autonomously. If so,
// the last line output will either read "SUCCESS" on success,
// or some other failure message otherwise.
// Purpose: A test-bench for the hardware butterfly subfile of the generic
// pipelined FFT. This file may be run autonomously. If so,
// the last line output will either read "SUCCESS" on success, or some
// other failure message otherwise.
//
// This file depends upon verilator to both compile, run, and
// therefore test butterfly.v
// This file depends upon verilator to both compile, run, and therefore
// test hwbfly.v
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
17,7 → 17,7
//
///////////////////////////////////////////////////////////////////////////
//
// 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
// modify it under the terms of the GNU General Public License as published
42,9 → 42,11
#include <stdio.h>
#include <stdint.h>
 
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vhwbfly.h"
#include "verilated.h"
#include "twoc.h"
#include "fftsize.h"
 
#ifdef NEW_VERILATOR
#define VVAR(A) hwbfly__DOT_ ## A
52,27 → 54,65
#define VVAR(A) v__DOT_ ## A
#endif
 
#define IWIDTH TST_BUTTERFLY_IWIDTH
#define CWIDTH TST_BUTTERFLY_CWIDTH
#define OWIDTH TST_BUTTERFLY_OWIDTH
 
class BFLY_TB {
class HWBFLY_TB {
public:
Vhwbfly *m_bfly;
VerilatedVcdC *m_trace;
unsigned long m_left[64], m_right[64];
bool m_aux[64];
int m_addr, m_lastaux, m_offset;
bool m_syncd;
uint64_t m_tickcount;
 
BFLY_TB(void) {
HWBFLY_TB(void) {
Verilated::traceEverOn(true);
m_trace = NULL;
m_bfly = new Vhwbfly;
m_addr = 0;
m_syncd = 0;
m_tickcount = 0;
m_bfly->i_reset = 1;
m_bfly->i_clk = 0;
m_bfly->eval();
m_bfly->i_reset = 0;
}
 
void opentrace(const char *vcdname) {
if (!m_trace) {
m_trace = new VerilatedVcdC;
m_bfly->trace(m_trace, 99);
m_trace->open(vcdname);
}
}
 
void closetrace(void) {
if (m_trace) {
m_trace->close();
delete m_trace;
m_trace = NULL;
}
}
 
void tick(void) {
m_tickcount++;
 
m_lastaux = m_bfly->o_aux;
m_bfly->i_clk = 0;
m_bfly->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount-2));
m_bfly->i_clk = 1;
m_bfly->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount));
m_bfly->i_clk = 0;
m_bfly->eval();
if (m_trace) {
m_trace->dump((uint64_t)(10ul*m_tickcount+5));
m_trace->flush();
}
 
if ((!m_syncd)&&(m_bfly->o_aux))
m_offset = m_addr;
79,14 → 119,33
m_syncd = (m_syncd) || (m_bfly->o_aux);
}
 
void cetick(void) {
int ce = m_bfly->i_ce, nkce;
 
tick();
 
nkce = (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
 
if ((ce)&&(nkce > 0)) {
m_bfly->i_ce = 0;
for(int kce=0; kce<nkce-1; kce++)
tick();
}
 
m_bfly->i_ce = ce;
}
 
void reset(void) {
m_bfly->i_ce = 0;
m_bfly->i_rst = 1;
m_bfly->i_reset = 1;
m_bfly->i_coef = 0l;
m_bfly->i_left = 0;
m_bfly->i_right = 0;
tick();
m_bfly->i_rst = 0;
m_bfly->i_reset = 0;
m_bfly->i_ce = 1;
//
// Let's run a RESET test here, forcing the whole butterfly
93,18 → 152,18
// to be filled with aux=1. If the reset works right,
// we'll never get an aux=1 output.
//
m_bfly->i_rst = 1;
m_bfly->i_reset = 1;
m_bfly->i_aux = 1;
m_bfly->i_ce = 1;
m_bfly->i_aux = 1;
for(int i=0; i<200; i++)
tick();
cetick();
 
// Now here's the RESET line, so let's see what the test does
m_bfly->i_rst = 1;
m_bfly->i_reset = 1;
m_bfly->i_ce = 1;
m_bfly->i_aux = 1;
tick();
m_bfly->i_rst = 0;
cetick();
m_bfly->i_reset = 0;
m_syncd = 0;
}
 
111,13 → 170,13
void test(const int n, const int k, const unsigned long cof,
const unsigned lft, const unsigned rht, const int aux) {
 
m_bfly->i_coef = cof & (~(-1l << 40));
m_bfly->i_left = lft;
m_bfly->i_right = rht;
m_bfly->i_coef = ubits(cof, 2*TST_BUTTERFLY_CWIDTH);
m_bfly->i_left = ubits(lft, 2*TST_BUTTERFLY_IWIDTH);
m_bfly->i_right = ubits(rht, 2*TST_BUTTERFLY_IWIDTH);
m_bfly->i_aux = aux & 1;
 
m_bfly->i_ce = 1;
tick();
cetick();
 
if ((m_bfly->o_aux)&&(!m_lastaux))
printf("\n");
130,30 → 189,49
m_bfly->o_left,
m_bfly->o_right,
m_bfly->o_aux);
#if (FFT_CKPCE == 1)
printf(", p1 = 0x%08lx p2 = 0x%08lx, p3 = 0x%08lx",
#define rp_one VVAR(_CKPCE_ONE__DOT__rp_one)
#define rp_two VVAR(_CKPCE_ONE__DOT__rp_two)
#define rp_three VVAR(_CKPCE_ONE__DOT__rp_three)
m_bfly->rp_one,
m_bfly->rp_two,
m_bfly->rp_three);
#elif (FFT_CKPCE == 2)
#define rp_one VVAR(_genblk1__DOT__CKPCE_TWO__DOT__rp2_one)
#define rp_two VVAR(_genblk1__DOT__CKPCE_TWO__DOT__rp_two)
#define rp_three VVAR(_genblk1__DOT__CKPCE_TWO__DOT__rp_three)
printf(", p1 = 0x%08lx p2 = 0x%08lx, p3 = 0x%08lx",
m_bfly->rp_one,
m_bfly->rp_two,
m_bfly->rp_three);
#else
printf("CKPCE = %d\n", FFT_CKPCE);
#endif
 
printf("\n");
 
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",
printf("WRONG O_LEFT! (%lx(exp) != %lx(sut)\n",
m_left[(m_addr-m_offset)&(64-1)],
m_bfly->o_left);
exit(-1);
exit(EXIT_FAILURE);
}
 
if ((m_syncd)&&(m_right[(m_addr-m_offset)&(64-1)] != m_bfly->o_right)) {
fprintf(stderr, "WRONG O_RIGHT! (%lx(exp) != %lx(sut))\n",
m_right[(m_addr-m_offset)&(64-1)],
m_bfly->o_right);
exit(-1);
printf("WRONG O_RIGHT! (%lx(exp) != %lx(sut))\n",
m_right[(m_addr-m_offset)&(64-1)], m_bfly->o_right);
exit(EXIT_FAILURE);
}
 
if ((m_syncd)&&(m_aux[(m_addr-m_offset)&(64-1)] != m_bfly->o_aux)) {
fprintf(stderr, "FAILED AUX CHANNEL TEST (i.e. the SYNC)\n");
exit(-1);
printf("FAILED AUX CHANNEL TEST (i.e. the SYNC)\n");
exit(EXIT_FAILURE);
}
 
if ((m_addr > 22)&&(!m_syncd)) {
fprintf(stderr, "NO SYNC PULSE!\n");
exit(-1);
printf("NO SYNC PULSE!\n");
exit(EXIT_FAILURE);
}
 
// Now, let's calculate an "expected" result ...
160,20 → 238,20
long rlft, ilft;
 
// Extract left and right values ...
rlft = sbits(m_bfly->i_left >> 16, 16);
ilft = sbits(m_bfly->i_left , 16);
rlft = sbits(m_bfly->i_left >> IWIDTH, IWIDTH);
ilft = sbits(m_bfly->i_left , IWIDTH);
 
// Now repeat for the right hand value ...
long rrht, irht;
// Extract left and right values ...
rrht = sbits(m_bfly->i_right >> 16, 16);
irht = sbits(m_bfly->i_right , 16);
rrht = sbits(m_bfly->i_right >> IWIDTH, IWIDTH);
irht = sbits(m_bfly->i_right , IWIDTH);
 
// and again for the coefficients
long rcof, icof;
// Extract left and right values ...
rcof = sbits(m_bfly->i_coef >> 20, 20);
icof = sbits(m_bfly->i_coef , 20);
rcof = sbits(m_bfly->i_coef >> CWIDTH, CWIDTH);
icof = sbits(m_bfly->i_coef , CWIDTH);
 
// Now, let's do the butterfly ourselves ...
long sumi, sumr, difi, difr;
198,9 → 276,12
p2 = difi * icof;
p3 = (difr + difi) * (rcof + icof);
 
mpyr = p1-p2 + (1<<17);
mpyi = p3-p1-p2 + (1<<17);
mpyr = p1-p2;
mpyi = p3-p1-p2;
 
mpyr = rndbits(mpyr, (IWIDTH+2)+(CWIDTH+1), OWIDTH+4);
mpyi = rndbits(mpyi, (IWIDTH+2)+(CWIDTH+1), OWIDTH+4);
 
/*
printf("RC=%lx, IC=%lx, ", rcof, icof);
printf("P1=%lx,P2=%lx,P3=%lx, ", p1,p2,p3);
211,12 → 292,15
long o_left_r, o_left_i, o_right_r, o_right_i;
unsigned long o_left, o_right;
 
o_left_r = sumr & 0x01ffff; o_left_i = sumi & 0x01ffff;
o_left = (o_left_r << 17) | (o_left_i);
o_left_r = rndbits(sumr<<(CWIDTH-2), CWIDTH+IWIDTH+3, OWIDTH+4);
o_left_r = ubits(o_left_r, OWIDTH);
o_left_i = rndbits(sumi<<(CWIDTH-2), CWIDTH+IWIDTH+3, OWIDTH+4);
o_left_i = ubits(o_left_i, OWIDTH);
o_left = (o_left_r << OWIDTH) | (o_left_i);
 
o_right_r = (mpyr>>18) & 0x01ffff;
o_right_i = (mpyi>>18) & 0x01ffff;
o_right = (o_right_r << 17) | (o_right_i);
o_right_r = ubits(mpyr, OWIDTH);
o_right_i = ubits(mpyi, OWIDTH);
o_right = (o_right_r << OWIDTH) | (o_right_i);
/*
printf("oR_r = %lx, ", o_right_r);
printf("oR_i = %lx\n", o_right_i);
232,7 → 316,7
 
int main(int argc, char **argv, char **envp) {
Verilated::commandArgs(argc, argv);
BFLY_TB *bfly = new BFLY_TB;
HWBFLY_TB *bfly = new HWBFLY_TB;
int16_t ir0, ii0, lstr, lsti;
int32_t sumr, sumi, difr, difi;
int32_t smr, smi, dfr, dfi;
240,6 → 324,8
 
const int TESTSZ = 256;
 
bfly->opentrace("hwbfly.vcd");
 
bfly->reset();
 
bfly->test(9,0,0x4000000000l,0x7fff0000,0x7fff0000, 1);
/cpp/laststage_tb.cpp
0,0 → 1,332
////////////////////////////////////////////////////////////////////////////
//
// Filename: laststage_tb.cpp
//
// Project: A Doubletime Pipelined FFT
//
// Purpose: A test-bench for the laststage.v subfile of the general purpose
// pipelined FFT. This file may be run autonomously. If so,
// the last line output will either read "SUCCESS" on success, or some
// other failure message otherwise.
//
// This file depends upon verilator to both compile, run, and therefore
// test laststage.v
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
///////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015,2018 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 <stdio.h>
#include <stdint.h>
 
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vlaststage.h"
#include "twoc.h"
 
#define IWIDTH 16
#define OWIDTH (IWIDTH+1)
#define SHIFT 0
#define ROUND 1
 
#define ASIZ 32
#define AMSK (ASIZ-1)
 
class LASTSTAGE_TB {
public:
Vlaststage *m_last;
VerilatedVcdC *m_trace;
#ifdef DBLCLKFFT
unsigned long m_left[ASIZ], m_right[ASIZ];
#else
unsigned long m_data[ASIZ];
#endif
bool m_syncd;
int m_addr, m_offset;
unsigned long m_tickcount;
 
LASTSTAGE_TB(void) {
Verilated::traceEverOn(true);
m_last = new Vlaststage;
m_tickcount = 0;
m_syncd = false; m_addr = 0, m_offset = 0;
}
 
void opentrace(const char *vcdname) {
if (!m_trace) {
m_trace = new VerilatedVcdC;
m_last->trace(m_trace, 99);
m_trace->open(vcdname);
}
}
 
void closetrace(void) {
if (m_trace) {
m_trace->close();
delete m_trace;
m_trace = NULL;
}
}
 
void tick(void) {
m_tickcount++;
 
m_last->i_clk = 0;
m_last->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul * m_tickcount - 2));
m_last->i_clk = 1;
m_last->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul * m_tickcount));
m_last->i_clk = 0;
m_last->eval();
if (m_trace) {
m_trace->dump((uint64_t)(10ul * m_tickcount + 5));
m_trace->flush();
}
m_last->i_reset = 0;
m_last->i_sync = 0;
}
 
void cetick(void) {
int nkce;
 
tick();
nkce = (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
if ((m_last->i_ce)&&(nkce > 0)) {
m_last->i_ce = 0;
for(int kce = 1; kce < nkce; kce++)
tick();
m_last->i_ce = 1;
}
}
 
void reset(void) {
m_last->i_reset = 1;
tick();
 
m_syncd = false; m_addr = 0, m_offset = 0;
}
 
void check_results(void) {
bool failed = false;
 
if ((!m_syncd)&&(m_last->o_sync)) {
m_syncd = true;
m_offset = m_addr;
printf("SYNCD at %d\n", m_addr);
}
 
#ifdef DBLCLKFFT
int ir0, ir1, ii0, ii1, or0, oi0, or1, oi1;
 
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);
 
 
or0 = sbits(m_last->o_left >> OWIDTH, OWIDTH);
oi0 = sbits(m_last->o_left , OWIDTH);
or1 = sbits(m_last->o_right >> OWIDTH, OWIDTH);
oi1 = sbits(m_last->o_right , OWIDTH);
 
 
// Sign extensions
printf("k=%3d: IN = %08x:%08x, OUT =%09lx:%09lx, S=%d\n",
m_addr, m_last->i_left, m_last->i_right,
m_last->o_left, m_last->o_right,
m_last->o_sync);
 
/*
printf("\tI0 = { %x : %x }, I1 = { %x : %x }, O0 = { %x : %x }, O1 = { %x : %x }\n",
ir0, ii0, ir1, ii1, or0, oi0, or1, oi1);
*/
 
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;
}
#else
int or0, oi0;
int sumr, sumi, difr, difi;
int ir0, ii0, ir1, ii1, ir2, ii2, ir3, ii3, irn, iin;
 
irn = sbits(m_data[(m_addr-m_offset+2)&AMSK]>>IWIDTH, IWIDTH);
iin = sbits(m_data[(m_addr-m_offset+2)&AMSK], IWIDTH);
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);
ir3 = sbits(m_data[(m_addr-m_offset-2)&AMSK]>>IWIDTH, IWIDTH);
ii3 = sbits(m_data[(m_addr-m_offset-2)&AMSK], IWIDTH);
 
sumr = ir1 + ir0;
sumi = ii1 + ii0;
 
difr = ir2 - ir1;
difi = ii2 - ii1;
 
or0 = sbits(m_last->o_val >> OWIDTH, OWIDTH);
oi0 = sbits(m_last->o_val , OWIDTH);
 
printf("IR0 = %08x, IR1 = %08x, IR2 = %08x, ",
ir0, ir1, ir2);
printf("II0 = %08x, II1 = %08x, II2 = %08x, ",
ii0, ii1, ii2);
// Sign extensions
printf("k=%3d: IN = %08x, %c, OUT =%09lx, S=%d\n",
m_addr, m_last->i_val,
m_last->i_sync ? 'S':' ',
m_last->o_val, m_last->o_sync);
 
 
if ((m_syncd)&&(0 == ((m_addr-m_offset)&1))) {
if (or0 != sumr) {
printf("FAIL 1: or0 != (ir0+ir1), or %x(exp) != %x(sut)\n", sumr, or0);
failed=true;
} if (oi0 != sumi) {
printf("FAIL 2\n");
failed=true;
}
} else if ((m_syncd)&&(1 == ((m_addr-m_offset)&1))) {
if (or0 != difr) {
printf("FAIL 3: or0 != (ir1-ir0), or %x(exp) != %x(sut)\n", difr, or0);
failed=true;
} if (oi0 != difi) {
printf("FAIL 4: oi0 != (ii1-ii0), or %x(exp) != %x(sut)\n", difi, oi0);
failed=true;
}
} else if (m_addr > 20) {
printf("NO SYNC!\n");
failed = true;
}
#endif
if (failed)
exit(-2);
}
 
void sync(void) {
m_last->i_sync = 1;
}
 
void test(unsigned long left, unsigned long right) {
m_last->i_ce = 1;
if (m_last->i_sync)
m_addr = 0;
#ifdef DBLCLKFFT
m_last->i_left = left;
m_last->i_right = right;
 
m_left[ m_addr&AMSK] = m_last->i_left;
m_right[m_addr&AMSK] = m_last->i_right;
m_addr++;
 
cetick();
#else
m_last->i_val = left;
m_data[ m_addr&AMSK] = m_last->i_val;
m_addr = (m_addr+1);
cetick();
 
check_results();
 
m_last->i_val = right;
m_data[m_addr&AMSK] = m_last->i_val;
m_addr = (m_addr+1)&AMSK;
cetick();
#endif
 
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);
LASTSTAGE_TB *tb = new LASTSTAGE_TB;
 
tb->opentrace("laststage.vcd");
tb->reset();
 
tb->sync();
 
tb->test( 1, 0,0,0);
tb->test( 0, 2,0,0);
tb->test( 0, 0,4,0);
tb->test( 0, 0,0,8);
 
tb->test( 0, 0,0,0);
 
tb->test(16,16,0,0);
tb->test(0,0,16,16);
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/mpy_tb.cpp
2,7 → 2,7
//
// Filename: mpy_tb.cpp
//
// Project: A Doubletime Pipelined FFT
// Project: A General Purpose Pipelined FFT Implementation
//
// Purpose: A test-bench for the shift and add shiftaddmpy.v subfile of
// the double clocked FFT. This file may be run autonomously.
17,7 → 17,7
//
///////////////////////////////////////////////////////////////////////////
//
// 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
// modify it under the terms of the GNU General Public License as published
39,7 → 39,11
//
//
///////////////////////////////////////////////////////////////////////////
#include "verilated.h"
#include "verilated_vcd_c.h"
 
#include "fftsize.h"
 
#ifdef USE_OLD_MULTIPLY
#include "Vshiftaddmpy.h"
typedef Vshiftaddmpy Vmpy;
54,17 → 58,20
#define DELAY ((AW/2)+(AW&1)+2)
#endif
 
#include "verilated.h"
#include "twoc.h"
 
class MPYTB {
public:
Vmpy *mpy;
long vals[32];
int m_addr;
Vmpy *m_mpy;
VerilatedVcdC *m_trace;
long vals[32];
int m_addr;
uint64_t m_tickcount;
 
MPYTB(void) {
mpy = new Vmpy;
Verilated::traceEverOn(true);
m_mpy = new Vmpy;
m_tickcount = 0;
 
for(int i=0; i<32; i++)
vals[i] = 0;
71,24 → 78,68
m_addr = 0;
}
~MPYTB(void) {
delete mpy;
closetrace();
delete m_mpy;
}
 
void tick(void) {
mpy->i_clk = 0;
mpy->eval();
mpy->i_clk = 1;
mpy->eval();
void opentrace(const char *vcdname) {
if (!m_trace) {
m_trace = new VerilatedVcdC;
m_mpy->trace(m_trace, 99);
m_trace->open(vcdname);
}
}
 
void closetrace(void) {
if (m_trace) {
m_trace->close();
delete m_trace;
m_trace = NULL;
}
}
 
void tick(void) {
m_tickcount++;
 
m_mpy->i_clk = 0;
m_mpy->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount-2));
m_mpy->i_clk = 1;
m_mpy->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount));
m_mpy->i_clk = 0;
m_mpy->eval();
if (m_trace) {
m_trace->dump((uint64_t)(10ul*m_tickcount+5));
m_trace->flush();
}
}
 
void cetick(void) {
int ce = m_mpy->i_ce, nkce;
 
tick();
nkce = (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
if ((ce)&&(nkce>0)) {
m_mpy->i_ce = 0;
for(int kce=1; kce<nkce; kce++)
tick();
}
 
m_mpy->i_ce = ce;
}
 
void reset(void) {
mpy->i_clk = 0;
mpy->i_ce = 1;
mpy->i_a = 0;
mpy->i_b = 0;
m_mpy->i_clk = 0;
m_mpy->i_ce = 1;
m_mpy->i_a_unsorted = 0;
m_mpy->i_b_unsorted = 0;
 
for(int k=0; k<20; k++)
tick();
cetick();
}
 
bool test(const int ia, const int ib) {
97,23 → 148,21
 
a = sbits(ia, AW);
b = sbits(ib, BW);
mpy->i_ce = 1;
mpy->i_a = ubits(a, AW);
mpy->i_b = ubits(b, BW);
m_mpy->i_ce = 1;
m_mpy->i_a_unsorted = ubits(a, AW);
m_mpy->i_b_unsorted = ubits(b, BW);
 
vals[m_addr&31] = a * b;
 
tick();
if (rand()&1) {
mpy->i_ce = 0;
tick();
}
cetick();
 
printf("k=%3d: A =%04x, B =%05x -> O = %9lx (ANS=%10lx)\n",
m_addr, (int)ubits(a,AW), (int)ubits(b,BW),
(long)mpy->o_r, ubits(vals[m_addr&31], AW+BW+4));
printf("k=%3d: A =%0*x, B =%0*x -> O = %*lx (ANS=%*lx)\n",
m_addr, (AW+3)/4, (int)ubits(a,AW),
(BW+3)/4, (int)ubits(b,BW),
(AW+BW+3)/4, (long)m_mpy->o_r,
(AW+BW+7)/4, ubits(vals[m_addr&31], AW+BW+4));
 
out = sbits(mpy->o_r, AW+BW);
out = sbits(m_mpy->o_r, AW+BW);
 
m_addr++;
 
131,6 → 180,7
Verilated::commandArgs(argc, argv);
MPYTB *tb = new MPYTB;
 
tb->opentrace("mpy.vcd");
tb->reset();
 
for(int k=0; k<15; k++) {
149,10 → 199,16
tb->test(a, b);
}
 
for(int k=0; k<2048; k++) {
int a, b, out;
 
tb->test(rand(), rand());
if (AW+BW <= 20) {
// Exhaustive test
for(int a=0; a< (1<<AW); a++)
for(int b=0; b< (1<<BW); b++)
tb->test(a, b);
printf("Exhaust complete\n");
} else {
// Pseudorandom test
for(int k=0; k<2048; k++)
tb->test(rand(), rand());
}
 
delete tb;
/cpp/qtrstage_tb.cpp
6,11 → 6,11
//
// Purpose: A test-bench for the qtrstage.v subfile of the double
// clocked FFT. This file may be run autonomously. If so,
// the last line output will either read "SUCCESS" on success,
// or some other failure message otherwise.
// the last line output will either read "SUCCESS" on success, or some
// other failure message otherwise.
//
// This file depends upon verilator to both compile, run, and
// therefore test qtrstage.v
// This file depends upon verilator to both compile, run, and therefore
// test qtrstage.v
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
17,7 → 17,7
//
///////////////////////////////////////////////////////////////////////////
//
// 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
// modify it under the terms of the GNU General Public License as published
42,8 → 42,9
#include <stdio.h>
#include <stdint.h>
 
#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vqtrstage.h"
#include "verilated.h"
#include "twoc.h"
#include "fftsize.h"
 
72,30 → 73,78
class QTRTEST_TB {
public:
Vqtrstage *m_qstage;
unsigned long m_data[ASIZ];
VerilatedVcdC *m_trace;
unsigned long m_data[ASIZ], m_tickcount;
int m_addr, m_offset;
bool m_syncd;
 
QTRTEST_TB(void) {
Verilated::traceEverOn(true);
m_trace = NULL;
m_qstage = new Vqtrstage;
m_addr = 0; m_offset = 6; m_syncd = false;
m_addr = 0;
m_offset = 6;
m_syncd = false;
m_tickcount = 0;
}
 
void opentrace(const char *vcdname) {
if (!m_trace) {
m_trace = new VerilatedVcdC;
m_qstage->trace(m_trace, 99);
m_trace->open(vcdname);
}
}
 
void closetrace(void) {
if (m_trace) {
m_trace->close();
delete m_trace;
m_trace = NULL;
}
}
 
void tick(void) {
m_tickcount++;
 
m_qstage->i_clk = 0;
m_qstage->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount-2));
m_qstage->i_clk = 1;
m_qstage->eval();
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount));
m_qstage->i_clk = 0;
m_qstage->eval();
if (m_trace) {
m_trace->dump((uint64_t)(10ul*m_tickcount+5));
m_trace->flush();
}
 
m_qstage->i_sync = 0;
}
 
void cetick(void) {
int nkce;
 
tick();
nkce = (rand()&1);
#ifdef FFT_CKPCE
nkce += FFT_CKPCE;
#endif
if ((m_qstage->i_ce)&&(nkce>0)) {
m_qstage->i_ce = 0;
for(int kce = 1; kce < nkce; kce++)
tick();
m_qstage->i_ce = 1;
}
}
 
void reset(void) {
m_qstage->i_ce = 0;
m_qstage->i_rst = 1;
m_qstage->i_reset = 1;
tick();
m_qstage->i_ce = 0;
m_qstage->i_rst = 0;
m_qstage->i_reset = 0;
tick();
 
m_addr = 0; m_offset = 6; m_syncd = false;
102,18 → 151,22
}
 
void check_results(void) {
int ir0, ii0, ir1, ii1, ir2, ii2;
int sumr, sumi, difr, difi, or0, oi0;
bool fail = false;
 
if ((!m_syncd)&&(m_qstage->o_sync)) {
m_syncd = true;
assert(m_addr == m_offset);
m_offset = m_addr;
printf("VALID-SYNC!!\n");
}
 
if (!m_syncd)
return;
 
#ifdef DBLCLKFFT
int ir0, ii0, ir1, ii1, ir2, ii2;
 
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);
140,11 → 193,49
if (oi0 != difi) {
printf("FAIL 4: oi0 != difi (%x(exp) != %x(sut))\n", difi, oi0); fail = true;}
}
#else
int locn = (m_addr-m_offset)&AMSK;
int ir1, ii1, ir3, ii3, ir5, ii5;
 
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;
ir5 = sbits(m_data[(m_addr-m_offset-2)&AMSK]>>IWIDTH, IWIDTH);
ii5 = sbits(m_data[(m_addr-m_offset-2)&AMSK], IWIDTH);
ir3 = sbits(m_data[(m_addr-m_offset )&AMSK]>>IWIDTH, IWIDTH);
ii3 = sbits(m_data[(m_addr-m_offset )&AMSK], IWIDTH);
ir1 = sbits(m_data[(m_addr-m_offset+2)&AMSK]>>IWIDTH, IWIDTH);
ii1 = sbits(m_data[(m_addr-m_offset+2)&AMSK], IWIDTH);
 
sumr = ir3 + ir1;
sumi = ii3 + ii1;
difr = ir5 - ir3;
difi = ii5 - ii3;
 
or0 = sbits(m_qstage->o_data >> OWIDTH, OWIDTH);
oi0 = sbits(m_qstage->o_data, OWIDTH);
 
if (0==((locn)&2)) {
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 (2==((m_addr-m_offset)&3)) {
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;}
} else if (3==((m_addr-m_offset)&3)) {
if (or0 != difi) {
printf("FAIL 3: or0 != difr (%x(exp) != %x(sut))\n", difr, or0); fail = true;}
if (oi0 != -difr) {
printf("FAIL 4: oi0 != difi (%x(exp) != %x(sut))\n", difi, oi0); fail = true;}
}
 
// 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;
// }
#endif
 
 
if (fail)
exit(-1);
}
159,6 → 250,7
m_qstage->i_ce = 1;
m_qstage->i_data = data;
// m_qstage->i_sync = (((m_addr&127)==2)?1:0);
// printf("DATA[%08x] = %08x ... ", m_addr, data);
m_data[ (m_addr++)&AMSK] = data;
tick();
 
172,7 → 264,11
m_qstage->diff_i,
m_qstage->pipeline,
m_qstage->iaddr,
#ifdef DBLCLKFFT
m_qstage->imem,
#else
m_qstage->imem[1],
#endif
m_qstage->wait_for_sync);
 
check_results();
202,17 → 298,57
int16_t ir0, ii0, ir1, ii1, ir2, ii2;
int32_t sumr, sumi, difr, difi;
 
tb->opentrace("qtrstage.vcd");
tb->reset();
 
tb->test( 16, 0);
tb->test( 16, 0);
tb->sync();
 
tb->test( 8, 0);
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 0, 0);
 
tb->test( 0, 4);
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 0, 0);
 
tb->test( 0, 0);
tb->test( 32, 0);
tb->test( 0, 0);
tb->test( 0, 0);
 
tb->test( 0, 0);
tb->test( 0, 64);
tb->test( 0, 0);
tb->test( 0, 0);
 
tb->test( 0, 0);
tb->test( 0, 0);
tb->test(128, 0);
tb->test( 0, 0);
 
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 0,256);
tb->test( 0, 0);
 
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 2, 0);
 
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 0, 0);
tb->test( 0, 1);
 
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();
/formal/.gitignore
0,0 → 1,15
bitreverse
laststage
qtrstage
hwbfly_one
hwbfly_two
hwbfly_three
butterfly_one
butterfly_two
butterfly_three
butterfly_ck1
butterfly_ck2_r0
butterfly_ck2_r1
butterfly_ck3_r0
butterfly_ck3_r1
butterfly_ck3_r2
/formal/README.md
0,0 → 1,18
This directory contains several SymbiYosys scripts useful for
formally verifying parts and pieces of the design. Admittedly,
the entire design has yet to be formally verfified, however many
components have been verified successfully. These include:
 
- The butterflies, both the hardware enabled butterflies and the
soft multiplies.
 
- The penultimate (4-pt) stage of the FFT
 
- The final stage (2-pt) of the FFT
 
- The bitreverse
 
My intention is not to place formal properties into the repository.
Within the [defaults.h](../../sw/defaults.h) there's a
``formal_property_flag`` used for controlling whether or not the
formal properties are included into the RTL files.
/formal/abs_mpy.v
0,0 → 1,114
////////////////////////////////////////////////////////////////////////////////
//
// Filename: abs_mpy.v
//
// Project: Zip CPU -- a small, lightweight, RISC CPU soft core
//
// Purpose: This code has been modified from the mpyop.v file so as to
// abstract the multiply that formal methods struggle so hard to
// deal with. It also simplifies the interface so that (if enabled)
// the multiply will return in 1-6 clocks, rather than the specified
// number for the given architecture.
//
//
// Creator: Dan Gisselquist, Ph.D.
// Gisselquist Technology, LLC
//
////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2015-2018, 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
//
//
////////////////////////////////////////////////////////////////////////////////
//
//
`default_nettype none
//
module abs_mpy(i_a, i_b, o_result);
parameter AW = 32, BW=32;
parameter [0:0] OPT_SIGNED = 1'b1;
input wire [(AW-1):0] i_a;
input wire [(BW-1):0] i_b;
output wire [(AW+BW-1):0] o_result;
 
wire [(AW+BW-1):0] any_result;
assign any_result = $anyseq;
 
reg [AW-1:0] u_a;
reg [BW-1:0] u_b;
 
always @(*)
begin
u_a = ((i_a[AW-1])&&(OPT_SIGNED)) ? -i_a : i_a;
u_b = ((i_b[BW-1])&&(OPT_SIGNED)) ? -i_b : i_b;
end
 
reg [(AW+BW-1):0] u_result;
always @(*)
if ((OPT_SIGNED)&&(any_result[AW+BW-1]))
u_result = - { 1'b1, any_result };
else
u_result = { 1'b0, any_result };
 
always @(*)
begin
// Constrain our result among many possibilities
if ((i_a == 0)||(i_b == 0))
assume(any_result == 0);
else if (OPT_SIGNED)
assume(any_result[AW+BW-1]
== (i_a[AW-1] ^ i_b[BW-1]));
 
assume(u_result[AW+BW-1:BW] <= u_a);
assume(u_result[AW+BW-1:AW] <= u_b);
end
 
genvar k;
generate
begin
for(k=0; k<AW-1; k=k+1)
begin
always @(*)
if (u_a == (1<<k))
assume(u_result == (u_b << k));
end
 
for(k=0; k<BW; k=k+1)
begin
always @(*)
if (u_b == (1<<k))
assume(u_result== (u_a << k));
end
 
end endgenerate
 
assign o_result = any_result;
 
/*
always @(*)
if (i_a == 1)
assert(o_result == {{(AW){i_b[BW-1]}}, i_b });
 
always @(*)
if (i_b == 1)
assert(o_result == {{(BW){i_a[AW-1]}}, i_a });
*/
endmodule
/formal/bitreverse.sby
0,0 → 1,13
[options]
mode prove
depth 12
 
[engines]
smtbmc
 
[script]
read_verilog -formal -DBITREVERSE bitreverse.v
prep -top bitreverse
 
[files]
../../rtl/bitreverse.v
/formal/butterfly.sby
0,0 → 1,42
[tasks]
ck1
ck2_r0
ck2_r1
ck3_r0
ck3_r1
 
[options]
mode prove
depth 30
 
[engines]
smtbmc
 
[script]
read_verilog -formal -DHWBFLY abs_mpy.v
read_verilog -formal -DHWBFLY convround.v
read_verilog -formal -DHWBFLY longbimpy.v
read_verilog -formal -DHWBFLY bimpy.v
read_verilog -formal -DHWBFLY butterfly.v
 
# While I'd love to change the width of the inputs and the coefficients,
# doing so would adjust the width of the firmware multiplies, and so defeat
# our purpose here.
# ck1: chparam -set CKPCE 1 butterfly
ck1: chparam -set CKPCE 1 -set CWIDTH 19 -set IWIDTH 15 butterfly
#
ck2_r0: chparam -set CKPCE 2 -set CWIDTH 20 -set IWIDTH 12 -set F_CHECK 1 butterfly
ck2_r1: chparam -set CKPCE 2 -set CWIDTH 16 -set IWIDTH 6 -set F_CHECK 0 butterfly
#
ck3_r0: chparam -set CKPCE 3 -set CWIDTH 16 -set IWIDTH 12 -set F_CHECK 0 butterfly
ck3_r1: chparam -set CKPCE 3 -set CWIDTH 18 -set IWIDTH 14 -set F_CHECK 1 butterfly
ck3_r2: chparam -set CKPCE 3 -set CWIDTH 20 -set IWIDTH 16 -set F_CHECK 2 butterfly
 
prep -top butterfly
 
[files]
abs_mpy.v
../../rtl/convround.v
../../rtl/bimpy.v
../../rtl/longbimpy.v
../../rtl/butterfly.v
/formal/hwbfly.sby
0,0 → 1,27
[tasks]
one
two
three
 
[options]
mode prove
depth 23
 
[engines]
smtbmc
 
[script]
read_verilog -formal -DHWBFLY abs_mpy.v
read_verilog -formal -DHWBFLY convround.v
read_verilog -formal -DHWBFLY hwbfly.v
 
one: chparam -set CKPCE 1 -set IWIDTH 4 -set CWIDTH 6 hwbfly
two: chparam -set CKPCE 2 -set IWIDTH 4 -set CWIDTH 6 hwbfly
three: chparam -set CKPCE 3 -set IWIDTH 4 -set CWIDTH 6 hwbfly
 
prep -top hwbfly
 
[files]
abs_mpy.v
../../rtl/convround.v
../../rtl/hwbfly.v
/formal/laststage.sby
0,0 → 1,16
[options]
mode prove
depth 20
 
[engines]
smtbmc yices
 
[script]
read_verilog -formal -DLASTSTAGE convround.v
read_verilog -formal -DLASTSTAGE laststage.v
chparam -set IWIDTH 3 -set OWIDTH 4 laststage
prep -top laststage
 
[files]
../../rtl/laststage.v
../../rtl/convround.v
/formal/qtrstage.sby
0,0 → 1,16
[options]
mode prove
depth 20
 
[engines]
smtbmc boolector
 
[script]
read_verilog -formal -DQTRSTAGE convround.v
read_verilog -formal -DQTRSTAGE qtrstage.v
chparam -set IWIDTH 3 -set OWIDTH 4 qtrstage
prep -top qtrstage
 
[files]
../../rtl/qtrstage.v
../../rtl/convround.v

powered by: WebSVN 2.1.0

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