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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [bench/] [cpp/] [fftstage_tb.cpp] - Blame information for rev 41

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 36 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    fftstage_tb.cpp
4
//
5
// Project:     A General Purpose Pipelined FFT Implementation
6
//
7
// Purpose:     A test-bench for a generic FFT stage which has been
8
//              instantiated by fftgen.  Without loss of (much) generality,
9
//      we'll examine the 2048 fftstage.v.  This file may be run autonomously.
10
//      If so, the last line output will either read "SUCCESS" on success, or
11
//      some other failure message otherwise.  Likewise the exit code will
12
//      also indicate success (exit(0)) or failure (anything else).
13
//
14
//      This file depends upon verilator to both compile, run, and therefore
15
//      test fftstage.v.  Also, you'll need to place a copy of the cmem_*2048
16
//      hex file into the directory where you run this test bench.
17
//
18
// Creator:     Dan Gisselquist, Ph.D.
19
//              Gisselquist Technology, LLC
20
//
21
////////////////////////////////////////////////////////////////////////////////
22
//
23
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
24
//
25
// This program is free software (firmware): you can redistribute it and/or
26
// modify it under the terms of  the GNU General Public License as published
27
// by the Free Software Foundation, either version 3 of the License, or (at
28
// your option) any later version.
29
//
30
// This program is distributed in the hope that it will be useful, but WITHOUT
31
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
32
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
33
// for more details.
34
//
35
// You should have received a copy of the GNU General Public License along
36 41 dgisselq
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
37 36 dgisselq
// target there if the PDF file isn't present.)  If not, see
38
// <http://www.gnu.org/licenses/> for a copy.
39
//
40
// License:     GPL, v3, as defined and found on www.gnu.org,
41
//              http://www.gnu.org/licenses/gpl.html
42
//
43
//
44
////////////////////////////////////////////////////////////////////////////////
45
//
46
//
47
#include "Vfftstage.h"
48
#include "verilated.h"
49
#include "verilated_vcd_c.h"
50
#include "twoc.h"
51
#include "fftsize.h"
52
 
53
 
54
#ifdef  NEW_VERILATOR
55
#define VVAR(A) fftstage__DOT_ ## A
56
#else
57
#define VVAR(A) v__DOT_ ## A
58
#endif
59
 
60
#define cmem    VVAR(_cmem)
61
#define iaddr   VVAR(_iaddr)
62 41 dgisselq
#define ib_sync VVAR(_ib_sync)
63
#define ib_a    VVAR(_ib_a)
64
#define ib_b    VVAR(_ib_b)
65
#define ib_c    VVAR(_ib_c)
66 36 dgisselq
 
67 41 dgisselq
#define ob_sync VVAR(_ob_sync)
68
#define ob_a    VVAR(_ob_a)
69
#define ob_b    VVAR(_ob_b)
70
 
71 36 dgisselq
#define FFTBITS (FFT_LGWIDTH)
72
#define FFTLEN  (1<<FFTBITS)
73
#define FFTSIZE FFTLEN
74
#define FFTMASK (FFTLEN-1)
75
#define IWIDTH  FFT_IWIDTH
76
#define CWIDTH  20
77
#define OWIDTH  (FFT_IWIDTH+1)
78
#define BFLYSHIFT       0
79
#define LGWIDTH (FFT_LGWIDTH)
80
#ifdef  DBLCLKFFT
81
#define LGSPAN  (LGWIDTH-2)
82
#else
83
#define LGSPAN  (LGWIDTH-1)
84
#endif
85
#define ROUND   true
86
 
87 41 dgisselq
#define SPANLEN         (1<<LGSPAN)
88 36 dgisselq
#define SPANMASK        (SPANLEN-1)
89
#define DBLSPANLEN      (1<<(LGSPAN+4))
90
#define DBLSPANMASK     (DBLSPANLEN-1)
91
 
92 41 dgisselq
const   bool    gbl_debug = false;
93
 
