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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [bench/] [cpp/] [ifft_tb.cpp] - Blame information for rev 14

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 14 dgisselq
//
2
// Filename:    ifft_tb.cpp
3
//
4
// Project:     A Doubletime Pipelined FFT
5
//
6
// Purpose:     A test-bench for the combined work of both fftmain.v and
7
//              ifftmain.v.  If they work together, in concert like they should,
8
//              then the operation of both in series should yield an identity.
9
//              This program attempts to check that identity with various
10
//              inputs given to it.
11
//
12
//              This file has a variety of dependencies, not the least of which
13
//              are verilator, ifftmain.v and fftmain.v (both produced by
14
//              fftgen), but also on the ifft_tb.v verilog test bench found
15
//              within this directory.
16
//
17
// Creator:     Dan Gisselquist, Ph.D.
18
//              Gisselquist Tecnology, LLC
19
//
20
///////////////////////////////////////////////////////////////////////////
21
//
22
// Copyright (C) 2015, Gisselquist Technology, LLC
23
//
24
// This program is free software (firmware): you can redistribute it and/or
25
// modify it under the terms of  the GNU General Public License as published
26
// by the Free Software Foundation, either version 3 of the License, or (at
27
// your option) any later version.
28
//
29
// This program is distributed in the hope that it will be useful, but WITHOUT
30
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
31
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
32
// for more details.
33
//
34
// You should have received a copy of the GNU General Public License along
35
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
36
// target there if the PDF file isn't present.)  If not, see
37
// <http://www.gnu.org/licenses/> for a copy.
38
//
39
// License:     GPL, v3, as defined and found on www.gnu.org,
40
//              http://www.gnu.org/licenses/gpl.html
41
//
42
//
43
///////////////////////////////////////////////////////////////////////////
44
#include <stdio.h>
45
#include <math.h>
46
#include <assert.h>
47
 
48
#include "verilated.h"
49
#include "Vifft_tb.h"
50
 
51
#define LGWIDTH 11
52
#define IWIDTH  16
53
#define MWIDTH  22
54
#define OWIDTH  28
55
 
56
#define FFTLEN  (1<<LGWIDTH)
57
 
