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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [rtl/] [ifftstage.v] - Blame information for rev 39

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 39 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    fftstage.v
4
//
5
// Project:     A General Purpose Pipelined FFT Implementation
6
//
7
// Purpose:     This file is (almost) a Verilog source file.  It is meant to
8
//              be used by a FFT core compiler to generate FFTs which may be
9
//      used as part of an FFT core.  Specifically, this file encapsulates
10
//      the options of an FFT-stage.  For any 2^N length FFT, there shall be
11
//      (N-1) of these stages.
12
//
13
//
14
// Operation:
15
//      Given a stream of values, operate upon them as though they were
16
//      value pairs, x[n] and x[n+N/2].  The stream begins when n=0, and ends
17
//      when n=N/2-1 (i.e. there's a full set of N values).  When the value
18
//      x[0] enters, the synchronization input, i_sync, must be true as well.
19
//
20
//      For this stream, produce outputs
21
//      y[n    ] = x[n] + x[n+N/2], and
22
//      y[n+N/2] = (x[n] - x[n+N/2]) * c[n],
23
//                      where c[n] is a complex coefficient found in the
24
//                      external memory file COEFFILE.
25
//      When y[0] is output, a synchronization bit o_sync will be true as
26
//      well, otherwise it will be zero.
27
//
28
//      Most of the work to do this is done within the butterfly, whether the
29
//      hardware accelerated butterfly (uses a DSP) or not.
30
//
31
// Creator:     Dan Gisselquist, Ph.D.
32
//              Gisselquist Technology, LLC
33
//
34
////////////////////////////////////////////////////////////////////////////////
35
//
36
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
37
//
38
// This program is free software (firmware): you can redistribute it and/or
39
// modify it under the terms of  the GNU General Public License as published
40
// by the Free Software Foundation, either version 3 of the License, or (at
41
// your option) any later version.
42
//
43
// This program is distributed in the hope that it will be useful, but WITHOUT
44
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
45
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
46
// for more details.
47
//
48
// You should have received a copy of the GNU General Public License along
49
// with this program.  (It's in the $(ROOT)/doc directory.  Run make with no
50
// target there if the PDF file isn't present.)  If not, see
51
// <http://www.gnu.org/licenses/> for a copy.
52
//
53
// License:     GPL, v3, as defined and found on www.gnu.org,
54
//              http://www.gnu.org/licenses/gpl.html
55
//
56
//
57
////////////////////////////////////////////////////////////////////////////////
58
//
59
//
60
`default_nettype        none
61
//
62
module  fftstage(i_clk, i_reset, i_ce, i_sync, i_data, o_data, o_sync);
63
        parameter       IWIDTH=15,CWIDTH=20,OWIDTH=16;
64
        // Parameters specific to the core that should be changed when this
65
        // core is built ... Note that the minimum LGSPAN (the base two log
66
        // of the span, or the base two log of the current FFT size) is 3.
67
        // Smaller spans (i.e. the span of 2) must use the dbl laststage module.
68
        parameter       LGSPAN=10, BFLYSHIFT=0; // LGWIDTH=11
69
        parameter       [0:0]     OPT_HWMPY = 1;
70
        // Clocks per CE.  If your incoming data rate is less than 50% of your
71
        // clock speed, you can set CKPCE to 2'b10, make sure there's at least
72
        // one clock between cycles when i_ce is high, and then use two
73
        // multiplies instead of three.  Setting CKPCE to 2'b11, and insisting
74
        // on at least two clocks with i_ce low between cycles with i_ce high,
75
        // then the hardware optimized butterfly code will used one multiply
76
        // instead of two.
77
        parameter               CKPCE = 1;
78
        // The COEFFILE parameter contains the name of the file containing the
79
        // FFT twiddle factors
80
        parameter       COEFFILE="cmem_2048.hex";
81
 
82
`ifdef  VERILATOR
83
        parameter [0:0] ZERO_ON_IDLE = 1'b0;
84
`else
85
        localparam [0:0] ZERO_ON_IDLE = 1'b0;
86
`endif // VERILATOR
87
 
88
        input   wire                            i_clk, i_reset, i_ce, i_sync;
89
        input   wire    [(2*IWIDTH-1):0] i_data;
90
        output  reg     [(2*OWIDTH-1):0] o_data;
91
        output  reg                             o_sync;
92
 
93
        // I am using the prefixes
94
        //      ib_*    to reference the inputs to the butterfly, and
95
        //      ob_*    to reference the outputs from the butterfly
96
        reg     wait_for_sync;
97
        reg     [(2*IWIDTH-1):0] ib_a, ib_b;
98
        reg     [(2*CWIDTH-1):0] ib_c;
99
        reg     ib_sync;
100
 
101
        reg     b_started;