94 36 dgisselq
class   FFTSTAGE_TB {
95
public:
96
        Vfftstage       *m_ftstage;
97
        VerilatedVcdC   *m_trace;
98 41 dgisselq
        long            m_iaddr;
99 36 dgisselq
        long            m_vals[SPANLEN], m_out[DBLSPANLEN];
100 41 dgisselq
        bool            m_syncd, m_ib_syncd, m_ob_syncd, m_input_sync;
101
        int             m_offset, m_ib_offset, m_ob_offset;
102 36 dgisselq
        uint64_t        m_tickcount;
103
 
104
        FFTSTAGE_TB(void) {
105
                Verilated::traceEverOn(true);
106
                m_ftstage = new Vfftstage;
107
                m_syncd = false;
108 41 dgisselq
                m_input_sync = false;
109
                m_ib_syncd   = false;
110
                m_ob_syncd   = false;
111
                m_iaddr = 0;
112 36 dgisselq
                m_offset = 0;
113
                m_tickcount = 0;
114 41 dgisselq
assert(OWIDTH == IWIDTH+1);
115 36 dgisselq
        }
116
 
117
        void    opentrace(const char *vcdname) {
118
                if (!m_trace) {
119
                        m_trace = new VerilatedVcdC;
120
                        m_ftstage->trace(m_trace, 99);
121
                        m_trace->open(vcdname);
122
                }
123
        }
124
 
125
        void    closetrace(void) {
126
                if (m_trace) {
127
                        m_trace->close();
128
                        delete  m_trace;
129
                        m_trace = NULL;
130
                }
131
        }
132
 
133
        void    tick(void) {
134
                m_tickcount++;
135
 
136
                m_ftstage->i_clk = 0;
137
                m_ftstage->eval();
138 41 dgisselq
                if (m_trace)    m_trace->dump((vluint64_t)(10ul*m_tickcount-2));
139 36 dgisselq
                m_ftstage->i_clk = 1;
140
                m_ftstage->eval();
141 41 dgisselq
                if (m_trace)    m_trace->dump((vluint64_t)(10ul*m_tickcount));
142 36 dgisselq
                m_ftstage->i_clk = 0;
143
                m_ftstage->eval();
144
                if (m_trace) {
145 41 dgisselq
                        m_trace->dump((vluint64_t)(10ul*m_tickcount+5));
146 36 dgisselq
                        m_trace->flush();
147
                }
148
        }
149
 
150
        void    cetick(void) {
151
                int     ce = m_ftstage->i_ce, nkce;
152
 
153
                tick();
154
                nkce = 0; // (rand()&1);
155
#ifdef  FFT_CKPCE
156
                nkce += FFT_CKPCE;
157
#endif
158
                if ((ce)&&(nkce > 0)) {
159
                        m_ftstage->i_ce = 0;
160
                        for(int kce = 1; kce < nkce; kce++)
161
                                tick();
162
                }
163
 
164
                m_ftstage->i_ce = ce;
165
        }
166
 
167
        void    reset(void) {
168
                m_ftstage->i_ce  = 0;
169
                m_ftstage->i_reset = 1;
170 41 dgisselq
                m_ftstage->i_sync  = 0;
171 36 dgisselq
                tick();
172
 
173
                // Let's give it several ticks with no sync
174
                m_ftstage->i_ce = 0;
175
                m_ftstage->i_reset = 0;
176 41 dgisselq
                m_ftstage->i_sync  = 0;
177
                /*
178 36 dgisselq
                for(int i=0; i<8192; i++) {
179
                        m_ftstage->i_data = rand();
180
                        m_ftstage->i_sync = 0;
181
                        m_ftstage->i_ce = 1;
182
 
183
                        cetick();
184
 
185
                        assert(m_ftstage->o_sync == 0);
186
                }
187 41 dgisselq
                */
188 36 dgisselq
 
189
                m_iaddr = 0;
190
                m_offset = 0;
191
                m_syncd = false;
192 41 dgisselq
                m_ib_syncd = false;
193
                m_ob_syncd = false;
194 36 dgisselq
        }
195
 
196
        void    butterfly(const long cv, const long lft, const long rht,
197
                                long &o_lft, long &o_rht) {
198
                long    cv_r, cv_i;
199
                long    lft_r, lft_i, rht_r, rht_i;
200
                long    o_lft_r, o_lft_i, o_rht_r, o_rht_i;
201
 
202
                cv_r = sbits(cv>>CWIDTH, CWIDTH);
203
                cv_i = sbits(cv, CWIDTH);
204
 
205
                lft_r = sbits(lft>>IWIDTH, IWIDTH);
206
                lft_i = sbits(lft, IWIDTH);
207
 
208
                rht_r = sbits(rht>>IWIDTH, IWIDTH);
209
                rht_i = sbits(rht, IWIDTH);
210
 
211
                o_lft_r = lft_r + rht_r;
212
                o_lft_i = lft_i + rht_i;
213 41 dgisselq
                o_lft_r = ubits(o_lft_r, OWIDTH);
214
                o_lft_i = ubits(o_lft_i, OWIDTH);
215 36 dgisselq
 
216
                // o_lft_r >>= 1;
217
                // o_lft_i >>= 1;
218
                o_lft = (o_lft_r << OWIDTH) | (o_lft_i);
219
 
220
                o_rht_r = (cv_r * (lft_r-rht_r)) - (cv_i * (lft_i-rht_i));
221
                o_rht_i = (cv_r * (lft_i-rht_i)) + (cv_i * (lft_r-rht_r));
222
 
223
                if (ROUND) {
224 41 dgisselq
                        /* Non-convergent rounding
225 36 dgisselq
                        if (o_rht_r & (1<<(CWIDTH-3)))
226
                                o_rht_r += (1<<(CWIDTH-3))-1;
227
                        if (o_rht_i & (1<<(CWIDTH-3)))
228
                                o_rht_i += (1<<(CWIDTH-3))-1;
229 41 dgisselq
                        */
230
 
231
                        // Convergent rounding
232
                        if (o_rht_r & (1<<(CWIDTH-2)))
233
                                o_rht_r += (1<<(CWIDTH-3));
234
                        else
235
                                o_rht_r += (1<<(CWIDTH-3))-1;
236
 
237
                        if (o_rht_i & (1<<(CWIDTH-2)))
238
                                o_rht_i += (1<<(CWIDTH-3));
239
                        else
240
                                o_rht_i += (1<<(CWIDTH-3))-1;
241 36 dgisselq
                }
242
 
243
                o_rht_r >>= (CWIDTH-2);
244
                o_rht_i >>= (CWIDTH-2);
245
 
246 41 dgisselq
                o_rht_r = ubits(o_rht_r, OWIDTH);
247
                o_rht_i = ubits(o_rht_i, OWIDTH);
248 36 dgisselq
                o_rht = (o_rht_r << OWIDTH) | (o_rht_i);
249
 
250
                /*
251 41 dgisselq
                printf("BUTTERFLY: %10lx %10lx %10lx -> %10lx %10lx\n",
252
                        ubits(cv, 2*CWIDTH),
253
                        ubits(lft,   2*IWIDTH), ubits(rht,   2*IWIDTH),
254
                        ubits(o_lft, 2*OWIDTH), ubits(o_rht, 2*OWIDTH));
255 36 dgisselq
                */
256
        }
257
 
258
        void    test(bool i_sync, long i_data) {
259
                long    cv;
260
                bool    bc;
261
                int     raddr;
262
                bool    failed = false;
263
 
264 41 dgisselq
                m_ftstage->i_reset = 0;
265 36 dgisselq
                m_ftstage->i_ce   = 1;
266
                m_ftstage->i_sync = i_sync;
267 41 dgisselq
                i_data = ubits(i_data, 2*IWIDTH);
268 36 dgisselq
                m_ftstage->i_data = i_data;
269
 
270 41 dgisselq
                if (!m_input_sync) {
271
                        if (i_sync)
272
                                m_input_sync = true;
273
                        m_iaddr = 0;
274
                }
275
 
276 36 dgisselq
                cv = m_ftstage->cmem[m_iaddr & SPANMASK];
277
                bc = m_iaddr & (1<<LGSPAN);
278
                if (!bc)
279
                        m_vals[m_iaddr & (SPANMASK)] = i_data;
280
                else {
281
                        int     waddr = m_iaddr ^ (1<<LGSPAN);
282
                        waddr &= (DBLSPANMASK);
283
                        if (m_iaddr & (1<<(LGSPAN+1)))
284
                                waddr |= (1<<(LGSPAN));
285 41 dgisselq
                        butterfly(cv,
286
                                m_vals[m_iaddr & (SPANMASK)],
287
                                i_data,
288 36 dgisselq
                                m_out[(m_iaddr-SPANLEN) & (DBLSPANMASK)],
289
                                m_out[m_iaddr & (DBLSPANMASK)]);
290
                }
291
 
292
                cetick();
293
 
294 41 dgisselq
                unsigned        ib_addr = (m_iaddr - m_ib_offset)
295
                                        & ((SPANMASK<<1)|1);
296
                if ((!m_ib_syncd)&&(m_ftstage->ib_sync)) {
297
                        m_ib_syncd = true;
298
                        m_ib_offset = m_iaddr;
299
 
300
                        if (gbl_debug) printf("IB-SYNC!!!!  Offset = %d\n", m_ib_offset);
301
                } else if ((m_ib_syncd)&&(ib_addr <(1<<(LGSPAN)))) {
302
                        unsigned long   ib_a, ib_b, ib_c;
303
                        ib_a = m_vals[ib_addr&SPANMASK];
304
                        ib_b = i_data; // m_vals[(m_iaddr-m_ib_offset+(1<<(LGSPAN-1)))&(SPANMASK)];
305
                        ib_c = m_ftstage->cmem[(m_iaddr-m_ib_offset)&(SPANMASK)];
306
 
307
                        assert(m_ftstage->ib_a == ib_a);
308
                        assert(m_ftstage->ib_b == ib_b);
309
                        // assert(m_ftstage->ib_a == ib_a);
310
                }
311
 
312
                if ((!m_ob_syncd)&&(m_ftstage->ob_sync)) {
313
                        m_ob_syncd = true;
314
                        m_ob_offset = m_iaddr;
315
 
316
                        if (gbl_debug) printf("OB-SYNC!!!!  Offset = %d\n", m_ob_offset);
317
                }
318
 
319 36 dgisselq
                if ((!m_syncd)&&(m_ftstage->o_sync)) {
320
                        m_syncd = true;
321
                        m_offset = m_iaddr;
322
 
323 41 dgisselq
                        if (gbl_debug) printf("SYNC!!!!\n");
324 36 dgisselq
                }
325
 
326
                raddr = (m_iaddr-m_offset) & DBLSPANMASK;
327
 
328 41 dgisselq
                if (gbl_debug)
329
                        printf("%4ld, %4ld: %d %9lx -> %d %9lx ... "
330
                                "%4x %15lx (%10lx)",
331
                        (long)m_iaddr, (long)raddr,
332
                        // Input values
333
                        i_sync, ubits(i_data, 2*IWIDTH),
334
                        // Output values
335
                        m_ftstage->o_sync,
336 36 dgisselq
                        (long)m_ftstage->o_data,
337
 
338 41 dgisselq
                        m_ftstage->iaddr&FFTMASK,
339
                        (long)(ubits(m_ftstage->cmem[
340
                                m_ftstage->iaddr&(SPANMASK)],
341
                                2*CWIDTH)),
342 36 dgisselq
                        (long)m_out[raddr]);
343
 
344 41 dgisselq
                unsigned long   oba, obb;
345
 
346
                oba = ubits(
347
                m_ftstage->VVAR(_HWBFLY__DOT__bfly__DOT__rnd_left_r),OWIDTH)
348
                                <<OWIDTH;
349
                oba |= ubits(
350
                m_ftstage->VVAR(_HWBFLY__DOT__bfly__DOT__rnd_left_i), OWIDTH);
351
 
352
                obb = ubits(
353
                m_ftstage->VVAR(_HWBFLY__DOT__bfly__DOT__rnd_right_r), OWIDTH)
354
                                <<OWIDTH;
355
                obb |= ubits(
356
                m_ftstage->VVAR(_HWBFLY__DOT__bfly__DOT__rnd_right_i), OWIDTH);
357
 
358
                if ((gbl_debug)&&(m_ob_syncd))
359
                        printf(" [%d %10lx %10lx]",
360
                                m_ftstage->ob_sync,
361
                                ubits(oba, 2*OWIDTH), ubits(obb, 2*OWIDTH));
362
 
363 36 dgisselq
                if ((m_syncd)&&(m_ftstage->o_sync != ((((m_iaddr-m_offset)&((1<<(LGSPAN+1))-1))==0)?1:0))) {
364
                        fprintf(stderr, "Bad output sync (m_iaddr = %lx, m_offset = %x)\n",
365
                                (m_iaddr-m_offset) & SPANMASK, m_offset);
366
                        failed = true;
367 41 dgisselq
                } if (gbl_debug) printf("\n");
368 36 dgisselq
 
369
                if (m_syncd) {
370
                        if (m_out[raddr] != m_ftstage->o_data) {
371 41 dgisselq
                                printf("Bad output data, ([%lx - %x = %x (%d)] "
372
                                        "%lx(exp) != %lx(sut))\n",
373
                                        m_iaddr, m_offset, raddr, raddr,
374 36 dgisselq
                                        m_out[raddr], (long)m_ftstage->o_data);
375
                                failed = true;
376 41 dgisselq
                        } // printf("Checked #%d\n", raddr);
377
                } else if (m_iaddr > FFTSIZE/2+128) {
378 36 dgisselq
                        printf("NO OUTPUT SYNC!\n");
379
                        failed = true;
380
                }
381
                m_iaddr++;
382
 
383
                if (failed)
384
                        exit(-1);
385
        }
386
};
387
 
