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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [sw/] [bldstage.cpp] - Blame information for rev 37

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 36 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    bldstage.cpp
4
//
5
// Project:     A General Purpose Pipelined FFT Implementation
6
//
7 37 dgisselq
// Purpose:     Builds the logic necessary to implement a single stage of an
8
//              FFT.  This includes referencing the butterfly, but not the
9
//      actual butterflies themselves.  Further, this file only contains the
10
//      code for the general case of an FFT stage: the special cases of the
11
//      two final stages are described in other files.
12 36 dgisselq
//
13
// Creator:     Dan Gisselquist, Ph.D.
14
//              Gisselquist Technology, LLC
15
//
16
////////////////////////////////////////////////////////////////////////////////
17
//
18
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
19
//
20
// This program is free software (firmware): you can redistribute it and/or
21
// modify it under the terms of  the GNU General Public License as published
22
// by the Free Software Foundation, either version 3 of the License, or (at
23
// your option) any later version.
24
//
25
// This program is distributed in the hope that it will be useful, but WITHOUT
26
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
27
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
28
// for more details.
29
//
30
// You should have received a copy of the GNU General Public License along
31 37 dgisselq
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
32 36 dgisselq
// target there if the PDF file isn't present.)  If not, see
33
// <http://www.gnu.org/licenses/> for a copy.
34
//
35
// License:     GPL, v3, as defined and found on www.gnu.org,
36
//              http://www.gnu.org/licenses/gpl.html
37
//
38
//
39
////////////////////////////////////////////////////////////////////////////////
40
//
41
//
42
#define _CRT_SECURE_NO_WARNINGS   //  ms vs 2012 doesn't like fopen
43
#include <stdio.h>
44
#include <stdlib.h>
45
 
46
#ifdef _MSC_VER //  added for ms vs compatibility
47
 
48
#include <io.h>
49
#include <direct.h>
50
#define _USE_MATH_DEFINES
51
 
52
#else
53
// And for G++/Linux environment
54
 
55
#include <unistd.h>     // Defines the R_OK/W_OK/etc. macros
56
#endif
57
 
58
#include <string.h>
59
#include <string>
60
#include <math.h>
61
#include <ctype.h>
62
#include <assert.h>
63
 
64
#include "defaults.h"
65
#include "legal.h"
66
#include "fftlib.h"
67
#include "rounding.h"
68
#include "bldstage.h"
69
 