102
        wire    ob_sync;
103
        wire    [(2*OWIDTH-1):0] ob_a, ob_b;
104
 
105
        // cmem is defined as an array of real and complex values,
106
        // where the top CWIDTH bits are the real value and the bottom
107
        // CWIDTH bits are the imaginary value.
108
        //
109
        // cmem[i] = { (2^(CWIDTH-2)) * cos(2*pi*i/(2^LGWIDTH)),
110
        //              (2^(CWIDTH-2)) * sin(2*pi*i/(2^LGWIDTH)) };
111
        //
112
        reg     [(2*CWIDTH-1):0] cmem [0:((1<<LGSPAN)-1)];
113
`ifdef  FORMAL
114
// Let the formal tool pick the coefficients
115
`else
116
        initial $readmemh(COEFFILE,cmem);
117
 
118
`endif
119
 
120
        reg     [(LGSPAN):0]             iaddr;
121
        reg     [(2*IWIDTH-1):0] imem    [0:((1<<LGSPAN)-1)];
122
 
123
        reg     [LGSPAN:0]               oaddr;
124
        reg     [(2*OWIDTH-1):0] omem    [0:((1<<LGSPAN)-1)];
125
 
126
        initial wait_for_sync = 1'b1;
127
        initial iaddr = 0;
128
        always @(posedge i_clk)
129
        if (i_reset)
130
        begin
131
                wait_for_sync <= 1'b1;
132
                iaddr <= 0;
133
        end else if ((i_ce)&&((!wait_for_sync)||(i_sync)))
134
        begin
135
                //
136
                // First step: Record what we're not ready to use yet
137
                //
138
                iaddr <= iaddr + { {(LGSPAN){1'b0}}, 1'b1 };
139
                wait_for_sync <= 1'b0;
140
        end
141
        always @(posedge i_clk) // Need to make certain here that we don't read
142
        if ((i_ce)&&(!iaddr[LGSPAN])) // and write the same address on
143
                imem[iaddr[(LGSPAN-1):0]] <= i_data; // the same clk
144
 
145
        //
146
        // Now, we have all the inputs, so let's feed the butterfly
147
        //
148
        // ib_sync is the synchronization bit to the butterfly.  It will
149
        // be tracked within the butterfly, and used to create the o_sync
150
        // value when the results from this output are produced
151
        initial ib_sync = 1'b0;
152
        always @(posedge i_clk)
153
        if (i_reset)
154
                ib_sync <= 1'b0;
155
        else if (i_ce)
156
        begin
157
                // Set the sync to true on the very first
158
                // valid input in, and hence on the very
159
                // first valid data out per FFT.
160
                ib_sync <= (iaddr==(1<<(LGSPAN)));
161
        end
162
 
163
        // Read the values from our input memory, and use them to feed first of two
164
        // butterfly inputs
165
        always  @(posedge i_clk)
166
        if (i_ce)
167
        begin
168
                // One input from memory, ...
169
                ib_a <= imem[iaddr[(LGSPAN-1):0]];
170
                // One input clocked in from the top
171
                ib_b <= i_data;
172
                // and the coefficient or twiddle factor
173
                ib_c <= cmem[iaddr[(LGSPAN-1):0]];
174
        end
175
 
176
        // The idle register is designed to keep track of when an input
177
        // to the butterfly is important and going to be used.  It's used
178
        // in a flag following, so that when useful values are placed
179
        // into the butterfly they'll be non-zero (idle=0), otherwise when
180
        // the inputs to the butterfly are irrelevant and will be ignored,
181
        // then (idle=1) those inputs will be set to zero.  This
182
        // functionality is not designed to be used in operation, but only
183
        // within a Verilator simulation context when chasing a bug.
184
        // In this limited environment, the non-zero answers will stand
185
        // in a trace making it easier to highlight a bug.
186
        reg     idle;
187
        generate if (ZERO_ON_IDLE)
188
        begin
189
                initial idle = 1;
190
                always @(posedge i_clk)
191
                if (i_reset)
192
                        idle <= 1'b1;
193
                else if (i_ce)
194
                        idle <= (!iaddr[LGSPAN])&&(!wait_for_sync);
195
 
196
        end else begin
197
 
198
                always @(*) idle = 0;
199
 
200
        end endgenerate
201
 
202
// For the formal proof, we'll assume the outputs of hwbfly and/or
203
// butterfly, rather than actually calculating them.  This will simplify
204
// the proof and (if done properly) will be equivalent.  Be careful of
205
// defining FORMAL if you want the full logic!
206
`ifndef FORMAL
207
        //
208
        generate if (OPT_HWMPY)
209
        begin : HWBFLY
210
                hwbfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),
211
                                .CKPCE(CKPCE), .SHIFT(BFLYSHIFT))
