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

Subversion Repositories dblclockfft

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 41 dgisselq
////////////////////////////////////////////////////////////////////////////////
2 6 dgisselq
//
3
// Filename:    butterfly_tb.cpp
4
//
5 41 dgisselq
// Project:     A General Purpose Pipelined FFT Implementation
6 6 dgisselq
//
7 36 dgisselq
// Purpose:     A test-bench for the butterfly.v subfile of the generic
8
//              pipelined FFT.  This file may be run autonomously.  If so,
9
//      the last line output will either read "SUCCESS" on success, or some
10
//      other failure message otherwise.
11 6 dgisselq
//
12 36 dgisselq
//      This file depends upon verilator to both compile, run, and therefore
13
//      test butterfly.v
14 6 dgisselq
//
15
// Creator:     Dan Gisselquist, Ph.D.
16 30 dgisselq
//              Gisselquist Technology, LLC
17 6 dgisselq
//
18 41 dgisselq
////////////////////////////////////////////////////////////////////////////////
19 6 dgisselq
//
20 36 dgisselq
// Copyright (C) 2015,2018 Gisselquist Technology, LLC
21 6 dgisselq
//
22
// This program is free software (firmware): you can redistribute it and/or
23
// modify it under the terms of  the GNU General Public License as published
24
// by the Free Software Foundation, either version 3 of the License, or (at
25
// your option) any later version.
26
//
27
// This program is distributed in the hope that it will be useful, but WITHOUT
28
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
29
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
30
// for more details.
31
//
32
// You should have received a copy of the GNU General Public License along
33 41 dgisselq
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
34 6 dgisselq
// target there if the PDF file isn't present.)  If not, see
35
// <http://www.gnu.org/licenses/> for a copy.
36
//
37
// License:     GPL, v3, as defined and found on www.gnu.org,
38
//              http://www.gnu.org/licenses/gpl.html
39
//
40
//
41 41 dgisselq
////////////////////////////////////////////////////////////////////////////////
42 3 dgisselq
#include <stdio.h>
43
#include <stdint.h>
44
 
45 36 dgisselq
#include "verilated.h"
46
#include "verilated_vcd_c.h"
47 3 dgisselq
#include "Vbutterfly.h"
48 23 dgisselq
#include "twoc.h"
49 36 dgisselq
#include "fftsize.h"
50 3 dgisselq
 
51 36 dgisselq
#ifdef  NEW_VERILATOR
52
#define VVAR(A) butterfly__DOT__ ## A
53
#else
54
#define VVAR(A) v__DOT_ ## A
55
#endif
56
 
57 29 dgisselq
#define IWIDTH  TST_BUTTERFLY_IWIDTH
58
#define CWIDTH  TST_BUTTERFLY_CWIDTH
59
#define OWIDTH  TST_BUTTERFLY_OWIDTH
60
#define BFLYDELAY       TST_BUTTERFLY_MPYDELAY
61 15 dgisselq
 
62 41 dgisselq
bool    gbl_debug = false;
63
 
