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

Subversion Repositories dblclockfft

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 36 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    qtrstage.v
4
//
5
// Project:     A General Purpose Pipelined FFT Implementation
6
//
7
// Purpose:     This file encapsulates the 4 point stage of a decimation in
8
//              frequency FFT.  This particular implementation is optimized
9
//      so that all of the multiplies are accomplished by additions and
10
//      multiplexers only.
11
//
12 39 dgisselq
// Operation:
13
//      The operation of this stage is identical to the regular stages of
14
//      the FFT (see them for details), with one additional and critical
15
//      difference: this stage doesn't require any hardware multiplication.
16
//      The multiplies within it may all be accomplished using additions and
17
//      subtractions.
18 36 dgisselq
//
19 39 dgisselq
//      Let's see how this is done.  Given x[n] and x[n+2], cause thats the
20
//      stage we are working on, with i_sync true for x[0] being input,
21
//      produce the output:
22
//
23
//      y[n  ] = x[n] + x[n+2]
24
//      y[n+2] = (x[n] - x[n+2]) * e^{-j2pi n/2}        (forward transform)
25
//             = (x[n] - x[n+2]) * -j^n
26
//
27
//      y[n].r = x[n].r + x[n+2].r      (This is the easy part)
28
//      y[n].i = x[n].i + x[n+2].i
29
//
30
//      y[2].r = x[0].r - x[2].r
31
//      y[2].i = x[0].i - x[2].i
32
//
33
//      y[3].r =   (x[1].i - x[3].i)            (forward transform)
34
//      y[3].i = - (x[1].r - x[3].r)
35
//
36
//      y[3].r = - (x[1].i - x[3].i)            (inverse transform)
37
//      y[3].i =   (x[1].r - x[3].r)            (INVERSE = 1)
38
//
39 36 dgisselq
// Creator:     Dan Gisselquist, Ph.D.
40
//              Gisselquist Technology, LLC
41
//
42
////////////////////////////////////////////////////////////////////////////////
43
//
44
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
45
//
46 39 dgisselq
// This file is part of the general purpose pipelined FFT project.
47 36 dgisselq
//
48 39 dgisselq
// The pipelined FFT project is free software (firmware): you can redistribute
49
// it and/or modify it under the terms of the GNU Lesser General Public License
50
// as published by the Free Software Foundation, either version 3 of the
51
// License, or (at your option) any later version.
52 36 dgisselq
//
53 39 dgisselq
// The pipelined FFT project is distributed in the hope that it will be useful,
54
// but WITHOUT ANY WARRANTY; without even the implied warranty of
55
// MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
56
// General Public License for more details.
57
//
58
// You should have received a copy of the GNU Lesser General Public License
59
// along with this program.  (It's in the $(ROOT)/doc directory.  Run make
60
// with no target there if the PDF file isn't present.)  If not, see
61 36 dgisselq
// <http://www.gnu.org/licenses/> for a copy.
62
//
63 39 dgisselq
// License:     LGPL, v3, as defined and found on www.gnu.org,
64
//              http://www.gnu.org/licenses/lgpl.html
65 36 dgisselq
//
66
//
67
////////////////////////////////////////////////////////////////////////////////
68
//
69
//
70
`default_nettype        none
71
//
72
module  qtrstage(i_clk, i_reset, i_ce, i_sync, i_data, o_data, o_sync);
73
        parameter       IWIDTH=16, OWIDTH=IWIDTH+1;
74 39 dgisselq
        parameter       LGWIDTH=8, INVERSE=0,SHIFT=0;
75
        input   wire                            i_clk, i_reset, i_ce, i_sync;
76
        input   wire    [(2*IWIDTH-1):0] i_data;
77 36 dgisselq
        output  reg     [(2*OWIDTH-1):0] o_data;
78
        output  reg                             o_sync;
79
 
80
        reg             wait_for_sync;
81 39 dgisselq
        reg     [2:0]    pipeline;
82 36 dgisselq
 
83 39 dgisselq
        reg     signed [(IWIDTH):0]      sum_r, sum_i, diff_r, diff_i;
84 36 dgisselq
 
85
        reg     [(2*OWIDTH-1):0] ob_a;
86
        wire    [(2*OWIDTH-1):0] ob_b;
87
        reg     [(OWIDTH-1):0]           ob_b_r, ob_b_i;
88
        assign  ob_b = { ob_b_r, ob_b_i };
89
 
90
        reg     [(LGWIDTH-1):0]          iaddr;
91 39 dgisselq
        reg     [(2*IWIDTH-1):0] imem    [0:1];
92 36 dgisselq
 
93
        wire    signed  [(IWIDTH-1):0]   imem_r, imem_i;
94 39 dgisselq
        assign  imem_r = imem[1][(2*IWIDTH-1):(IWIDTH)];
95
        assign  imem_i = imem[1][(IWIDTH-1):0];
96 36 dgisselq
 
97
        wire    signed  [(IWIDTH-1):0]   i_data_r, i_data_i;
98
        assign  i_data_r = i_data[(2*IWIDTH-1):(IWIDTH)];
99
        assign  i_data_i = i_data[(IWIDTH-1):0];
100
 
101 39 dgisselq
        reg     [(2*OWIDTH-1):0] omem [0:1];
102 36 dgisselq
 
103 39 dgisselq
        //
104
        // Round our output values down to OWIDTH bits
105
        //
106
        wire    signed  [(OWIDTH-1):0]   rnd_sum_r, rnd_sum_i,
107
                        rnd_diff_r, rnd_diff_i, n_rnd_diff_r, n_rnd_diff_i;
108 36 dgisselq
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_sum_r(i_clk, i_ce,
109
                                sum_r, rnd_sum_r);
110
 
111
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_sum_i(i_clk, i_ce,
112
                                sum_i, rnd_sum_i);
113
 
114
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_diff_r(i_clk, i_ce,
115
                                diff_r, rnd_diff_r);
116
 
117
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_diff_i(i_clk, i_ce,
118
                                diff_i, rnd_diff_i);
119
 
120
        assign n_rnd_diff_r = - rnd_diff_r;
121
        assign n_rnd_diff_i = - rnd_diff_i;
122
        initial wait_for_sync = 1'b1;
123
        initial iaddr = 0;
124
        always @(posedge i_clk)
125
                if (i_reset)
126
                begin
127
                        wait_for_sync <= 1'b1;
128
                        iaddr <= 0;
129
                end else if ((i_ce)&&((!wait_for_sync)||(i_sync)))
130
                begin
131 39 dgisselq
                        iaddr <= iaddr + 1'b1;
132 36 dgisselq
                        wait_for_sync <= 1'b0;
133
                end
134
 
135
        always @(posedge i_clk)
136
                if (i_ce)
137 39 dgisselq
                begin
138
                        imem[0] <= i_data;
139
                        imem[1] <= imem[0];
140
                end
141 36 dgisselq
 
142
 
143
        // Note that we don't check on wait_for_sync or i_sync here.
144
        // Why not?  Because iaddr will always be zero until after the
145
        // first i_ce, so we are safe.
146 39 dgisselq
        initial pipeline = 3'h0;
147 36 dgisselq
        always  @(posedge i_clk)
148
                if (i_reset)
149 39 dgisselq
                        pipeline <= 3'h0;
150 36 dgisselq
                else if (i_ce) // is our pipeline process full?  Which stages?
151 39 dgisselq
                        pipeline <= { pipeline[1:0], iaddr[1] };
152 36 dgisselq
 
153
        // This is the pipeline[-1] stage, pipeline[0] will be set next.
154
        always  @(posedge i_clk)
155 39 dgisselq
                if ((i_ce)&&(iaddr[1]))
156 36 dgisselq
                begin
157
                        sum_r  <= imem_r + i_data_r;
158
                        sum_i  <= imem_i + i_data_i;
159
                        diff_r <= imem_r - i_data_r;
160
                        diff_i <= imem_i - i_data_i;
161
                end
162
 
163
        // pipeline[1] takes sum_x and diff_x and produces rnd_x
164
 
165
        // Now for pipeline[2].  We can actually do this at all i_ce
166
        // clock times, since nothing will listen unless pipeline[3]
167
        // on the next clock.  Thus, we simplify this logic and do
168
        // it independent of pipeline[2].
169
        always  @(posedge i_clk)
170
                if (i_ce)
171
                begin
172
                        ob_a <= { rnd_sum_r, rnd_sum_i };
173
                        // on Even, W = e^{-j2pi 1/4 0} = 1
174 39 dgisselq
                        if (!iaddr[0])
175 36 dgisselq
                        begin
176
                                ob_b_r <= rnd_diff_r;
177
                                ob_b_i <= rnd_diff_i;
178
                        end else if (INVERSE==0) begin
179
                                // on Odd, W = e^{-j2pi 1/4} = -j
180
                                ob_b_r <=   rnd_diff_i;
181
                                ob_b_i <= n_rnd_diff_r;
182
                        end else begin
183
                                // on Odd, W = e^{j2pi 1/4} = j
184
                                ob_b_r <= n_rnd_diff_i;
185
                                ob_b_i <=   rnd_diff_r;
186
                        end
187
                end
188
 
189
        always  @(posedge i_clk)
190
                if (i_ce)
191
                begin // In sequence, clock = 3
192 39 dgisselq
                        omem[0] <= ob_b;
193
                        omem[1] <= omem[0];
194
                        if (pipeline[2])
195 36 dgisselq
                                o_data <= ob_a;
196 39 dgisselq
                        else
197
                                o_data <= omem[1];
198 36 dgisselq
                end
199
 
200
        initial o_sync = 1'b0;
201
        always  @(posedge i_clk)
202
                if (i_reset)
203
                        o_sync <= 1'b0;
204
                else if (i_ce)
205 39 dgisselq
                        o_sync <= (iaddr[2:0] == 3'b101);
206
 
207
`ifdef  FORMAL
208
        reg     f_past_valid;