58
class   IFFT_TB {
59
public:
60
        Vifft_tb        *m_tb;
61
        unsigned int    m_log[8*FFTLEN];
62
        long            m_data[2*FFTLEN];
63
        int             m_iaddr, m_oaddr, m_offset;
64
        FILE            *m_dumpfp;
65
        // double               *m_tb_buf;
66
        // int                  m_ntest;
67
        bool            m_syncd;
68
 
69
        IFFT_TB(void) {
70
                m_tb = new Vifft_tb;
71
                m_iaddr = m_oaddr = 0;
72
                m_dumpfp = NULL;
73
 
74
                m_syncd = false;
75
                // m_ntest = 0;
76
        }
77
 
78
        void    tick(void) {
79
                m_tb->i_clk = 0;
80
                m_tb->eval();
81
                m_tb->i_clk = 1;
82
                m_tb->eval();
83
        }
84
 
85
        void    reset(void) {
86
                m_tb->i_ce  = 0;
87
                m_tb->i_rst = 1;
88
                tick();
89
                m_tb->i_rst = 0;
90
                tick();
91
 
92
                m_iaddr = m_oaddr = 0;
93
                m_syncd = false;
94
        }
95
 
96
        long    twos_complement(const long val, const int bits) {
97
                long    r;
98
 
99
                r = val & ((1l<<bits)-1);
100
                if (r & (1l << (bits-1)))
101
                        r |= (-1l << bits);
102
                return r;
103
        }
104
 
105
        void    checkresults(void) {
106
        /*
107
                double  *dp, *sp; // Complex array
108
                double  vout[FFTLEN*2];
109
                double  isq=0.0, osq = 0.0;
110
                long    *lp;
111
 
112
                // Fill up our test array from the log array
113
                printf("%3d : CHECK: %8d %5x\n", m_ntest, m_iaddr, m_iaddr);
114
                dp = m_tb_buf; lp = &m_log[(m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))];
115
                for(int i=0; i<FFTLEN; i++) {
116
                        long    tv = *lp++;
117
 
118
                        dp[0] = twos_complement(tv >> IWIDTH, IWIDTH);
119
                        dp[1] = twos_complement(tv, IWIDTH);
120
 
121
                        printf("IN[%4d = %4x] = %9.1f %9.1f\n",
122
                                i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
123
                                i+((m_iaddr-FFTLEN*3)&((4*FFTLEN-1)&(-FFTLEN))),
124
                                dp[0], dp[1]);
125
                        dp += 2;
126
                }
127
 
128
                // Let's measure ... are we the zero vector?  If not, how close?
129
                dp = m_tb_buf;
130
                for(int i=0; i<FFTLEN; i++)
131
                        isq += (*dp) * (*dp);
132
 
133
                fftw_execute(m_plan);
134
 
135
                // Let's load up the output we received into vout
136
                dp = vout;
137
                for(int i=0; i<FFTLEN; i++) {
138
                        long    tv = m_data[i];
139
 
140
                        printf("OUT[%4d = %4x] = ", i, i);
141
                        printf("%16lx = ", tv);
142
                        *dp = twos_complement(tv >> OWIDTH, OWIDTH);
143
                        printf("%12.1f + ", *dp);
144
                        osq += (*dp) * (*dp); dp++;
145
                        *dp = twos_complement(tv, OWIDTH);
146
                        printf("%12.1f j", *dp);
147
                        osq += (*dp) * (*dp); dp++;
148
                        printf(" <-> %12.1f %12.1f\n", m_tb_buf[2*i], m_fft_buf[2*i+1]);
149
                }
150
 
151
 
152
                // Let's figure out if there's a scale factor difference ...
153
                double  scale = 0.0, wt = 0.0;
154
                sp = m_tb_buf;  dp = vout;
155
                for(int i=0; i<FFTLEN*2; i++) {
156
                        scale += (*sp) * (*dp++);
157
                        wt += (*sp) * (*sp); sp++;
158
                } scale = scale / wt;
159
 
160
                if (wt == 0.0) scale = 1.0;
161
 
162
                double xisq = 0.0;
163
                sp = m_tb_buf;  dp = vout;
164
                for(int i=0; i<FFTLEN*2; i++) {
165
                        double vl = (*sp++) * scale - (*dp++);
166
                        xisq += vl * vl;
167
                }
168
 
169
                printf("%3d : SCALE = %12.6f, WT = %18.1f, ISQ = %15.1f, ",
170
                        m_ntest, scale, wt, isq);
171
                printf("OSQ = %18.1f, ", osq);
172
                printf("XISQ = %18.1f\n", xisq);
173
                m_ntest++;
174
                */
175
        }
176
 
177
        bool    test(int lft, int rht) {
178
                m_tb->i_ce    = 1;
179
                m_tb->i_rst   = 0;
180
                m_tb->i_left  = lft;
181
                m_tb->i_right = rht;
182
 
183
                m_log[(m_iaddr++)&(8*FFTLEN-1)] = lft;
184
                m_log[(m_iaddr++)&(8*FFTLEN-1)] = rht;
185
 
186
                tick();
187
 
188
                if ((m_tb->o_sync)&&(!m_syncd)) {
189
                        m_offset = m_iaddr;
190
                        m_oaddr = 0;
191
                        m_syncd = true;
192
                }
193
 
194
                m_data[(m_oaddr++)&(FFTLEN-1)] = m_tb->o_left;
195
                m_data[(m_oaddr++)&(FFTLEN-1)] = m_tb->o_right;
196
 
197
                if ((m_syncd)&&((m_oaddr&(FFTLEN-1)) == 0)) {
198
                        dumpwrite();
199
                        // checkresults();
200
                }
201
 
202
                return (m_tb->o_sync);
203
        }
204
 
205
        bool    test(double lft_r, double lft_i, double rht_r, double rht_i) {
206
                int     ilft, irht, ilft_r, ilft_i, irht_r, irht_i;
207
 
208
                assert(2*IWIDTH <= 32);
209
                ilft_r = (int)(lft_r) & ((1<<IWIDTH)-1);
210
                ilft_i = (int)(lft_i) & ((1<<IWIDTH)-1);
211
                irht_r = (int)(rht_r) & ((1<<IWIDTH)-1);
212
                irht_i = (int)(rht_i) & ((1<<IWIDTH)-1);
213
 
214
                ilft = (ilft_r << IWIDTH) | ilft_i;
215
                irht = (irht_r << IWIDTH) | irht_i;
216
 
217
                return test(ilft, irht);
218
        }
219
 
220
        double  rdata(int addr) {
221
                long    ivl = m_data[addr & (FFTLEN-1)];
222
 
223
                ivl = twos_complement(ivl >> OWIDTH, OWIDTH);
224
                return (double)ivl;
225
        }
226
 
227
        double  idata(int addr) {
228
                long    ivl = m_data[addr & (FFTLEN-1)];
229
 
230
                ivl = twos_complement(ivl, OWIDTH);
231
                return (double)ivl;
232
        }
233
 
234
        void    dump(FILE *fp) {
235
                m_dumpfp = fp;
236
        }
237
 
238
        void    dumpwrite(void) {
239
                if (!m_dumpfp)
240
                        return;
241
 
242
                double  *buf;
243
 
244
                buf = new double[FFTLEN * 2];
245
                for(int i=0; i<FFTLEN; i++) {
246
                        buf[i*2] = rdata(i);
247
                        buf[i*2+1] = idata(i);
248
                }
249
 
250
                fwrite(buf, sizeof(double), FFTLEN*2, m_dumpfp);
251
                delete[] buf;
252
        }
253
};
254
 