388
 
389
 
390
int     main(int argc, char **argv, char **envp) {
391
        Verilated::commandArgs(argc, argv);
392
        FFTSTAGE_TB     *ftstage = new FFTSTAGE_TB;
393 41 dgisselq
#ifdef  DBLCLKFFT
394
#define STEP    2
395
#else
396
#define STEP    1
397
#endif
398 36 dgisselq
 
399 41 dgisselq
        // ftstage->opentrace("fftstage.vcd");
400 36 dgisselq
        ftstage->reset();
401
 
402
        // Medium real (constant) value ... just for starters
403 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
404
                ftstage->test((k==0), 0x00200000l);
405 36 dgisselq
        // Medium imaginary (constant) value ... just for starters
406 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
407
                ftstage->test((k==0), 0x00000020l);
408 36 dgisselq
        // Medium sine wave, real
409 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP) {
410 36 dgisselq
                long vl;
411
                vl= (long)(cos(2.0 * M_PI * 1.0 / FFTSIZE * k)*(1l<<30) + 0.5);
412
                vl &= (-1l << 16); // Turn off the imaginary bit portion
413 41 dgisselq
                vl = ubits(vl,2*IWIDTH); // Turn off unused high order bits
414 36 dgisselq
                ftstage->test((k==1), vl);
415
        }