70 37 dgisselq
//
71
// Builds the penultimate FFT stage, using integer operations only.
72
// This stage is called laststage elsewhere.
73
//
74 36 dgisselq
void    build_dblstage(const char *fname, ROUND_T rounding,
75
                        const bool async_reset, const bool dbg) {
76
        FILE    *fp = fopen(fname, "w");
77
        if (NULL == fp) {
78
                fprintf(stderr, "Could not open \'%s\' for writing\n", fname);
79
                perror("O/S Err was:");
80
                return;
81
        }
82
 
83
        const   char    *rnd_string;
84
        if (rounding == RND_TRUNCATE)
85
                rnd_string = "truncate";
86
        else if (rounding == RND_FROMZERO)
87
                rnd_string = "roundfromzero";
88
        else if (rounding == RND_HALFUP)
89
                rnd_string = "roundhalfup";
90
        else
91
                rnd_string = "convround";
92
 
93
        std::string     resetw("i_reset");
94
        if (async_reset)
95
                resetw = std::string("i_areset_n");
96
 
97
 
98
        fprintf(fp,
99
SLASHLINE
100
"//\n"
101
"// Filename:\tlaststage%s.v\n"
102
"//\n"
103
"// Project:\t%s\n"
104
"//\n"
105
"// Purpose:\tThis is part of an FPGA implementation that will process\n"
106
"//             the final stage of a decimate-in-frequency FFT, running\n"
107
"//     through the data at two samples per clock.  If you notice from the\n"
108
"//     derivation of an FFT, the only time both even and odd samples are\n"
109
"//     used at the same time is in this stage.  Therefore, other than this\n"
110
"//     stage and these twiddles, all of the other stages can run two stages\n"
111
"//     at a time at one sample per clock.\n"
112
"//\n"
113
"// Operation:\n"
114
"//     Given a stream of values, operate upon them as though they were\n"
115
"//     value pairs, x[2n] and x[2n+1].  The stream begins when n=0, and ends\n"
116
"//     when n=1.  When the first x[0] value enters, the synchronization\n"
117
"//     input, i_sync, must be true as well.\n"
118
"//\n"
119
"//     For this stream, produce outputs\n"
120
"//     y[2n  ] = x[2n] + x[2n+1], and\n"
121
"//     y[2n+1] = x[2n] - x[2n+1]\n"
122
"//\n"
123
"//     When y[0] is output, a synchronization bit o_sync will be true as\n"
124
"//     well, otherwise it will be zero.\n"
125
"//\n"
126
"//\n"
127
"//     In this implementation, the output is valid one clock after the input\n"
128
"//     is valid.  The output also accumulates one bit above and beyond the\n"
129
"//     number of bits in the input.\n"
130
"//\n"
131
"//             i_clk   A system clock\n", (dbg)?"_dbg":"", prjname);
132
        if (async_reset)
133
                fprintf(fp,
134
"//             i_areset_n      An active low asynchronous reset\n");
135
        else
136
                fprintf(fp,
137
"//             i_reset A synchronous reset\n");
138
 
139
        fprintf(fp,
140
"//             i_ce    Circuit enable--nothing happens unless this line is high\n"
141
"//             i_sync  A synchronization signal, high once per FFT at the start\n"
142
"//             i_left  The first (even) complex sample input.  The higher order\n"
143
"//                     bits contain the real portion, low order bits the\n"
144
"//                     imaginary portion, all in two\'s complement.\n"
145
"//             i_right The next (odd) complex sample input, same format as\n"
146
"//                     i_left.\n"
147
"//             o_left  The first (even) complex output.\n"
148
"//             o_right The next (odd) complex output.\n"
149
"//             o_sync  Output synchronization signal.\n"
150
"//\n%s"
151
"//\n", creator);
152
 
153
        fprintf(fp, "%s", cpyleft);
154
        fprintf(fp, "//\n//\n`default_nettype\tnone\n//\n");
155
        fprintf(fp,
156
"module\tlaststage%s(i_clk, %s, i_ce, i_sync, i_left, i_right, o_left, o_right, o_sync%s);\n"
157
        "\tparameter\tIWIDTH=%d,OWIDTH=IWIDTH+1, SHIFT=%d;\n"
158 37 dgisselq
        "\tinput\twire\ti_clk, %s, i_ce, i_sync;\n"
159
        "\tinput\twire\t[(2*IWIDTH-1):0]\ti_left, i_right;\n"
160 36 dgisselq
        "\toutput\treg\t[(2*OWIDTH-1):0]\to_left, o_right;\n"
161
        "\toutput\treg\t\t\to_sync;\n"
162
        "\n", (dbg)?"_dbg":"", resetw.c_str(), (dbg)?", o_dbg":"",
163
        TST_DBLSTAGE_IWIDTH, TST_DBLSTAGE_SHIFT,
164
                resetw.c_str());
165
 
166
        if (dbg) { fprintf(fp, "\toutput\twire\t[33:0]\t\t\to_dbg;\n"
167
                "\tassign\to_dbg = { ((o_sync)&&(i_ce)), i_ce, o_left[(2*OWIDTH-1):(2*OWIDTH-16)],\n"
168
                        "\t\t\t\t\to_left[(OWIDTH-1):(OWIDTH-16)] };\n"
169
"\n");
170
        }
171
        fprintf(fp,
172
        "\twire\tsigned\t[(IWIDTH-1):0]\ti_in_0r, i_in_0i, i_in_1r, i_in_1i;\n"
173
        "\tassign\ti_in_0r = i_left[(2*IWIDTH-1):(IWIDTH)];\n"
174
        "\tassign\ti_in_0i = i_left[(IWIDTH-1):0];\n"
175
        "\tassign\ti_in_1r = i_right[(2*IWIDTH-1):(IWIDTH)];\n"
176
        "\tassign\ti_in_1i = i_right[(IWIDTH-1):0];\n"
177
        "\twire\t[(OWIDTH-1):0]\t\to_out_0r, o_out_0i,\n"
178
                                "\t\t\t\t\to_out_1r, o_out_1i;\n"
179
"\n"
180
"\n"
181
        "\t// Handle a potential rounding situation, when IWIDTH>=OWIDTH.\n"
182
"\n"
183
"\n");
184
        fprintf(fp,
185
        "\n"
186
        "\t// As with any register connected to the sync pulse, these must\n"
187
        "\t// have initial values and be reset on the %s signal.\n"
188
        "\t// Other data values need only restrict their updates to i_ce\n"
189
        "\t// enabled clocks, but sync\'s must obey resets and initial\n"
190
        "\t// conditions as well.\n"
191
        "\treg\trnd_sync, r_sync;\n"
192
"\n"
193
        "\tinitial\trnd_sync      = 1\'b0; // Sync into rounding\n"
194
        "\tinitial\tr_sync        = 1\'b0; // Sync coming out\n",
195
                resetw.c_str());
196
        if (async_reset)
197 37 dgisselq
                fprintf(fp, "\talways @(posedge i_clk, negdge i_areset_n)\n\tif (!i_areset_n)\n");
198 36 dgisselq
        else
199 37 dgisselq
                fprintf(fp, "\talways @(posedge i_clk)\n\tif (i_reset)\n");
200 36 dgisselq
        fprintf(fp,
201
                "\t\tbegin\n"
202
                        "\t\t\trnd_sync <= 1\'b0;\n"
203
                        "\t\t\tr_sync <= 1\'b0;\n"
204
                "\t\tend else if (i_ce)\n"
205
                "\t\tbegin\n"
206
                        "\t\t\trnd_sync <= i_sync;\n"
207
                        "\t\t\tr_sync <= rnd_sync;\n"
208
                "\t\tend\n"
209
"\n"
210
        "\t// As with other variables, these are really only updated when in\n"
211
        "\t// the processing pipeline, after the first i_sync.  However, to\n"
212
        "\t// eliminate as much unnecessary logic as possible, we toggle\n"
213
        "\t// these any time the i_ce line is enabled, and don\'t reset.\n"
214
        "\t// them on %s.\n", resetw.c_str());
215
        fprintf(fp,
216
        "\t// Don't forget that we accumulate a bit by adding two values\n"
217
        "\t// together. Therefore our intermediate value must have one more\n"
218
        "\t// bit than the two originals.\n"
219
        "\treg\tsigned\t[(IWIDTH):0]\trnd_in_0r, rnd_in_0i;\n"
220
        "\treg\tsigned\t[(IWIDTH):0]\trnd_in_1r, rnd_in_1i;\n\n"
221
        "\talways @(posedge i_clk)\n"
222
                "\t\tif (i_ce)\n"
223
                "\t\tbegin\n"
224
                        "\t\t\t//\n"
225
                        "\t\t\trnd_in_0r <= i_in_0r + i_in_1r;\n"
226
                        "\t\t\trnd_in_0i <= i_in_0i + i_in_1i;\n"
227
                        "\t\t\t//\n"
228
                        "\t\t\trnd_in_1r <= i_in_0r - i_in_1r;\n"
229
                        "\t\t\trnd_in_1i <= i_in_0i - i_in_1i;\n"
230
                        "\t\t\t//\n"
231
                "\t\tend\n"
232
"\n");
233
        fprintf(fp,
234
        "\t%s #(IWIDTH+1,OWIDTH,SHIFT) do_rnd_0r(i_clk, i_ce,\n"
235
        "\t\t\t\t\t\t\trnd_in_0r, o_out_0r);\n\n", rnd_string);
236
        fprintf(fp,
237
        "\t%s #(IWIDTH+1,OWIDTH,SHIFT) do_rnd_0i(i_clk, i_ce,\n"
238
        "\t\t\t\t\t\t\trnd_in_0i, o_out_0i);\n\n", rnd_string);
239
        fprintf(fp,
240
        "\t%s #(IWIDTH+1,OWIDTH,SHIFT) do_rnd_1r(i_clk, i_ce,\n"
241
        "\t\t\t\t\t\t\trnd_in_1r, o_out_1r);\n\n", rnd_string);
242
        fprintf(fp,
243
        "\t%s #(IWIDTH+1,OWIDTH,SHIFT) do_rnd_1i(i_clk, i_ce,\n"
244
        "\t\t\t\t\t\t\trnd_in_1i, o_out_1i);\n\n", rnd_string);
245
 
246
        fprintf(fp, "\n"
247
        "\t// Prior versions of this routine did not include the extra\n"
248
        "\t// clock and register/flip-flops that this routine requires.\n"
249
        "\t// These are placed in here to correct a bug in Verilator, that\n"
250
        "\t// otherwise struggles.  (Hopefully this will fix the problem ...)\n"
251
        "\talways @(posedge i_clk)\n"
252
                "\t\tif (i_ce)\n"
253
                "\t\tbegin\n"
254
                        "\t\t\to_left  <= { o_out_0r, o_out_0i };\n"
255
                        "\t\t\to_right <= { o_out_1r, o_out_1i };\n"
256
                "\t\tend\n"
257
"\n"
258
        "\tinitial\to_sync = 1\'b0; // Final sync coming out of module\n");
259
        if (async_reset)
260
                fprintf(fp, "\talways @(posedge i_clk, negdge i_areset_n)\n\t\tif (!i_areset_n)\n");
261
        else
262 37 dgisselq
                fprintf(fp, "\talways @(posedge i_clk)\n\tif (i_reset)\n");
263 36 dgisselq
        fprintf(fp,
264
                "\t\t\to_sync <= 1\'b0;\n"
265
                "\t\telse if (i_ce)\n"
266
                "\t\t\to_sync <= r_sync;\n"
267
"\n"
268
"endmodule\n");
269
        fclose(fp);
270
}
271
 