209
        initial f_past_valid = 1'b0;
210
        always @(posedge i_clk)
211
                f_past_valid = 1'b1;
212
 
213
`ifdef  QTRSTAGE
214
        always @(posedge i_clk)
215
                assume((i_ce)||($past(i_ce))||($past(i_ce,2)));
216
`endif
217
 
218
        // The below logic only works if the rounding stage does nothing
219
        initial assert(IWIDTH+1 == OWIDTH);
220
 
221
        reg     signed [IWIDTH-1:0]      f_piped_real    [0:7];
222
        reg     signed [IWIDTH-1:0]      f_piped_imag    [0:7];
223
 
224
        always @(posedge i_clk)
225
        if (i_ce)
226
        begin
227
                f_piped_real[0] <= i_data[2*IWIDTH-1:IWIDTH];
228
                f_piped_imag[0] <= i_data[  IWIDTH-1:0];
229
 
230
                f_piped_real[1] <= f_piped_real[0];
231
                f_piped_imag[1] <= f_piped_imag[0];
232
 
233
                f_piped_real[2] <= f_piped_real[1];
234
                f_piped_imag[2] <= f_piped_imag[1];
235
 
236
                f_piped_real[3] <= f_piped_real[2];
237
                f_piped_imag[3] <= f_piped_imag[2];
