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

Subversion Repositories dblclockfft

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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