64 5 dgisselq
class   BFLY_TB {
65
public:
66
        Vbutterfly      *m_bfly;
67 36 dgisselq
        VerilatedVcdC   *m_trace;
68 5 dgisselq
        unsigned long   m_left[64], m_right[64];
69 6 dgisselq
        bool            m_aux[64];
70 13 dgisselq
        int             m_addr, m_lastaux, m_offset;
71 23 dgisselq
        bool            m_syncd, m_waiting_for_sync_input;
72 36 dgisselq
        uint64_t        m_tickcount;
73 3 dgisselq
 
74 5 dgisselq
        BFLY_TB(void) {
75 36 dgisselq
                Verilated::traceEverOn(true);
76
                m_trace = NULL;
77 5 dgisselq
                m_bfly = new Vbutterfly;
78
                m_addr = 0;
79 6 dgisselq
                m_syncd = 0;
80 36 dgisselq
                m_tickcount = 0;
81 23 dgisselq
                m_waiting_for_sync_input = true;
82 5 dgisselq
        }
83 3 dgisselq
 
84 36 dgisselq
        void    opentrace(const char *vcdname) {
85
                if (!m_trace) {
86
                        m_trace = new VerilatedVcdC;
87
                        m_bfly->trace(m_trace, 99);
88
                        m_trace->open(vcdname);
89
                }
90
        }
91
 
92
        void    closetrace(void) {
93
                if (m_trace) {
94
                        m_trace->close();
95
                        delete  m_trace;
96
                        m_trace = NULL;
97
                }
98
        }
99
 
100 5 dgisselq
        void    tick(void) {
101 36 dgisselq
                m_tickcount++;
102
 
103 5 dgisselq
                m_lastaux = m_bfly->o_aux;
104
                m_bfly->i_clk = 0;
105
                m_bfly->eval();
106 41 dgisselq
                if (m_trace) m_trace->dump((vluint64_t)(10ul*m_tickcount-2));
107 5 dgisselq
                m_bfly->i_clk = 1;
108
                m_bfly->eval();
109 41 dgisselq
                if (m_trace) m_trace->dump((vluint64_t)(10ul*m_tickcount));
110 36 dgisselq
                m_bfly->i_clk = 0;
111
                m_bfly->eval();
112
                if (m_trace) {
113 41 dgisselq
                        m_trace->dump((vluint64_t)(10ul*m_tickcount+5));
114 36 dgisselq
                        m_trace->flush();
115
                }
116 6 dgisselq
 
117 13 dgisselq
                if ((!m_syncd)&&(m_bfly->o_aux))
118
                        m_offset = m_addr;
119 6 dgisselq
                m_syncd = (m_syncd) || (m_bfly->o_aux);
120 5 dgisselq
        }
121
 
122 36 dgisselq
        void    cetick(void) {
123
                int     ce = m_bfly->i_ce, nkce;
124
 
125
                tick();
126
 
127
                nkce = (rand()&1);
128
#ifdef  FFT_CKPCE
129
                nkce += FFT_CKPCE;
130
#endif
131
 
132
                if ((ce)&&(nkce > 0)) {
133
                        m_bfly->i_ce = 0;
134
                        for(int kce=0; kce<nkce-1; kce++)
135
                                tick();
136
                }
137
 
138
                m_bfly->i_ce = ce;
139
        }
140
 
141 5 dgisselq
        void    reset(void) {
142
                m_bfly->i_ce    = 0;
143 36 dgisselq
                m_bfly->i_reset = 1;
144 5 dgisselq
                m_bfly->i_coef  = 0l;
145
                m_bfly->i_left  = 0;
146
                m_bfly->i_right = 0;
147
                tick();
148 36 dgisselq
                m_bfly->i_reset = 0;
149 5 dgisselq
                m_bfly->i_ce  = 1;
150 6 dgisselq
                //
151
                // Let's run a RESET test here, forcing the whole butterfly
152
                // to be filled with aux=1.  If the reset works right,
153
                // we'll never get an aux=1 output.
154
                //
155 36 dgisselq
                m_bfly->i_reset = 1;
156 5 dgisselq
                m_bfly->i_aux = 1;
157 36 dgisselq
                m_bfly->i_ce  = 1;
158
                for(int i=0; i<200; i++)
159
                        cetick();
160 5 dgisselq
 
161 6 dgisselq
                // Now here's the RESET line, so let's see what the test does
162 36 dgisselq
                m_bfly->i_reset = 1;
163 6 dgisselq
                m_bfly->i_ce  = 1;
164
                m_bfly->i_aux = 1;
165 36 dgisselq
                cetick();
166
                m_bfly->i_reset = 0;
167 6 dgisselq
                m_syncd = 0;
168 23 dgisselq
 
169
                m_waiting_for_sync_input = true;
170 5 dgisselq
        }
171
 
172
        void    test(const int n, const int k, const unsigned long cof,
173
                        const unsigned lft, const unsigned rht, const int aux) {
174
 
175 29 dgisselq
                m_bfly->i_coef  = ubits(cof, 2*TST_BUTTERFLY_CWIDTH);
176
                m_bfly->i_left  = ubits(lft, 2*TST_BUTTERFLY_IWIDTH);
177
                m_bfly->i_right = ubits(rht, 2*TST_BUTTERFLY_IWIDTH);
178 5 dgisselq
                m_bfly->i_aux   = aux & 1;
179 23 dgisselq
                if ((m_waiting_for_sync_input)&&(aux&1)) {
180
                        m_waiting_for_sync_input = false;
181
                        m_addr = 0;
182
                }
183 5 dgisselq
 
184 26 dgisselq
                m_bfly->i_ce = 1;
185 36 dgisselq
                cetick();
186 5 dgisselq
 
187 41 dgisselq
                if (gbl_debug) {
188
                        if ((m_bfly->o_aux)&&(!m_lastaux))
189
                                printf("\n");
190
                        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",
191 5 dgisselq
                        n,k,
192 36 dgisselq
                        (2*CWIDTH+3)/4, ubits(m_bfly->i_coef, 2*CWIDTH),
193
                        (2*IWIDTH+3)/4, m_bfly->i_left,
194
                        (2*IWIDTH+3)/4, m_bfly->i_right,
195 5 dgisselq
                        m_bfly->i_aux,
196 36 dgisselq
                        (2*OWIDTH+3)/4, (long)m_bfly->o_left,
197
                        (2*OWIDTH+3)/4, (long)m_bfly->o_right,
198 5 dgisselq
                        m_bfly->o_aux);
199 41 dgisselq
                }
200 5 dgisselq
 
201 13 dgisselq
                if ((m_syncd)&&(m_left[(m_addr-m_offset)&(64-1)] != m_bfly->o_left)) {
202 36 dgisselq
                        printf("WRONG O_LEFT! (%lx(exp) != %lx(sut)\n",
203 15 dgisselq
                                m_left[(m_addr-m_offset)&(64-1)],
204 36 dgisselq
                                (long)m_bfly->o_left);
205
                        exit(EXIT_FAILURE);
206 5 dgisselq
                }
207
 
208 13 dgisselq
                if ((m_syncd)&&(m_right[(m_addr-m_offset)&(64-1)] != m_bfly->o_right)) {
209 36 dgisselq
                        printf("WRONG O_RIGHT! (%lx(exp) != %lx(sut))\n",
210
                                m_right[(m_addr-m_offset)&(64-1)],
211
                                (long)m_bfly->o_right);
212
                        exit(EXIT_FAILURE);
213 5 dgisselq
                }
214
 
215 13 dgisselq
                if ((m_syncd)&&(m_aux[(m_addr-m_offset)&(64-1)] != m_bfly->o_aux)) {
216 29 dgisselq
                        printf("FAILED AUX CHANNEL TEST (i.e. the SYNC)\n");
217 36 dgisselq
                        exit(EXIT_FAILURE);
218 6 dgisselq
                }
219
 
220 29 dgisselq
                if ((m_addr > TST_BUTTERFLY_MPYDELAY+6)&&(!m_syncd)) {
221
                        printf("NO SYNC PULSE!\n");
222 36 dgisselq
                        exit(EXIT_FAILURE);
223 6 dgisselq
                }
224
 
225 5 dgisselq
                // Now, let's calculate an "expected" result ...
226
                long    rlft, ilft;
227
 
228
                // Extract left and right values ...
229 29 dgisselq
                rlft = sbits(m_bfly->i_left >> IWIDTH, IWIDTH);
230
                ilft = sbits(m_bfly->i_left          , IWIDTH);
231 5 dgisselq
 
232
                // Now repeat for the right hand value ...
233
                long    rrht, irht;
234
                // Extract left and right values ...
235 29 dgisselq
                rrht = sbits(m_bfly->i_right >> IWIDTH, IWIDTH);
236
                irht = sbits(m_bfly->i_right          , IWIDTH);
237 5 dgisselq
 
238
                // and again for the coefficients
239
                long    rcof, icof;
240
                // Extract left and right values ...
241 29 dgisselq
                rcof = sbits(m_bfly->i_coef >> CWIDTH, CWIDTH);
242
                icof = sbits(m_bfly->i_coef          , CWIDTH);
243 5 dgisselq
 
244
                // Now, let's do the butterfly ourselves ...
245
                long sumi, sumr, difi, difr;
246
                sumr = rlft + rrht;
247
                sumi = ilft + irht;
248
                difr = rlft - rrht;
249
                difi = ilft - irht;
250
 
251
        /*
252
                printf("L=%5lx+%5lx,R=%5lx+%5lx,S=%5lx+%5lx,D=%5lx+%5lx, ",
253
                        rlft & 0x02ffffl,
254
                        ilft & 0x02ffffl,
255
                        rrht & 0x02ffffl,
256
                        irht & 0x02ffffl,
257
                        sumr & 0x02ffffl,
258
                        sumi & 0x02ffffl,
259
                        difr & 0x02ffffl,
260
                        difi & 0x02ffffl);
261
        */
262
                long p1, p2, p3, mpyr, mpyi;
263
                p1 = difr * rcof;
264
                p2 = difi * icof;
265
                p3 = (difr + difi) * (rcof + icof);
266
 
267 29 dgisselq
                mpyr = p1-p2;
268
                mpyi = p3-p1-p2;
269 5 dgisselq
 
270 29 dgisselq
                mpyr = rndbits(mpyr, (IWIDTH+2)+(CWIDTH+1), OWIDTH+4);
271
                mpyi = rndbits(mpyi, (IWIDTH+2)+(CWIDTH+1), OWIDTH+4);
272
 
273 5 dgisselq
        /*
274
                printf("RC=%lx, IC=%lx, ", rcof, icof);
275
                printf("P1=%lx,P2=%lx,P3=%lx, ", p1,p2,p3);
276
                printf("MPYr = %lx, ", mpyr);
277
                printf("MPYi = %lx, ", mpyi);
278
        */
279
 
280
                long    o_left_r, o_left_i, o_right_r, o_right_i;
281
                unsigned long   o_left, o_right;
282
 
283 29 dgisselq
                o_left_r = rndbits(sumr<<(CWIDTH-2), CWIDTH+IWIDTH+3, OWIDTH+4);
284
                        o_left_r = ubits(o_left_r, OWIDTH);
285
                o_left_i = rndbits(sumi<<(CWIDTH-2), CWIDTH+IWIDTH+3, OWIDTH+4);
286
                        o_left_i = ubits(o_left_i, OWIDTH);
287
                o_left = (o_left_r << OWIDTH) | (o_left_i);
288 5 dgisselq
 
289 29 dgisselq
                o_right_r = ubits(mpyr, OWIDTH);
290
                o_right_i = ubits(mpyi, OWIDTH);
291
                o_right = (o_right_r << OWIDTH) | (o_right_i);
292 5 dgisselq
        /*
293
                printf("oR_r = %lx, ", o_right_r);
294
                printf("oR_i = %lx\n", o_right_i);
295
        */
296
 
297
                m_left[ m_addr&(64-1)] = o_left;
298
                m_right[m_addr&(64-1)] = o_right;
299 6 dgisselq
                m_aux[  m_addr&(64-1)] = aux;
300 5 dgisselq
 
301
                m_addr++;
302
        }