212
                        bfly(i_clk, i_reset, i_ce, (idle)?0:ib_c,
213
                                (idle || (!i_ce)) ? 0:ib_a,
214
                                (idle || (!i_ce)) ? 0:ib_b,
215
                                (ib_sync)&&(i_ce),
216
                                ob_a, ob_b, ob_sync);
217
        end else begin : FWBFLY
218
                butterfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),
219
                                .CKPCE(CKPCE),.SHIFT(BFLYSHIFT))
220
                        bfly(i_clk, i_reset, i_ce,
221
                                        (idle||(!i_ce))?0:ib_c,
222
                                        (idle||(!i_ce))?0:ib_a,
223
                                        (idle||(!i_ce))?0:ib_b,
224
                                        (ib_sync&&i_ce),
225
                                        ob_a, ob_b, ob_sync);
226
        end endgenerate
227
`endif
228
 
229
        //
230
        // Next step: recover the outputs from the butterfly
231
        //
232
        // The first output can go immediately to the output of this routine
233
        // The second output must wait until this time in the idle cycle
234
        // oaddr is the output memory address, keeping track of where we are
235
        // in this output cycle.
236
        initial oaddr     = 0;
237
        initial o_sync    = 0;
238
        initial b_started = 0;
239
        always @(posedge i_clk)
240
        if (i_reset)
241
        begin
242
                oaddr     <= 0;
243
                o_sync    <= 0;
244
                // b_started will be true once we've seen the first ob_sync
245
                b_started <= 0;
246
        end else if (i_ce)
247
        begin
248
                o_sync <= (!oaddr[LGSPAN])?ob_sync : 1'b0;
249
                if (ob_sync||b_started)
250
                        oaddr <= oaddr + 1'b1;
251
                if ((ob_sync)&&(!oaddr[LGSPAN]))
252
                        // If b_started is true, then a butterfly output is available
253
                        b_started <= 1'b1;
254
        end
255
 
256
        reg     [(LGSPAN-1):0]           nxt_oaddr;
257
        reg     [(2*OWIDTH-1):0] pre_ovalue;
258
        always @(posedge i_clk)
259
        if (i_ce)
260
                nxt_oaddr[0] <= oaddr[0];
261
        generate if (LGSPAN>1)
262
        begin
263
 
264
                always @(posedge i_clk)
265
                if (i_ce)
266
                        nxt_oaddr[LGSPAN-1:1] <= oaddr[LGSPAN-1:1] + 1'b1;
267
 
268
        end endgenerate
269
 
270
        // Only write to the memory on the first half of the outputs
271
        // We'll use the memory value on the second half of the outputs
272
        always @(posedge i_clk)
273
        if ((i_ce)&&(!oaddr[LGSPAN]))
274
                omem[oaddr[(LGSPAN-1):0]] <= ob_b;
275
 
276
        always @(posedge i_clk)
277
        if (i_ce)
278
                pre_ovalue <= omem[nxt_oaddr[(LGSPAN-1):0]];
279
 
280
        always @(posedge i_clk)
281
        if (i_ce)
282
                o_data <= (!oaddr[LGSPAN]) ? ob_a : pre_ovalue;
283
 
284
`ifdef  FORMAL
285
        // An arbitrary processing delay from butterfly input to
286
        // butterfly output(s)
287
        (* anyconst *) reg      [LGSPAN:0]       f_mpydelay;
288
        always @(*)
289
                assume(f_mpydelay > 1);
290
 
291
        reg     f_past_valid;
292
        initial f_past_valid = 1'b0;
293
        always @(posedge i_clk)
294
                f_past_valid <= 1'b1;
295
 
296
        always @(posedge i_clk)
297
        if ((!f_past_valid)||($past(i_reset)))
298
        begin
299
                assert(iaddr == 0);
300
                assert(wait_for_sync);
301
                assert(o_sync == 0);
302
                assert(oaddr == 0);
303
                assert(!b_started);
304
                assert(!o_sync);
305
        end
306
 
307
        /////////////////////////////////////////
308
        //
309
        // Formally verify the input half, from the inputs to this module
310
        // to the inputs of the butterfly
311
        //
312
        /////////////////////////////////////////
313
        //
314
        // Let's  verify a specific set of inputs
315
        (* anyconst *)  reg     [LGSPAN:0]       f_addr;
316
        reg     [2*IWIDTH-1:0]                   f_left, f_right;
317
        wire    [LGSPAN:0]                       f_next_addr;
318
 
319
        always @(posedge i_clk)
320
        if ((!$past(i_ce))&&(!$past(i_ce,2))&&(!$past(i_ce,3))&&(!$past(i_ce,4)))
321
        assume(!i_ce);
322
 
323
        always @(*)