238
 
239
                f_piped_real[4] <= f_piped_real[3];
240
                f_piped_imag[4] <= f_piped_imag[3];
241
 
242
                f_piped_real[5] <= f_piped_real[4];
243
                f_piped_imag[5] <= f_piped_imag[4];
244
 
245
                f_piped_real[6] <= f_piped_real[5];
246
                f_piped_imag[6] <= f_piped_imag[5];
247
 
248
                f_piped_real[7] <= f_piped_real[6];
249
                f_piped_imag[7] <= f_piped_imag[6];
250
        end
251
 
252
        reg     f_rsyncd;
253
        wire    f_syncd;
254
 
255
        initial f_rsyncd = 0;
256
        always @(posedge i_clk)
257
        if(i_reset)
258
                f_rsyncd <= 1'b0;
259
        else if (!f_rsyncd)
260
                f_rsyncd <= (o_sync);
261
        assign  f_syncd = (f_rsyncd)||(o_sync);
262
 
263
        reg     [1:0]    f_state;
264
 
265
 
266
        initial f_state = 0;
267
        always @(posedge i_clk)
268
        if (i_reset)
269
                f_state <= 0;
270
        else if ((i_ce)&&((!wait_for_sync)||(i_sync)))
271
                f_state <= f_state + 1;