303
};
304
 
305 36 dgisselq
long gentestword(int w, int al, int ar) {
306
        unsigned long   lo, hi, r;
307
        hi  = ((unsigned long)(al&0x0c))<<(w-4);
308
        hi += (al&3)-2ul;
309
 
310
        lo  = ((unsigned long)(ar&0x0c))<<(w-4);
311
        lo += (ar&3)-2ul;
312
 
313
        r = (ubits(hi, w) << w) | (ubits(lo, w));
314
        return r;
315
}
316
 
317 3 dgisselq
int     main(int argc, char **argv, char **envp) {
318
        Verilated::commandArgs(argc, argv);
319 5 dgisselq
        BFLY_TB *bfly = new BFLY_TB;
320 3 dgisselq
        int16_t         ir0, ii0, lstr, lsti;
321
        int32_t         sumr, sumi, difr, difi;
322
        int32_t         smr, smi, dfr, dfi;
323
        int             rnd = 0;
324
 
325 5 dgisselq
        const int       TESTSZ = 256;
326 3 dgisselq
 
327 41 dgisselq
        // bfly->opentrace("butterfly.vcd");
328 36 dgisselq
 
329 5 dgisselq
        bfly->reset();
330 3 dgisselq
 
331 36 dgisselq
// #define      ZEROTEST
332
#define ZEROTEST bfly->test(9,0,0x0000000000l,0x00000000,0x00000000, 0)
333 23 dgisselq
        // Test whether or not the aux channel starts clear, like its supposed to
334 36 dgisselq
 
335
        bfly->test(9,0,0x4000000000l,0x000f0000,0x00000000, 1);
336
        ZEROTEST;
337
        ZEROTEST;
338
        bfly->test(9,0,0x4000000000l,0x00000000,0x000f0000, 0);
339
        ZEROTEST;
340
        ZEROTEST;
341 23 dgisselq
        bfly->test(9,0,0x4000000000l,0x000f0000,0x000f0000, 0);
342 36 dgisselq
        ZEROTEST;
343
        ZEROTEST;
344 23 dgisselq
        bfly->test(9,1,0x4000000000l,0x000f0000,0xfff10000, 0);
345 36 dgisselq
        ZEROTEST;
346
        ZEROTEST;
347 23 dgisselq
        bfly->test(9,2,0x4000000000l,0x0000000f,0x0000fff1, 0);
348 36 dgisselq
        ZEROTEST;
349
        ZEROTEST;
350 23 dgisselq
        bfly->test(9,3,0x4000000000l,0x0000000f,0x0000000f, 0);
351 36 dgisselq
        ZEROTEST;
352
        ZEROTEST;
353 23 dgisselq
 
354 5 dgisselq
        bfly->test(9,0,0x4000000000l,0x7fff0000,0x7fff0000, 1);
355
        bfly->test(9,1,0x4000000000l,0x7fff0000,0x80010000, 0);
356
        bfly->test(9,2,0x4000000000l,0x00007fff,0x00008001, 0);
357
        bfly->test(9,3,0x4000000000l,0x00007fff,0x00007fff, 0);
358 3 dgisselq
 
359 5 dgisselq
        bfly->test(8,0,0x4000000000l,0x80010000,0x80010000, 1);
360
        bfly->test(8,1,0x4000000000l,0x00008001,0x00008001, 0);
361 3 dgisselq
 
362 5 dgisselq
        bfly->test(9,0,0x4000000000l,0x40000000,0xc0000000, 1);
363
        bfly->test(9,1,0x4000000000l,0x40000000,0x40000000, 0);
364
        bfly->test(9,2,0x4000000000l,0x00004000,0x0000c000, 0);
365
        bfly->test(9,3,0x4000000000l,0x00004000,0x00004000, 0);
366 3 dgisselq
 
367 5 dgisselq
        bfly->test(9,0,0x4000000000l,0x20000000,0xe0000000, 1);
368
        bfly->test(9,1,0x4000000000l,0x20000000,0x20000000, 0);
369
        bfly->test(9,2,0x4000000000l,0x00002000,0x0000e000, 0);
370
        bfly->test(9,3,0x4000000000l,0x00002000,0x00002000, 0);
371 3 dgisselq
 
372 5 dgisselq
        bfly->test(9,0,0x4000000000l,0x00080000,0xfff80000, 1);
373
        bfly->test(9,1,0x4000000000l,0x00080000,0x00080000, 0);
374
        bfly->test(9,2,0x4000000000l,0x00000008,0x0000fff8, 0);
375
        bfly->test(9,3,0x4000000000l,0x00000008,0x00000008, 0);
376 3 dgisselq
 
377 8 dgisselq
        bfly->test(7,0,0x3fffbff9b9l,0xfffe0000,0x00000000, 1);
378
        bfly->test(7,1,0x3ffd4fed28l,0xfffc0000,0x00020000, 0);
379
        bfly->test(7,2,0x3ff85fe098l,0xfff80000,0x00060000, 0);
380
        bfly->test(7,3,0x3ff0efd409l,0xfff00000,0x000e0000, 0);
381
        bfly->test(7,4,0x3fe70fc77cl,0xffe60000,0x00180000, 0);
382
        bfly->test(7,5,0x3fdabfbaf1l,0xffda0000,0x00240000, 0);
383
        bfly->test(7,6,0x3fcbefae69l,0xffca0000,0x00340000, 0);
384
        bfly->test(7,7,0x3fbaafa1e4l,0xffba0000,0x00440000, 0);
385
 
386
        /*
387
        // Special tests
388 5 dgisselq
        bfly->test(9,0,0x4000000000l,0x00010000,0xffff0000, 1);
389
        bfly->test(9,1,0x4000000000l,0x00010000,0x00010000, 0);
390
        bfly->test(9,2,0x4000000000l,0x00000001,0x0000ffff, 0);
391
        bfly->test(9,3,0x4000000000l,0x00000001,0x00000001, 0);
392 8 dgisselq
        */
393 3 dgisselq
 
394 5 dgisselq
        for(int n=0; n<4; n++) for(int k=0; k<TESTSZ; k++) {
395
                long    iv, rv;
396
                unsigned long   lft, rht, cof;
397
                double  c, s, W;
398
                bool    inv = 1;
399
                int     aux;
400 3 dgisselq
 
401 5 dgisselq
                W = ((inv)?-1:1) * 2.0 * M_PI * (2*k) / TESTSZ * 64;
402
                c = cos(W); s = sin(W);
403
                rv = (long)((double)(1l<<(16-2-n))*c+0.5);
404
                iv = (long)((double)(1l<<(16-2-n))*s+0.5);
405 3 dgisselq
 
406 5 dgisselq
                rv = (rv << 16) | (iv & (~(-1<<16)));
407
                lft = rv;
408 3 dgisselq
 
409 5 dgisselq
                W = ((inv)?-1:1) * 2.0 * M_PI * (2*k+1) / TESTSZ * 64;
410
                c = cos(W); s = sin(W);
411
                rv = (long)((double)(1l<<(16-2-n))*c+0.5);
412
                iv = (long)((double)(1l<<(16-2-n))*s+0.5);
413
 
414
                rv = (rv << 16) | (iv & (~(-1<<16)));
415
                rht = rv;
416
 
417
 
418
                // Switch the sign of W
419
                W = ((inv)?1:-1) * 2.0 * M_PI * (2*k) / TESTSZ;
420
                c = cos(W); s = sin(W);
421
                rv = (long)((double)(1l<<(20-2))*c+0.5); // Keep 20-2 bits for
422
                iv = (long)((double)(1l<<(20-2))*s+0.5); // coefficients
423
 
424
                rv = (rv << 20) | (iv & (~(-1<<20)));
425
                cof = rv;
426
 
427
                aux = ((k&(TESTSZ-1))==0);
428
 
429
                bfly->test(n,k, cof, lft, rht, aux);
430 3 dgisselq
        }
431
 
432 36 dgisselq
        int     k = TESTSZ;
433
        // Exhaustively test
434
#if (4*IWIDTH+2*CWIDTH <= 24)
435
                for(int a=0; a<(1<<(2*IWIDTH)); a++)
436
                for(int b=0; b<(1<<(2*IWIDTH)); b++)
437
                for(int c=0; c<(1<<(2*CWIDTH)); c++)
438
                        bfly->test(0, k++, c, a, b, 0);
439
 
440
                printf("Exhaust complete\n");
441
#else
442
                for(int al=0; al<16; al++)
443
                for(int ar=0; ar<16; ar++)
444
                for(int bl=0; bl<16; bl++)
445
                for(int br=0; br<16; br++)
446
                for(int cl=0; cl<16; cl++)
447
                for(int cr=0; cr<16; cr++) {
448
                        long a = gentestword(IWIDTH, al, ar);
449
                        long b = gentestword(IWIDTH, bl, br);
450
                        long c = gentestword(CWIDTH, cl, cr);
451
                        bfly->test(0, k++, c, a, b, 0);
452
                }
453
                printf("Partial exhaust complete\n");
454
#endif
455
 
456 3 dgisselq
        delete  bfly;
457
 
458 4 dgisselq
        printf("SUCCESS!\n");
459 3 dgisselq
        exit(0);
460
}

powered by: WebSVN 2.1.0

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