324
                assume(f_addr[LGSPAN]==1'b0);
325
 
326
        assign  f_next_addr = f_addr + 1'b1;
327
 
328
        always @(posedge i_clk)
329
        if ((i_ce)&&(iaddr[LGSPAN:0] == f_addr))
330
                f_left <= i_data;
331
 
332
        always @(*)
333
        if (wait_for_sync)
334
                assert(iaddr == 0);
335
 
336
        wire    [LGSPAN:0]       f_last_addr = iaddr - 1'b1;
337
 
338
        always @(posedge i_clk)
339
        if ((!wait_for_sync)&&(f_last_addr >= { 1'b0, f_addr[LGSPAN-1:0]}))
340
                assert(f_left == imem[f_addr[LGSPAN-1:0]]);
341
 
342
        always @(posedge i_clk)
343
        if ((i_ce)&&(iaddr == { 1'b1, f_addr[LGSPAN-1:0]}))
344
                f_right <= i_data;
345
 
346
        always @(posedge i_clk)
347
        if ((i_ce)&&(!wait_for_sync)&&(f_last_addr == { 1'b1, f_addr[LGSPAN-1:0]}))
348
        begin
349
                assert(ib_a == f_left);
350
                assert(ib_b == f_right);
351
                assert(ib_c == cmem[f_addr[LGSPAN-1:0]]);
352
        end
353
 
354
        /////////////////////////////////////////
355
        //
356
        // Formally verify the output half, from the output of the butterfly
357
        // to the outputs of this module
358
        //
359
        /////////////////////////////////////////
360
        reg     [2*OWIDTH-1:0]   f_oleft, f_oright;
361
        reg     [LGSPAN:0]       f_oaddr;
362
        wire    [LGSPAN:0]       f_oaddr_m1 = f_oaddr - 1'b1;
363
 
364
        always @(*)
365
                f_oaddr = iaddr - f_mpydelay + {1'b1,{(LGSPAN-1){1'b0}}};
366
 
367
        assign  f_oaddr_m1 = f_oaddr - 1'b1;
368
 
369
        reg     f_output_active;
370
        initial f_output_active = 1'b0;
371
        always @(posedge i_clk)
372
        if (i_reset)
373
                f_output_active <= 1'b0;
374
        else if ((i_ce)&&(ob_sync))
375
                f_output_active <= 1'b1;
376
 
377
        always @(*)
378
                assert(f_output_active == b_started);
379
 
380
        always @(*)
381
        if (wait_for_sync)
382
                assert(!f_output_active);
383
 
384
        always @(*)
385
        if (f_output_active)
386
                assert(oaddr == f_oaddr);
387
        else
388
                assert(oaddr == 0);
389
 
390
        always @(*)
391
        if (wait_for_sync)
392
                assume(!ob_sync);
393
 
394
        always @(*)
395
                assume(ob_sync == (f_oaddr == 0));
396
 
397
        always @(posedge i_clk)
398
        if ((f_past_valid)&&(!$past(i_ce)))
399
        begin
400
                assume($stable(ob_a));
401
                assume($stable(ob_b));
402
        end
403
 
404
        initial f_oleft  = 0;
405
        initial f_oright = 0;
406
        always @(posedge i_clk)
407
        if ((i_ce)&&(f_oaddr == f_addr))
408
        begin
409
                f_oleft  <= ob_a;
410
                f_oright <= ob_b;
411
        end
412
 
413
        always @(posedge i_clk)
414
        if ((f_output_active)&&(f_oaddr_m1 >= { 1'b0, f_addr[LGSPAN-1:0]}))
415
                assert(omem[f_addr[LGSPAN-1:0]] == f_oright);
416
 
417
        always @(posedge i_clk)
418
        if ((i_ce)&&(f_oaddr_m1 == 0)&&(f_output_active))
419
                assert(o_sync);
420
        else if ((i_ce)||(!f_output_active))
421
                assert(!o_sync);
422
 
423
        always @(posedge i_clk)
424
        if ((i_ce)&&(f_output_active)&&(f_oaddr_m1 == f_addr))
425
                assert(o_data == f_oleft);
426
        always @(posedge i_clk)
427
        if ((i_ce)&&(f_output_active)&&(f_oaddr[LGSPAN])
428
                        &&(f_oaddr[LGSPAN-1:0] == f_addr[LGSPAN-1:0]))
429
                assert(pre_ovalue == f_oright);
430
        always @(posedge i_clk)
431
        if ((i_ce)&&(f_output_active)&&(f_oaddr_m1[LGSPAN])
432
                        &&(f_oaddr_m1[LGSPAN-1:0] == f_addr[LGSPAN-1:0]))
433
                assert(o_data == f_oright);
434
 
435
`endif
436
endmodule

powered by: WebSVN 2.1.0

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