272
 
273
        always @(*)
274
        if (f_state != 0)
275
                assume(!i_sync);
276
 
277
        always @(posedge i_clk)
278
                assert(f_state[1:0] == iaddr[1:0]);
279
 
280
        wire    signed [2*IWIDTH-1:0]    f_i_real, f_i_imag;
281
        assign                  f_i_real = i_data[2*IWIDTH-1:IWIDTH];
282
        assign                  f_i_imag = i_data[  IWIDTH-1:0];
283
 
284
        wire    signed [OWIDTH-1:0]      f_o_real, f_o_imag;
285
        assign                  f_o_real = o_data[2*OWIDTH-1:OWIDTH];
286
        assign                  f_o_imag = o_data[  OWIDTH-1:0];
287
 
288
        always @(posedge i_clk)
289
        if (f_state == 2'b11)
290
        begin
291
                assume(f_piped_real[0] != 3'sb100);
292
                assume(f_piped_real[2] != 3'sb100);
293
                assert(sum_r  == f_piped_real[2] + f_piped_real[0]);
294
                assert(sum_i  == f_piped_imag[2] + f_piped_imag[0]);
295
 
296
                assert(diff_r == f_piped_real[2] - f_piped_real[0]);
297
                assert(diff_i == f_piped_imag[2] - f_piped_imag[0]);
298
        end
299
 
300
        always @(posedge i_clk)
301
        if ((f_state == 2'b00)&&((f_syncd)||(iaddr >= 4)))
302
        begin
303
                assert(rnd_sum_r  == f_piped_real[3]+f_piped_real[1]);
304
                assert(rnd_sum_i  == f_piped_imag[3]+f_piped_imag[1]);
305
                assert(rnd_diff_r == f_piped_real[3]-f_piped_real[1]);
306
                assert(rnd_diff_i == f_piped_imag[3]-f_piped_imag[1]);
307
        end
308
 
309
        always @(posedge i_clk)
310
        if ((f_state == 2'b10)&&(f_syncd))
311
        begin
312
                // assert(o_sync);
313
                assert(f_o_real == f_piped_real[5] + f_piped_real[3]);
314
                assert(f_o_imag == f_piped_imag[5] + f_piped_imag[3]);
315
        end
316
 
317
        always @(posedge i_clk)
318
        if ((f_state == 2'b11)&&(f_syncd))
319
        begin
320
                assert(!o_sync);
321
                assert(f_o_real == f_piped_real[5] + f_piped_real[3]);
322
                assert(f_o_imag == f_piped_imag[5] + f_piped_imag[3]);
323
        end
324
 
325
        always @(posedge i_clk)
326
        if ((f_state == 2'b00)&&(f_syncd))
327
        begin
328
                assert(!o_sync);
329
                assert(f_o_real == f_piped_real[7] - f_piped_real[5]);
330
                assert(f_o_imag == f_piped_imag[7] - f_piped_imag[5]);
331
        end
332
 
333
        always @(*)
334
        if ((iaddr[2:0] == 0)&&(!wait_for_sync))
335
                assume(i_sync);
336
 
337
        always @(*)
338
        if (wait_for_sync)
339
                assert((iaddr == 0)&&(f_state == 2'b00)&&(!o_sync)&&(!f_rsyncd));
340
 
341
        always @(posedge i_clk)
342
        if ((f_past_valid)&&($past(i_ce))&&($past(i_sync))&&(!$past(i_reset)))
343
                assert(!wait_for_sync);
344
 
345
        always @(posedge i_clk)
346
        if ((f_state == 2'b01)&&(f_syncd))
347
        begin
348
                assert(!o_sync);
349
                if (INVERSE)
350
                begin
351
                        assert(f_o_real == -f_piped_imag[7]+f_piped_imag[5]);
352
                        assert(f_o_imag ==  f_piped_real[7]-f_piped_real[5]);
353
                end else begin
354
                        assert(f_o_real ==  f_piped_imag[7]-f_piped_imag[5]);
355
                        assert(f_o_imag == -f_piped_real[7]+f_piped_real[5]);
356
                end
357
        end
358
 
359
`endif
360 36 dgisselq
endmodule

powered by: WebSVN 2.1.0

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