272
void    build_stage(const char *fname,
273
                int stage, int nwide, int offset,
274
                int nbits, int xtra, int ckpce,
275
                const bool async_reset, const bool dbg) {
276
        FILE    *fstage = fopen(fname, "w");
277
        int     cbits = nbits + xtra;
278
 
279
        std::string     resetw("i_reset");
280
        if (async_reset)
281
                resetw = std::string("i_areset_n");
282
 
283
        if (((unsigned)cbits * 2u) >= sizeof(long long)*8) {
284
                fprintf(stderr, "ERROR: CMEM Coefficient precision requested overflows long long data type.\n");
285
                exit(-1);
286
        }
287
 
288
        if (fstage == NULL) {
289
                fprintf(stderr, "ERROR: Could not open %s for writing!\n", fname);
290
                perror("O/S Err was:");
291
                fprintf(stderr, "Attempting to continue, but this file will be missing.\n");
292
                return;
293
        }
294
 
295
        fprintf(fstage,
296
SLASHLINE
297
"//\n"
298
"// Filename:\tfftstage%s.v\n"
299
"//\n"
300
"// Project:\t%s\n"
301
"//\n"
302
"// Purpose:\tThis file is (almost) a Verilog source file.  It is meant to\n"
303
"//             be used by a FFT core compiler to generate FFTs which may be\n"
304
"//     used as part of an FFT core.  Specifically, this file encapsulates\n"
305
"//     the options of an FFT-stage.  For any 2^N length FFT, there shall be\n"
306
"//     (N-1) of these stages.\n"
307
"//\n"
308
"//\n"
309
"// Operation:\n"
310
"//     Given a stream of values, operate upon them as though they were\n"
311
"//     value pairs, x[n] and x[n+N/2].  The stream begins when n=0, and ends\n"
312
"//     when n=N/2-1 (i.e. there's a full set of N values).  When the value\n"
313
"//     x[0] enters, the synchronization input, i_sync, must be true as well.\n"
314
"//\n"
315
"//     For this stream, produce outputs\n"
316
"//     y[n    ] = x[n] + x[n+N/2], and\n"
317
"//     y[n+N/2] = (x[n] - x[n+N/2]) * c[n],\n"
318
"//                     where c[n] is a complex coefficient found in the\n"
319
"//                     external memory file COEFFILE.\n"
320
"//     When y[0] is output, a synchronization bit o_sync will be true as\n"
321
"//     well, otherwise it will be zero.\n"
322
"//\n"
323
"//     Most of the work to do this is done within the butterfly, whether the\n"
324
"//     hardware accelerated butterfly (uses a DSP) or not.\n"
325
"//\n%s"
326
"//\n",
327
                (dbg)?"_dbg":"", prjname, creator);
328
        fprintf(fstage, "%s", cpyleft);
329
        fprintf(fstage, "//\n//\n`default_nettype\tnone\n//\n");
330
        fprintf(fstage, "module\tfftstage%s(i_clk, %s, i_ce, i_sync, i_data, o_data, o_sync%s);\n",
331
                (dbg)?"_dbg":"", resetw.c_str(),
332
                (dbg)?", o_dbg":"");
333
        // These parameter values are useless at this point--they are to be
334
        // replaced by the parameter values in the calling program.  Only
335
        // problem is, the CWIDTH needs to match exactly!
336
        fprintf(fstage, "\tparameter\tIWIDTH=%d,CWIDTH=%d,OWIDTH=%d;\n",
337
                nbits, 20, nbits+1); // 20, not cbits, since the tb depends upon it
338
        fprintf(fstage,
339
"\t// Parameters specific to the core that should be changed when this\n"
340
"\t// core is built ... Note that the minimum LGSPAN (the base two log\n"
341
"\t// of the span, or the base two log of the current FFT size) is 3.\n"
342
"\t// Smaller spans (i.e. the span of 2) must use the dbl laststage module.\n"
343 37 dgisselq
"\tparameter\tLGSPAN=%d, BFLYSHIFT=0; // LGWIDTH=%d\n"
344 36 dgisselq
"\tparameter\t[0:0]     OPT_HWMPY = 1;\n",
345 37 dgisselq
                (nwide <= 1) ? lgval(stage)-1 : lgval(stage)-2, lgval(stage));
346 36 dgisselq
        fprintf(fstage,
347
"\t// Clocks per CE.  If your incoming data rate is less than 50%% of your\n"
348
"\t// clock speed, you can set CKPCE to 2\'b10, make sure there's at least\n"
349
"\t// one clock between cycles when i_ce is high, and then use two\n"
350
"\t// multiplies instead of three.  Setting CKPCE to 2\'b11, and insisting\n"
351
"\t// on at least two clocks with i_ce low between cycles with i_ce high,\n"
352
"\t// then the hardware optimized butterfly code will used one multiply\n"
353
"\t// instead of two.\n"
354
"\tparameter\t  CKPCE = %d;\n", ckpce);
355
 
356
        fprintf(fstage,
357
"\t// The COEFFILE parameter contains the name of the file containing the\n"
358
"\t// FFT twiddle factors\n");
359
        if (nwide == 2) {
360
                fprintf(fstage, "\tparameter\tCOEFFILE=\"cmem_%c%d.hex\";\n",
361
                        (offset)?'o':'e', stage*2);
362
        } else
363
                fprintf(fstage, "\tparameter\tCOEFFILE=\"cmem_%d.hex\";\n",
364
                        stage);
365
 
366
        fprintf(fstage,"\n"
367
"`ifdef VERILATOR\n"
368
        "\tparameter [0:0] ZERO_ON_IDLE = 1'b0;\n"
369
"`else\n"
370
        "\tlocalparam [0:0] ZERO_ON_IDLE = 1'b0;\n"
371
"`endif // VERILATOR\n\n");
372
 
373
        fprintf(fstage,
374 37 dgisselq
"\tinput        wire                            i_clk, %s, i_ce, i_sync;\n"
375
"\tinput        wire    [(2*IWIDTH-1):0]        i_data;\n"
376 36 dgisselq
"\toutput       reg     [(2*OWIDTH-1):0]        o_data;\n"
377
"\toutput       reg                             o_sync;\n"
378
"\n", resetw.c_str());
379
        if (dbg) { fprintf(fstage, "\toutput\twire\t[33:0]\t\t\to_dbg;\n"
380
                "\tassign\to_dbg = { ((o_sync)&&(i_ce)), i_ce, o_data[(2*OWIDTH-1):(2*OWIDTH-16)],\n"
381
                        "\t\t\t\t\to_data[(OWIDTH-1):(OWIDTH-16)] };\n"
382
"\n");
383
        }
384
        fprintf(fstage,
385 37 dgisselq
        "\t// I am using the prefixes\n"
386
        "\t//   ib_*    to reference the inputs to the butterfly, and\n"
387
        "\t//   ob_*    to reference the outputs from the butterfly\n"
388
        "\treg  wait_for_sync;\n"
389
        "\treg  [(2*IWIDTH-1):0]        ib_a, ib_b;\n"
390
        "\treg  [(2*CWIDTH-1):0]        ib_c;\n"
391
        "\treg  ib_sync;\n"
392 36 dgisselq
"\n"
393 37 dgisselq
        "\treg  b_started;\n"
394
        "\twire ob_sync;\n"
395
        "\twire [(2*OWIDTH-1):0]\tob_a, ob_b;\n");
396 36 dgisselq
        fprintf(fstage,
397
"\n"
398
"\t// cmem is defined as an array of real and complex values,\n"
399
"\t// where the top CWIDTH bits are the real value and the bottom\n"
400
"\t// CWIDTH bits are the imaginary value.\n"
401
"\t//\n"
402
"\t// cmem[i] = { (2^(CWIDTH-2)) * cos(2*pi*i/(2^LGWIDTH)),\n"
403
"\t//           (2^(CWIDTH-2)) * sin(2*pi*i/(2^LGWIDTH)) };\n"
404
"\t//\n"
405 37 dgisselq
"\treg  [(2*CWIDTH-1):0]        cmem [0:((1<<LGSPAN)-1)];\n");
406 36 dgisselq
 
407 37 dgisselq
        if (formal_property_flag)
408
                fprintf(fstage,
409
                        "`ifdef FORMAL\n"
410
                        "// Let the formal tool pick the coefficients\n"
411
                        "`else\n");
412
        fprintf(fstage, "\tinitial\t$readmemh(COEFFILE,cmem);\n\n");
413
        if (formal_property_flag)
414
                fprintf(fstage, "`endif\n\n");
415
 
416 36 dgisselq
        // gen_coeff_file(coredir, fname, stage, cbits, nwide, offset, inv);
417
 
418
        fprintf(fstage,
419
"\treg  [(LGSPAN):0]            iaddr;\n"
420
"\treg  [(2*IWIDTH-1):0]        imem    [0:((1<<LGSPAN)-1)];\n"
421
"\n"
422 37 dgisselq
"\treg  [LGSPAN:0]              oaddr;\n"
423 36 dgisselq
"\treg  [(2*OWIDTH-1):0]        omem    [0:((1<<LGSPAN)-1)];\n"
424
"\n"
425
"\tinitial wait_for_sync = 1\'b1;\n"
426
"\tinitial iaddr = 0;\n");
427
        if (async_reset)
428 37 dgisselq
                fprintf(fstage, "\talways @(posedge i_clk, negedge i_areset_n)\n\tif (!i_areset_n)\n");
429 36 dgisselq
        else
430 37 dgisselq
                fprintf(fstage, "\talways @(posedge i_clk)\n\tif (i_reset)\n");
431 36 dgisselq
 
432
        fprintf(fstage,
433
        "\tbegin\n"
434 37 dgisselq
                "\t\twait_for_sync <= 1\'b1;\n"
435
                "\t\tiaddr <= 0;\n"
436 36 dgisselq
        "\tend else if ((i_ce)&&((!wait_for_sync)||(i_sync)))\n"
437
        "\tbegin\n"
438
                "\t\t//\n"
439
                "\t\t// First step: Record what we\'re not ready to use yet\n"
440
                "\t\t//\n"
441
                "\t\tiaddr <= iaddr + { {(LGSPAN){1\'b0}}, 1\'b1 };\n"
442
                "\t\twait_for_sync <= 1\'b0;\n"
443
        "\tend\n"
444
        "\talways @(posedge i_clk) // Need to make certain here that we don\'t read\n"
445
        "\tif ((i_ce)&&(!iaddr[LGSPAN])) // and write the same address on\n"
446
                "\t\timem[iaddr[(LGSPAN-1):0]] <= i_data; // the same clk\n"
447
        "\n");
448
 
449
        fprintf(fstage,
450
        "\t//\n"
451
        "\t// Now, we have all the inputs, so let\'s feed the butterfly\n"
452
        "\t//\n"
453 37 dgisselq
        "\t// ib_sync is the synchronization bit to the butterfly.  It will\n"
454
        "\t// be tracked within the butterfly, and used to create the o_sync\n"
455
        "\t// value when the results from this output are produced\n"
456 36 dgisselq
        "\tinitial ib_sync = 1\'b0;\n");
457
        if (async_reset)
458
                fprintf(fstage, "\talways @(posedge i_clk, negedge i_areset_n)\n\tif (!i_areset_n)\n");
459
        else
460
                fprintf(fstage, "\talways @(posedge i_clk)\n\tif (i_reset)\n");
461
        fprintf(fstage,
462
                        "\t\tib_sync <= 1\'b0;\n"
463
                "\telse if (i_ce)\n"
464
                "\tbegin\n"
465
                        "\t\t// Set the sync to true on the very first\n"
466
                        "\t\t// valid input in, and hence on the very\n"
467
                        "\t\t// first valid data out per FFT.\n"
468
                        "\t\tib_sync <= (iaddr==(1<<(LGSPAN)));\n"
469
                "\tend\n\n"
470 37 dgisselq
        "\t// Read the values from our input memory, and use them to feed first of two\n"
471
        "\t// butterfly inputs\n"
472 36 dgisselq
        "\talways\t@(posedge i_clk)\n"
473
        "\tif (i_ce)\n"
474
        "\tbegin\n"
475
                "\t\t// One input from memory, ...\n"
476
                "\t\tib_a <= imem[iaddr[(LGSPAN-1):0]];\n"
477
                "\t\t// One input clocked in from the top\n"
478
                "\t\tib_b <= i_data;\n"
479
                "\t\t// and the coefficient or twiddle factor\n"
480
                "\t\tib_c <= cmem[iaddr[(LGSPAN-1):0]];\n"
481
        "\tend\n\n");
482
 
483
        fprintf(fstage,
484
        "\t// The idle register is designed to keep track of when an input\n"
485
        "\t// to the butterfly is important and going to be used.  It's used\n"
486
        "\t// in a flag following, so that when useful values are placed\n"
487
        "\t// into the butterfly they'll be non-zero (idle=0), otherwise when\n"
488
        "\t// the inputs to the butterfly are irrelevant and will be ignored,\n"
489
        "\t// then (idle=1) those inputs will be set to zero.  This\n"
490
        "\t// functionality is not designed to be used in operation, but only\n"
491
        "\t// within a Verilator simulation context when chasing a bug.\n"
492
        "\t// In this limited environment, the non-zero answers will stand\n"
493
        "\t// in a trace making it easier to highlight a bug.\n"
494
        "\treg  idle;\n"
495
        "\tgenerate if (ZERO_ON_IDLE)\n"
496
        "\tbegin\n"
497
                "\t\tinitial    idle = 1;\n"
498
                "\t\talways @(posedge i_clk)\n"
499
                "\t\tif (i_reset)\n"
500
                        "\t\t\tidle <= 1\'b1;\n"
501
                "\t\telse if (i_ce)\n"
502
                        "\t\t\tidle <= (!iaddr[LGSPAN])&&(!wait_for_sync);\n\n"
503
        "\tend else begin\n\n"
504
        "\t\talways @(*) idle = 0;\n\n"
505
        "\tend endgenerate\n\n");
506
 
507 37 dgisselq
        if (formal_property_flag)
508
                fprintf(fstage,
509
"// For the formal proof, we'll assume the outputs of hwbfly and/or\n"
510
"// butterfly, rather than actually calculating them.  This will simplify\n"
511
"// the proof and (if done properly) will be equivalent.  Be careful of\n"
512
"// defining FORMAL if you want the full logic!\n"
513
"`ifndef        FORMAL\n"
514
        "\t//\n");
515
 
516 36 dgisselq
        fprintf(fstage,
517
"\tgenerate if (OPT_HWMPY)\n"
518
"\tbegin : HWBFLY\n"
519
"\t\thwbfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),\n"
520
                        "\t\t\t\t.CKPCE(CKPCE), .SHIFT(BFLYSHIFT))\n"
521
                "\t\t\tbfly(i_clk, %s, i_ce, (idle)?0:ib_c,\n"
522
                        "\t\t\t\t(idle || (!i_ce)) ? 0:ib_a,\n"
523
                        "\t\t\t\t(idle || (!i_ce)) ? 0:ib_b,\n"
524
                        "\t\t\t\t(ib_sync)&&(i_ce),\n"
525
                        "\t\t\t\tob_a, ob_b, ob_sync);\n"
526
"\tend else begin : FWBFLY\n"
527
"\t\tbutterfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),\n"
528
                "\t\t\t\t.CKPCE(CKPCE),.SHIFT(BFLYSHIFT))\n"
529
        "\t\t\tbfly(i_clk, %s, i_ce,\n"
530
                        "\t\t\t\t\t(idle||(!i_ce))?0:ib_c,\n"
531
                        "\t\t\t\t\t(idle||(!i_ce))?0:ib_a,\n"
532
                        "\t\t\t\t\t(idle||(!i_ce))?0:ib_b,\n"
533
                        "\t\t\t\t\t(ib_sync&&i_ce),\n"
534
                        "\t\t\t\t\tob_a, ob_b, ob_sync);\n"
535 37 dgisselq
"\tend endgenerate\n",
536 36 dgisselq
                        resetw.c_str(), resetw.c_str());
537
 
538 37 dgisselq
        if (formal_property_flag)
539
                fprintf(fstage, "`endif\n\n");
540
 
541 36 dgisselq
        fprintf(fstage,
542
        "\t//\n"
543
        "\t// Next step: recover the outputs from the butterfly\n"
544
        "\t//\n"
545 37 dgisselq
        "\t// The first output can go immediately to the output of this routine\n"
546
        "\t// The second output must wait until this time in the idle cycle\n"
547
        "\t// oaddr is the output memory address, keeping track of where we are\n"
548
        "\t// in this output cycle.\n"
549
        "\tinitial oaddr     = 0;\n"
550 36 dgisselq
        "\tinitial o_sync    = 0;\n"
551
        "\tinitial b_started = 0;\n");
552
        if (async_reset)
553 37 dgisselq
                fprintf(fstage, "\talways @(posedge i_clk, negedge i_areset_n)\n\tif (!i_areset_n)\n");
554 36 dgisselq
        else
555 37 dgisselq
                fprintf(fstage, "\talways @(posedge i_clk)\n\tif (i_reset)\n");
556 36 dgisselq
        fprintf(fstage,
557
        "\tbegin\n"
558 37 dgisselq
                "\t\toaddr     <= 0;\n"
559
                "\t\to_sync    <= 0;\n"
560
                "\t\t// b_started will be true once we've seen the first ob_sync\n"
561 36 dgisselq
                "\t\tb_started <= 0;\n"
562
        "\tend else if (i_ce)\n"
563
        "\tbegin\n"
564 37 dgisselq
        "\t\to_sync <= (!oaddr[LGSPAN])?ob_sync : 1\'b0;\n"
565 36 dgisselq
        "\t\tif (ob_sync||b_started)\n"
566 37 dgisselq
                "\t\t\toaddr <= oaddr + 1\'b1;\n"
567
        "\t\tif ((ob_sync)&&(!oaddr[LGSPAN]))\n"
568
                "\t\t\t// If b_started is true, then a butterfly output is available\n"
569 36 dgisselq
                        "\t\t\tb_started <= 1\'b1;\n"
570
        "\tend\n\n");
571
        fprintf(fstage,
572 37 dgisselq
        "\treg  [(LGSPAN-1):0]\t\tnxt_oaddr;\n"
573
        "\treg  [(2*OWIDTH-1):0]\tpre_ovalue;\n"
574 36 dgisselq
        "\talways @(posedge i_clk)\n"
575
        "\tif (i_ce)\n"
576 37 dgisselq
                "\t\tnxt_oaddr[0] <= oaddr[0];\n"
577
        "\tgenerate if (LGSPAN>1)\n"
578 36 dgisselq
        "\tbegin\n"
579 37 dgisselq
"\n"
580
        "\t\talways @(posedge i_clk)\n"
581
        "\t\tif (i_ce)\n"
582
                "\t\t\tnxt_oaddr[LGSPAN-1:1] <= oaddr[LGSPAN-1:1] + 1\'b1;\n"
583
"\n"
584
        "\tend endgenerate\n"
585
"\n"
586
        "\t// Only write to the memory on the first half of the outputs\n"
587
        "\t// We'll use the memory value on the second half of the outputs\n"
588 36 dgisselq
        "\talways @(posedge i_clk)\n"
589 37 dgisselq
        "\tif ((i_ce)&&(!oaddr[LGSPAN]))\n"
590
                "\t\tomem[oaddr[(LGSPAN-1):0]] <= ob_b;\n\n");
591
 
592
        fprintf(fstage,
593
        "\talways @(posedge i_clk)\n"
594 36 dgisselq
        "\tif (i_ce)\n"
595 37 dgisselq
                "\t\tpre_ovalue <= omem[nxt_oaddr[(LGSPAN-1):0]];\n"
596 36 dgisselq
"\n");
597
        fprintf(fstage,
598
        "\talways @(posedge i_clk)\n"
599
        "\tif (i_ce)\n"
600 37 dgisselq
        "\t\to_data <= (!oaddr[LGSPAN]) ? ob_a : pre_ovalue;\n"
601 36 dgisselq
"\n");
602 37 dgisselq
 
603
        fprintf(fstage,
604
"`ifdef FORMAL\n");
605
 
606
 
607
        if (formal_property_flag) {
608
 
609
        fprintf(fstage,
610
        "\t// An arbitrary processing delay from butterfly input to\n"
611
        "\t// butterfly output(s)\n"
612
        "\t(* anyconst *) reg   [LGSPAN:0]      f_mpydelay;\n"
613
        "\talways @(*)\n"
614
        "\t\tassume(f_mpydelay > 1);\n"
615
"\n"
616
        "\treg  f_past_valid;\n"
617
        "\tinitial      f_past_valid = 1'b0;\n"
618
        "\talways @(posedge i_clk)\n"
619
                "\t\tf_past_valid <= 1'b1;\n"
620
"\n");
621
 
622
        if (async_reset)
623
                fprintf(fstage, "\talways @(*)\n\tif ((!f_past_valid)||(!i_areset_n))\n");
624
        else
625
                fprintf(fstage, "\talways @(posedge i_clk)\n"
626
                                "\tif ((!f_past_valid)||($past(i_reset)))\n");
627
        fprintf(fstage,
628
        "\tbegin\n"
629
                "\t\tassert(iaddr == 0);\n"
630
                "\t\tassert(wait_for_sync);\n"
631
                "\t\tassert(o_sync == 0);\n"
632
                "\t\tassert(oaddr == 0);\n"
633
                "\t\tassert(!b_started);\n"
634
                "\t\tassert(!o_sync);\n"
635
        "\tend\n\n");
636
 
637
        fprintf(fstage,
638
        "\t/////////////////////////////////////////\n"
639
        "\t//\n"
640
        "\t// Formally verify the input half, from the inputs to this module\n"
641
        "\t// to the inputs of the butterfly\n"
642
        "\t//\n"
643
        "\t/////////////////////////////////////////\n"
644
        "\t//\n"
645
        "\t// Let's  verify a specific set of inputs\n"
646
        "\t(* anyconst *)       reg     [LGSPAN:0]      f_addr;\n"
647
        "\treg  [2*IWIDTH-1:0]                  f_left, f_right;\n"
648
        "\twire [LGSPAN:0]                      f_next_addr;\n"
649
"\n"
650
        "\talways @(posedge i_clk)\n"
651
        "\tif ((!$past(i_ce))&&(!$past(i_ce,2))&&(!$past(i_ce,3))&&(!$past(i_ce,4)))\n"
652
                "\tassume(!i_ce);\n"
653
"\n"
654
        "\talways @(*)\n"
655
                "\t\tassume(f_addr[LGSPAN]==1'b0);\n"
656
"\n"
657
        "\tassign\tf_next_addr = f_addr + 1'b1;\n"
658
"\n"
659
        "\talways @(posedge i_clk)\n"
660
        "\tif ((i_ce)&&(iaddr[LGSPAN:0] == f_addr))\n"
661
                "\t\tf_left <= i_data;\n"
662
"\n"
663
        "\talways @(*)\n"
664
        "\tif (wait_for_sync)\n"
665
                "\t\tassert(iaddr == 0);\n"
666
"\n"
667
        "\twire [LGSPAN:0]\tf_last_addr = iaddr - 1'b1;\n"
668
"\n"
669
        "\talways @(posedge i_clk)\n"
670
        "\tif ((!wait_for_sync)&&(f_last_addr >= { 1'b0, f_addr[LGSPAN-1:0]}))\n"
671
                "\t\tassert(f_left == imem[f_addr[LGSPAN-1:0]]);\n"
672
"\n"
673
        "\talways @(posedge i_clk)\n"
674
        "\tif ((i_ce)&&(iaddr == { 1'b1, f_addr[LGSPAN-1:0]}))\n"
675
                "\t\tf_right <= i_data;\n"
676
"\n"
677
        "\talways @(posedge i_clk)\n"
678
        "\tif ((i_ce)&&(!wait_for_sync)&&(f_last_addr == { 1'b1, f_addr[LGSPAN-1:0]}))\n"
679
        "\tbegin\n"
680
                "\t\tassert(ib_a == f_left);\n"
681
                "\t\tassert(ib_b == f_right);\n"
682
                "\t\tassert(ib_c == cmem[f_addr[LGSPAN-1:0]]);\n"
683
        "\tend\n\n");
684
 
685
        fprintf(fstage,
686
        "\t/////////////////////////////////////////\n"
687
        "\t//\n"
688
        "\t// Formally verify the output half, from the output of the butterfly\n"
689
        "\t// to the outputs of this module\n"
690
        "\t//\n"
691
        "\t/////////////////////////////////////////\n"
692
        "\treg  [2*OWIDTH-1:0]  f_oleft, f_oright;\n"
693
        "\treg  [LGSPAN:0]      f_oaddr;\n"
694
        "\twire [LGSPAN:0]      f_oaddr_m1 = f_oaddr - 1'b1;\n\n");
695
 
696
        fprintf(fstage,
697
        "\talways @(*)\n"
698
                "\t\tf_oaddr = iaddr - f_mpydelay + {1'b1,{(LGSPAN-1){1'b0}}};\n"
699
"\n"
700
        "\tassign\tf_oaddr_m1 = f_oaddr - 1'b1;\n"
701
"\n");
702
 
703
        fprintf(fstage,
704
        "\treg  f_output_active;\n"
705
        "\tinitial\tf_output_active = 1'b0;\n");
706
        if (async_reset)
707
                fprintf(fstage, "\talways @(posedge i_clk, negedge i_areset_n)\n\tif (!i_areset_n)\n");
708
        else
709
                fprintf(fstage, "\talways @(posedge i_clk)\n\tif (i_reset)\n");
710
        fprintf(fstage,
711
                "\t\tf_output_active <= 1'b0;\n"
712
        "\telse if ((i_ce)&&(ob_sync))\n"
713
                "\t\tf_output_active <= 1'b1;\n"
714
"\n"
715
        "\talways @(*)\n"
716
                "\t\tassert(f_output_active == b_started);\n"
717
"\n"
718
        "\talways @(*)\n"
719
        "\tif (wait_for_sync)\n"
720
                "\t\tassert(!f_output_active);\n\n");
721
 
722
        fprintf(fstage,
723
        "\talways @(*)\n"
724
        "\tif (f_output_active)\n"
725
                "\t\tassert(oaddr == f_oaddr);\n"
726
        "\telse\n"
727
                "\t\tassert(oaddr == 0);\n"
728
"\n");
729
 
730
 
731
        fprintf(fstage,
732
        "\talways @(*)\n"
733
        "\tif (wait_for_sync)\n"
734
                "\t\tassume(!ob_sync);\n"
735
"\n"
736
        "\talways @(*)\n"
737
                "\t\tassume(ob_sync == (f_oaddr == 0));\n"
738
"\n"
739
        "\talways @(posedge i_clk)\n"
740
        "\tif ((f_past_valid)&&(!$past(i_ce)))\n"
741
        "\tbegin\n"
742
                "\t\tassume($stable(ob_a));\n"
743
                "\t\tassume($stable(ob_b));\n"
744
        "\tend\n\n");
745
 
746
        fprintf(fstage,
747
        "\tinitial      f_oleft  = 0;\n"
748
        "\tinitial      f_oright = 0;\n"
749
        "\talways @(posedge i_clk)\n"
750
        "\tif ((i_ce)&&(f_oaddr == f_addr))\n"
751
        "\tbegin\n"
752
                "\t\tf_oleft  <= ob_a;\n"
753
                "\t\tf_oright <= ob_b;\n"
754
        "\tend\n"
755
"\n"
756
        "\talways @(posedge i_clk)\n"
757
        "\tif ((f_output_active)&&(f_oaddr_m1 >= { 1'b0, f_addr[LGSPAN-1:0]}))\n"
758
                "\t\tassert(omem[f_addr[LGSPAN-1:0]] == f_oright);\n"
759
"\n"
760
        "\talways @(posedge i_clk)\n"
761
        "\tif ((i_ce)&&(f_oaddr_m1 == 0)&&(f_output_active))\n"
762
                "\t\tassert(o_sync);\n"
763
        "\telse if ((i_ce)||(!f_output_active))\n"
764
                "\t\tassert(!o_sync);\n"
765
        "\n"
766
        "\talways @(posedge i_clk)\n"
767
        "\tif ((i_ce)&&(f_output_active)&&(f_oaddr_m1 == f_addr))\n"
768
                "\t\tassert(o_data == f_oleft);\n"
769
        "\talways @(posedge i_clk)\n"
770
        "\tif ((i_ce)&&(f_output_active)&&(f_oaddr[LGSPAN])\n"
771
                        "\t\t\t&&(f_oaddr[LGSPAN-1:0] == f_addr[LGSPAN-1:0]))\n"
772
                "\t\tassert(pre_ovalue == f_oright);\n"
773
        "\talways @(posedge i_clk)\n"
774
        "\tif ((i_ce)&&(f_output_active)&&(f_oaddr_m1[LGSPAN])\n"
775
                        "\t\t\t&&(f_oaddr_m1[LGSPAN-1:0] == f_addr[LGSPAN-1:0]))\n"
776
                "\t\tassert(o_data == f_oright);\n"
777
"\n");
778
        } else { // If no formal properties
779
                fprintf(fstage, "// Formal properties exist, but are not enabled"
780
                                " in this build\n");
781
        } // End of the formal properties section
782
 
783
        fprintf(fstage,
784
"`endif\n");
785
 
786 36 dgisselq
        fprintf(fstage, "endmodule\n");
787
}

powered by: WebSVN 2.1.0

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