255
 
256
int     main(int argc, char **argv, char **envp) {
257
        Verilated::commandArgs(argc, argv);
258
        IFFT_TB *tb = new IFFT_TB;
259
        FILE    *fpout;
260
 
261
        fpout = fopen("ifft_tb.dbl", "w");
262
        if (NULL == fpout) {
263
                fprintf(stderr, "Cannot write output file, fft_tb.dbl\n");
264
                exit(-1);
265
        }
266
 
267
        tb->reset();
268
        tb->dump(fpout);
269
 
270
        //     1 -> 0x0001 
271
        //     2 -> 0x0002 
272
        //     4 -> 0x0004 
273
        //     8 -> 0x0008 
274
        //    16 -> 0x0010 
275
        //    32 -> 0x0020 
276
        //    64 -> 0x0040 
277
        //   128 -> 0x0080 
278
        //   256 -> 0x0100 
279
        //   512 -> 0x0200 
280
        //  1024 -> 0x0400 
281
        //  2048 -> 0x0800
282
        //  4096 -> 0x1000
283
        //  8192 -> 0x2000
284
        // 16384 -> 0x4000
285
        for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
286
                tb->test((double)v,0.0,(double)v,0.0);
287
        //     1 -> 0xffff      
288
        //     2 -> 0xfffe
289
        //     4 -> 0xfffc
290
        //     8 -> 0xfff8
291
        //    16 -> 0xfff0
292
        //    32 -> 0xffe0
293
        //    64 -> 0xffc0
294
        //   128 -> 0xff80
295
        //   256 -> 0xff00
296
        //   512 -> 0xfe00
297
        //  1024 -> 0xfc00
298
        //  2048 -> 0xf800
299
        //  4096 -> 0xf000
300
        //  8192 -> 0xe000
301
        // 16384 -> 0xc000
302
        // 32768 -> 0x8000
303
        for(int v=1; v<=32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
304
                tb->test(-(double)v,0.0,-(double)v,0.0);
305
        //     1 -> 0x000040    CORRECT!!
306
        //     2 -> 0x000080 
307
        //     4 -> 0x000100 
308
        //     8 -> 0x000200
309
        //    16 -> 0x000400
310
        //    32 -> 0x000800
311
        //    64 -> 0x001000
312
        //   128 -> 0x002000
313
        //   256 -> 0x004000
314
        //   512 -> 0x008000
315
        //  1024 -> 0x010000
316
        //  2048 -> 0x020000
317
        //  4096 -> 0x040000
318
        //  8192 -> 0x080000
319
        // 16384 -> 0x100000
320
        for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
321
                tb->test(0.0,(double)v,0.0,(double)v);
322
        //     1 -> 0x3fffc0
323
        //     2 -> 0x3fff80
324
        //     4 -> 0x3fff00
325
        //     8 -> 0x3ffe00
326
        //    16 -> 0x3ffc00
327
        //    32 -> 0x3ff800
328
        //    64 -> 0x3ff000
329
        //   128 -> 0x3fe000
330
        //   256 -> 0x3fc000
331
        //   512 -> 0x3f8000
332
        //  1024 -> 0x3f0000
333
        //  2048 -> 0x3e0000
334
        //  4096 -> 0x3c0000
335
        //  8192 -> 0x380000
336
        // 16384 -> 0x300000
337
        for(int v=1; v<32768; v<<=1) for(int k=0; k<FFTLEN/2; k++)
338
                tb->test(0.0,-(double)v,0.0,-(double)v);
339
 
340
        // 61. Now, how about the smallest alternating real signal
341
        for(int k=0; k<FFTLEN/2; k++)
342
                tb->test(2.0,0.0,0.0,0.0); // Don't forget to expect a bias!
343
        // 62. Now, how about the smallest alternating imaginary signal
344
        for(int k=0; k<FFTLEN/2; k++)
345
                tb->test(0.0,2.0,0.0,0.0); // Don't forget to expect a bias!
346
        // 63. Now, how about the smallest alternating real signal,2nd phase
347
        for(int k=0; k<FFTLEN/2; k++)
348
                tb->test(0.0,0.0,2.0,0.0); // Don't forget to expect a bias!
349
        // 64.Now, how about the smallest alternating imaginary signal,2nd phase
350
        for(int k=0; k<FFTLEN/2; k++)
351
                tb->test(0.0,0.0,0.0,2.0); // Don't forget to expect a bias!
352
 
353
        // 65.
354
        for(int k=0; k<FFTLEN/2; k++)
355
                tb->test(32767.0,0.0,-32767.0,0.0);
356
        // 66.
357
        for(int k=0; k<FFTLEN/2; k++)
358
                tb->test(0.0,-32767.0,0.0,32767.0);
359
        // 67.
360
        for(int k=0; k<FFTLEN/2; k++)
361
                tb->test(-32768.0,-32768.0,-32768.0,-32768.0);
362
        // 68.
363
        for(int k=0; k<FFTLEN/2; k++)
364
                tb->test(0.0,-32767.0,0.0,32767.0);
365
        // 69.
366
        for(int k=0; k<FFTLEN/2; k++)
367
                tb->test(0.0,32767.0,0.0,-32767.0);
368
        // 70. 
369
        for(int k=0; k<FFTLEN/2; k++)
370
                tb->test(-32768.0,-32768.0,-32768.0,-32768.0);
371
 
372
        // 71. Now let's go for an impulse (SUCCESS)
373
        tb->test(16384.0, 0.0, 0.0, 0.0);
374
        for(int k=0; k<FFTLEN/2-1; k++)
375
                tb->test(0.0,0.0,0.0,0.0);
376
 
377
        // 72. And another one on the next clock (FAILS, ugly)
378
        //      Lot's of roundoff error, or some error in small bits
379
        tb->test(0.0, 0.0, 16384.0, 0.0);
380
        for(int k=0; k<FFTLEN/2-1; k++)
381
                tb->test(0.0,0.0,0.0,0.0);
382
 
383
        // 73. And an imaginary one on the second clock
384
        //      Much roundoff error, as in last test
385
        tb->test(0.0, 0.0, 0.0, 16384.0);
386
        for(int k=0; k<FFTLEN/2-1; k++)
387
                tb->test(0.0,0.0,0.0,0.0);
388
 
389
        // 74. Likewise the next clock
390
        //      Much roundoff error, as in last test
391
        tb->test(0.0,0.0,0.0,0.0);
392
        tb->test(16384.0, 0.0, 0.0, 0.0);
393
        for(int k=0; k<FFTLEN/2-2; k++)
394
                tb->test(0.0,0.0,0.0,0.0);
395
 
396
        // 75. And it's imaginary counterpart
397
        //      Much roundoff error, as in last test
398
        tb->test(0.0,0.0,0.0,0.0);
399
        tb->test(0.0, 16384.0, 0.0, 0.0);
400
        for(int k=0; k<FFTLEN/2-2; k++)
401
                tb->test(0.0,0.0,0.0,0.0);
402
 
403
        // 76. Likewise the next clock
404
        //      Much roundoff error, as in last test
405
        tb->test(0.0,0.0,0.0,0.0);
406
        tb->test(0.0, 0.0, 16384.0, 0.0);
407
        for(int k=0; k<FFTLEN/2-2; k++)
408
                tb->test(0.0,0.0,0.0,0.0);
409
 
410
        // 77. And it's imaginary counterpart
411
        //      Much roundoff error, as in last test
412
        tb->test(0.0,0.0,0.0,0.0);
413
        tb->test(0.0, 0.0, 0.0, 16384.0);
414
        for(int k=0; k<FFTLEN/2-2; k++)
415
                tb->test(0.0,0.0,0.0,0.0);
416
 
417
 
418
        // 78. Now let's try some exponentials
419
        for(int k=0; k<FFTLEN/2; k++) {
420
                double cl, cr, sl, sr, W;
421
                W = - 2.0 * M_PI / FFTLEN;
422
                cl = cos(W * (2*k  )) * 16383.0;
423
                sl = sin(W * (2*k  )) * 16383.0;
424
                cr = cos(W * (2*k+1)) * 16383.0;
425
                sr = sin(W * (2*k+1)) * 16383.0;
426
                tb->test(cl, sl, cr, sr);
427
        }
428
 
429
        // 79.
430
        for(int k=0; k<FFTLEN/2; k++) {
431
                double cl, cr, sl, sr, W;
432
                W = - 2.0 * M_PI / FFTLEN * 5;
433
                cl = cos(W * (2*k  )) * 16383.0;
434
                sl = sin(W * (2*k  )) * 16383.0;
435
                cr = cos(W * (2*k+1)) * 16383.0;
436
                sr = sin(W * (2*k+1)) * 16383.0;
437
                tb->test(cl, sl, cr, sr);
438
        }
439
 
440
        // 80.
441
        for(int k=0; k<FFTLEN/2; k++) {
442
                double cl, cr, sl, sr, W;
443
                W = - 2.0 * M_PI / FFTLEN * 8;
444
                cl = cos(W * (2*k  )) * 8190.0;
445
                sl = sin(W * (2*k  )) * 8190.0;
446
                cr = cos(W * (2*k+1)) * 8190.0;
447
                sr = sin(W * (2*k+1)) * 8190.0;
448
                tb->test(cl, sl, cr, sr);
449
        }
450
 
451
        // 81.
452
        for(int k=0; k<FFTLEN/2; k++) {
453
                double cl, cr, sl, sr, W;
454
                W = - 2.0 * M_PI / FFTLEN * 25;
455
                cl = cos(W * (2*k  )) * 4.0;
456
                sl = sin(W * (2*k  )) * 4.0;
457
                cr = cos(W * (2*k+1)) * 4.0;
458
                sr = sin(W * (2*k+1)) * 4.0;
459
                tb->test(cl, sl, cr, sr);
460
        }
461
 
462
        // 19.--24. And finally, let's clear out our results / buffer
463
        for(int k=0; k<(FFTLEN/2) * 5; k++)
464
                tb->test(0.0,0.0,0.0,0.0);
465
 
466
        fclose(fpout);
467
}
468
 
469
 

powered by: WebSVN 2.1.0

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