416
        // Smallest real value
417 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
418
                ftstage->test((k==0), 0x00080000l);
419 36 dgisselq
        // Smallest imaginary value
420 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
421
                ftstage->test((k==0), 0x00000001l);
422 36 dgisselq
        // Largest real value
423 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
424
                ftstage->test((k==0), 0x200000000l);
425 36 dgisselq
        // Largest negative imaginary value
426 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
427
                ftstage->test((k==0), 0x000010000l);
428 36 dgisselq
        // Let's try an impulse
429 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
430 36 dgisselq
                ftstage->test((k==0), (k==0)?0x020000000l:0l);
431
        // Now, let's clear out the result
432 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
433 36 dgisselq
                ftstage->test((k==0), 0x000000000l);
434 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
435 36 dgisselq
                ftstage->test((k==0), 0x000000000l);
436 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
437 36 dgisselq
                ftstage->test((k==0), 0x000000000l);
438 41 dgisselq
        for(int k=0; k<FFTSIZE; k+=STEP)
439 36 dgisselq
                ftstage->test((k==0), 0x000000000l);
440
 
441
        printf("SUCCESS! (Offset = %d)\n", ftstage->m_offset);
442
        delete  ftstage;
443
 
444 41 dgisselq
        exit(EXIT_SUCCESS);
445 36 dgisselq
}

powered by: WebSVN 2.1.0

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