Line 4... |
Line 4... |
//
|
//
|
// Project: A Doubletime Pipelined FFT
|
// Project: A Doubletime Pipelined FFT
|
//
|
//
|
// Purpose: A test-bench for the qtrstage.v subfile of the double
|
// Purpose: A test-bench for the qtrstage.v subfile of the double
|
// clocked FFT. This file may be run autonomously. If so,
|
// clocked FFT. This file may be run autonomously. If so,
|
// the last line output will either read "SUCCESS" on success,
|
// the last line output will either read "SUCCESS" on success, or some
|
// or some other failure message otherwise.
|
// other failure message otherwise.
|
//
|
//
|
// This file depends upon verilator to both compile, run, and
|
// This file depends upon verilator to both compile, run, and therefore
|
// therefore test qtrstage.v
|
// test qtrstage.v
|
//
|
//
|
// Creator: Dan Gisselquist, Ph.D.
|
// Creator: Dan Gisselquist, Ph.D.
|
// Gisselquist Technology, LLC
|
// Gisselquist Technology, LLC
|
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright (C) 2015, Gisselquist Technology, LLC
|
// Copyright (C) 2015,2018, Gisselquist Technology, LLC
|
//
|
//
|
// This program is free software (firmware): you can redistribute it and/or
|
// This program is free software (firmware): you can redistribute it and/or
|
// modify it under the terms of the GNU General Public License as published
|
// modify it under the terms of the GNU General Public License as published
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// by the Free Software Foundation, either version 3 of the License, or (at
|
// your option) any later version.
|
// your option) any later version.
|
Line 40... |
Line 40... |
//
|
//
|
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <stdint.h>
|
#include <stdint.h>
|
|
|
#include "Vqtrstage.h"
|
|
#include "verilated.h"
|
#include "verilated.h"
|
|
#include "verilated_vcd_c.h"
|
|
#include "Vqtrstage.h"
|
#include "twoc.h"
|
#include "twoc.h"
|
#include "fftsize.h"
|
#include "fftsize.h"
|
|
|
#define IWIDTH TST_QTRSTAGE_IWIDTH
|
#define IWIDTH TST_QTRSTAGE_IWIDTH
|
#define OWIDTH (IWIDTH+1)
|
#define OWIDTH (IWIDTH+1)
|
Line 70... |
Line 71... |
#define wait_for_sync VVAR(_wait_for_sync)
|
#define wait_for_sync VVAR(_wait_for_sync)
|
|
|
class QTRTEST_TB {
|
class QTRTEST_TB {
|
public:
|
public:
|
Vqtrstage *m_qstage;
|
Vqtrstage *m_qstage;
|
unsigned long m_data[ASIZ];
|
VerilatedVcdC *m_trace;
|
|
unsigned long m_data[ASIZ], m_tickcount;
|
int m_addr, m_offset;
|
int m_addr, m_offset;
|
bool m_syncd;
|
bool m_syncd;
|
|
|
QTRTEST_TB(void) {
|
QTRTEST_TB(void) {
|
|
Verilated::traceEverOn(true);
|
|
m_trace = NULL;
|
m_qstage = new Vqtrstage;
|
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) {
|
void tick(void) {
|
|
m_tickcount++;
|
|
|
m_qstage->i_clk = 0;
|
m_qstage->i_clk = 0;
|
m_qstage->eval();
|
m_qstage->eval();
|
|
if (m_trace) m_trace->dump((uint64_t)(10ul*m_tickcount-2));
|
m_qstage->i_clk = 1;
|
m_qstage->i_clk = 1;
|
m_qstage->eval();
|
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;
|
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) {
|
void reset(void) {
|
m_qstage->i_ce = 0;
|
m_qstage->i_ce = 0;
|
m_qstage->i_rst = 1;
|
m_qstage->i_reset = 1;
|
tick();
|
tick();
|
m_qstage->i_ce = 0;
|
m_qstage->i_ce = 0;
|
m_qstage->i_rst = 0;
|
m_qstage->i_reset = 0;
|
tick();
|
tick();
|
|
|
m_addr = 0; m_offset = 6; m_syncd = false;
|
m_addr = 0; m_offset = 6; m_syncd = false;
|
}
|
}
|
|
|
void check_results(void) {
|
void check_results(void) {
|
int ir0, ii0, ir1, ii1, ir2, ii2;
|
|
int sumr, sumi, difr, difi, or0, oi0;
|
int sumr, sumi, difr, difi, or0, oi0;
|
bool fail = false;
|
bool fail = false;
|
|
|
if ((!m_syncd)&&(m_qstage->o_sync)) {
|
if ((!m_syncd)&&(m_qstage->o_sync)) {
|
m_syncd = true;
|
m_syncd = true;
|
|
assert(m_addr == m_offset);
|
m_offset = m_addr;
|
m_offset = m_addr;
|
|
printf("VALID-SYNC!!\n");
|
}
|
}
|
|
|
if (!m_syncd)
|
if (!m_syncd)
|
return;
|
return;
|
|
|
|
#ifdef DBLCLKFFT
|
|
int ir0, ii0, ir1, ii1, ir2, ii2;
|
|
|
ir0 = sbits(m_data[(m_addr-m_offset-1)&AMSK]>>IWIDTH, IWIDTH);
|
ir0 = sbits(m_data[(m_addr-m_offset-1)&AMSK]>>IWIDTH, IWIDTH);
|
ii0 = sbits(m_data[(m_addr-m_offset-1)&AMSK], IWIDTH);
|
ii0 = sbits(m_data[(m_addr-m_offset-1)&AMSK], IWIDTH);
|
ir1 = sbits(m_data[(m_addr-m_offset )&AMSK]>>IWIDTH, IWIDTH);
|
ir1 = sbits(m_data[(m_addr-m_offset )&AMSK]>>IWIDTH, IWIDTH);
|
ii1 = sbits(m_data[(m_addr-m_offset )&AMSK], IWIDTH);
|
ii1 = sbits(m_data[(m_addr-m_offset )&AMSK], IWIDTH);
|
ir2 = sbits(m_data[(m_addr-m_offset+1)&AMSK]>>IWIDTH, IWIDTH);
|
ir2 = sbits(m_data[(m_addr-m_offset+1)&AMSK]>>IWIDTH, IWIDTH);
|
Line 138... |
Line 191... |
if (or0 != difr) {
|
if (or0 != difr) {
|
printf("FAIL 3: or0 != difr (%x(exp) != %x(sut))\n", difr, or0); fail = true;}
|
printf("FAIL 3: or0 != difr (%x(exp) != %x(sut))\n", difr, or0); fail = true;}
|
if (oi0 != difi) {
|
if (oi0 != difi) {
|
printf("FAIL 4: oi0 != difi (%x(exp) != %x(sut))\n", difi, oi0); fail = true;}
|
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;
|
|
|
|
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 (m_qstage->o_sync != ((((m_addr-m_offset)&127) == 0)?1:0)) {
|
if (0==((locn)&2)) {
|
printf("BAD O-SYNC, m_addr = %d, m_offset = %d\n", m_addr, m_offset); fail = true;
|
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)
|
if (fail)
|
exit(-1);
|
exit(-1);
|
}
|
}
|
|
|
void sync(void) {
|
void sync(void) {
|
Line 157... |
Line 248... |
void test(unsigned int data) {
|
void test(unsigned int data) {
|
int isync = m_qstage->i_sync;
|
int isync = m_qstage->i_sync;
|
m_qstage->i_ce = 1;
|
m_qstage->i_ce = 1;
|
m_qstage->i_data = data;
|
m_qstage->i_data = data;
|
// m_qstage->i_sync = (((m_addr&127)==2)?1:0);
|
// m_qstage->i_sync = (((m_addr&127)==2)?1:0);
|
|
// printf("DATA[%08x] = %08x ... ", m_addr, data);
|
m_data[ (m_addr++)&AMSK] = data;
|
m_data[ (m_addr++)&AMSK] = data;
|
tick();
|
tick();
|
|
|
printf("k=%4d: ISYNC=%d, IN = %08x, OUT =%09lx, SYNC=%d\t%5x,%5x,%5x,%5x\t%x %4x %8x %d\n",
|
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_addr-m_offset), isync, m_qstage->i_data,
|
Line 170... |
Line 262... |
m_qstage->sum_i,
|
m_qstage->sum_i,
|
m_qstage->diff_r,
|
m_qstage->diff_r,
|
m_qstage->diff_i,
|
m_qstage->diff_i,
|
m_qstage->pipeline,
|
m_qstage->pipeline,
|
m_qstage->iaddr,
|
m_qstage->iaddr,
|
|
#ifdef DBLCLKFFT
|
m_qstage->imem,
|
m_qstage->imem,
|
|
#else
|
|
m_qstage->imem[1],
|
|
#endif
|
m_qstage->wait_for_sync);
|
m_qstage->wait_for_sync);
|
|
|
check_results();
|
check_results();
|
}
|
}
|
|
|
Line 200... |
Line 296... |
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
QTRTEST_TB *tb = new QTRTEST_TB;
|
QTRTEST_TB *tb = new QTRTEST_TB;
|
int16_t ir0, ii0, ir1, ii1, ir2, ii2;
|
int16_t ir0, ii0, ir1, ii1, ir2, ii2;
|
int32_t sumr, sumi, difr, difi;
|
int32_t sumr, sumi, difr, difi;
|
|
|
|
tb->opentrace("qtrstage.vcd");
|
tb->reset();
|
tb->reset();
|
|
|
tb->test( 16, 0);
|
tb->test( 16, 0);
|
tb->test( 16, 0);
|
tb->test( 16, 0);
|
tb->sync();
|
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( 0, 16);
|
tb->test( 0, 16);
|
tb->test( 16, 0);
|
tb->test( 16, 0);
|
tb->test(-16, 0);
|
tb->test(-16, 0);
|
tb->test( 0, 16);
|
|
tb->test( 0,-16);
|
|
|
|
for(int k=0; k<1060; k++) {
|
for(int k=0; k<1060; k++) {
|
tb->random_test();
|
tb->random_test();
|
}
|
}
|
|
|