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

Subversion Repositories dblclockfft

[/] [dblclockfft/] [trunk/] [rtl/] [qtrstage.v] - Diff between revs 36 and 39

Show entire file | Details | Blame | View Log

Rev 36 Rev 39
Line 7... Line 7...
// Purpose:     This file encapsulates the 4 point stage of a decimation in
// Purpose:     This file encapsulates the 4 point stage of a decimation in
//              frequency FFT.  This particular implementation is optimized
//              frequency FFT.  This particular implementation is optimized
//      so that all of the multiplies are accomplished by additions and
//      so that all of the multiplies are accomplished by additions and
//      multiplexers only.
//      multiplexers only.
//
//
 
// Operation:
 
//      The operation of this stage is identical to the regular stages of
 
//      the FFT (see them for details), with one additional and critical
 
//      difference: this stage doesn't require any hardware multiplication.
 
//      The multiplies within it may all be accomplished using additions and
 
//      subtractions.
 
//
 
//      Let's see how this is done.  Given x[n] and x[n+2], cause thats the
 
//      stage we are working on, with i_sync true for x[0] being input,
 
//      produce the output:
 
//
 
//      y[n  ] = x[n] + x[n+2]
 
//      y[n+2] = (x[n] - x[n+2]) * e^{-j2pi n/2}        (forward transform)
 
//             = (x[n] - x[n+2]) * -j^n
 
//
 
//      y[n].r = x[n].r + x[n+2].r      (This is the easy part)
 
//      y[n].i = x[n].i + x[n+2].i
 
//
 
//      y[2].r = x[0].r - x[2].r
 
//      y[2].i = x[0].i - x[2].i
 
//
 
//      y[3].r =   (x[1].i - x[3].i)            (forward transform)
 
//      y[3].i = - (x[1].r - x[3].r)
 
//
 
//      y[3].r = - (x[1].i - x[3].i)            (inverse transform)
 
//      y[3].i =   (x[1].r - x[3].r)            (INVERSE = 1)
//
//
// Creator:     Dan Gisselquist, Ph.D.
// Creator:     Dan Gisselquist, Ph.D.
//              Gisselquist Technology, LLC
//              Gisselquist Technology, LLC
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
// Copyright (C) 2015-2018, Gisselquist Technology, LLC
//
//
// This program is free software (firmware): you can redistribute it and/or
// This file is part of the general purpose pipelined FFT project.
// modify it under the terms of  the GNU General Public License as published
//
// by the Free Software Foundation, either version 3 of the License, or (at
// The pipelined FFT project is free software (firmware): you can redistribute
// your option) any later version.
// it and/or modify it under the terms of the GNU Lesser General Public License
//
// as published by the Free Software Foundation, either version 3 of the
// This program is distributed in the hope that it will be useful, but WITHOUT
// License, or (at your option) any later version.
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
//
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// The pipelined FFT project is distributed in the hope that it will be useful,
// for more details.
// but WITHOUT ANY WARRANTY; without even the implied warranty of
//
// MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
// You should have received a copy of the GNU General Public License along
// General Public License for more details.
// with this program.  (It's in the $(ROOT)/doc directory, run make with no
//
// target there if the PDF file isn't present.)  If not, see
// You should have received a copy of the GNU Lesser General Public License
 
// along with this program.  (It's in the $(ROOT)/doc directory.  Run make
 
// with no target there if the PDF file isn't present.)  If not, see
// <http://www.gnu.org/licenses/> for a copy.
// <http://www.gnu.org/licenses/> for a copy.
//
//
// License:     GPL, v3, as defined and found on www.gnu.org,
// License:     LGPL, v3, as defined and found on www.gnu.org,
//              http://www.gnu.org/licenses/gpl.html
//              http://www.gnu.org/licenses/lgpl.html
//
//
//
//
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
//
//
`default_nettype        none
`default_nettype        none
//
//
module  qtrstage(i_clk, i_reset, i_ce, i_sync, i_data, o_data, o_sync);
module  qtrstage(i_clk, i_reset, i_ce, i_sync, i_data, o_data, o_sync);
        parameter       IWIDTH=16, OWIDTH=IWIDTH+1;
        parameter       IWIDTH=16, OWIDTH=IWIDTH+1;
        // Parameters specific to the core that should be changed when this
        parameter       LGWIDTH=8, INVERSE=0,SHIFT=0;
        // core is built ... Note that the minimum LGSPAN is 2.  Smaller
        input   wire                            i_clk, i_reset, i_ce, i_sync;
        // spans must use the fftdoubles stage.
        input   wire    [(2*IWIDTH-1):0] i_data;
        parameter       LGWIDTH=8, ODD=0, INVERSE=0,SHIFT=0;
 
        input                                   i_clk, i_reset, i_ce, i_sync;
 
        input           [(2*IWIDTH-1):0] i_data;
 
        output  reg     [(2*OWIDTH-1):0] o_data;
        output  reg     [(2*OWIDTH-1):0] o_data;
        output  reg                             o_sync;
        output  reg                             o_sync;
 
 
        reg             wait_for_sync;
        reg             wait_for_sync;
        reg     [3:0]    pipeline;
        reg     [2:0]    pipeline;
 
 
        reg     [(IWIDTH):0]     sum_r, sum_i, diff_r, diff_i;
        reg     signed [(IWIDTH):0]      sum_r, sum_i, diff_r, diff_i;
 
 
        reg     [(2*OWIDTH-1):0] ob_a;
        reg     [(2*OWIDTH-1):0] ob_a;
        wire    [(2*OWIDTH-1):0] ob_b;
        wire    [(2*OWIDTH-1):0] ob_b;
        reg     [(OWIDTH-1):0]           ob_b_r, ob_b_i;
        reg     [(OWIDTH-1):0]           ob_b_r, ob_b_i;
        assign  ob_b = { ob_b_r, ob_b_i };
        assign  ob_b = { ob_b_r, ob_b_i };
 
 
        reg     [(LGWIDTH-1):0]          iaddr;
        reg     [(LGWIDTH-1):0]          iaddr;
        reg     [(2*IWIDTH-1):0] imem;
        reg     [(2*IWIDTH-1):0] imem    [0:1];
 
 
        wire    signed  [(IWIDTH-1):0]   imem_r, imem_i;
        wire    signed  [(IWIDTH-1):0]   imem_r, imem_i;
        assign  imem_r = imem[(2*IWIDTH-1):(IWIDTH)];
        assign  imem_r = imem[1][(2*IWIDTH-1):(IWIDTH)];
        assign  imem_i = imem[(IWIDTH-1):0];
        assign  imem_i = imem[1][(IWIDTH-1):0];
 
 
        wire    signed  [(IWIDTH-1):0]   i_data_r, i_data_i;
        wire    signed  [(IWIDTH-1):0]   i_data_r, i_data_i;
        assign  i_data_r = i_data[(2*IWIDTH-1):(IWIDTH)];
        assign  i_data_r = i_data[(2*IWIDTH-1):(IWIDTH)];
        assign  i_data_i = i_data[(IWIDTH-1):0];
        assign  i_data_i = i_data[(IWIDTH-1):0];
 
 
        reg     [(2*OWIDTH-1):0] omem;
        reg     [(2*OWIDTH-1):0] omem [0:1];
 
 
        wire    signed  [(OWIDTH-1):0]   rnd_sum_r, rnd_sum_i, rnd_diff_r, rnd_diff_i,
        //
                                        n_rnd_diff_r, n_rnd_diff_i;
        // Round our output values down to OWIDTH bits
 
        //
 
        wire    signed  [(OWIDTH-1):0]   rnd_sum_r, rnd_sum_i,
 
                        rnd_diff_r, rnd_diff_i, n_rnd_diff_r, n_rnd_diff_i;
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_sum_r(i_clk, i_ce,
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_sum_r(i_clk, i_ce,
                                sum_r, rnd_sum_r);
                                sum_r, rnd_sum_r);
 
 
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_sum_i(i_clk, i_ce,
        convround #(IWIDTH+1,OWIDTH,SHIFT)      do_rnd_sum_i(i_clk, i_ce,
                                sum_i, rnd_sum_i);
                                sum_i, rnd_sum_i);
Line 98... Line 126...
                begin
                begin
                        wait_for_sync <= 1'b1;
                        wait_for_sync <= 1'b1;
                        iaddr <= 0;
                        iaddr <= 0;
                end else if ((i_ce)&&((!wait_for_sync)||(i_sync)))
                end else if ((i_ce)&&((!wait_for_sync)||(i_sync)))
                begin
                begin
                        iaddr <= iaddr + { {(LGWIDTH-1){1'b0}}, 1'b1 };
                        iaddr <= iaddr + 1'b1;
                        wait_for_sync <= 1'b0;
                        wait_for_sync <= 1'b0;
                end
                end
 
 
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (i_ce)
                if (i_ce)
                        imem <= i_data;
                begin
 
                        imem[0] <= i_data;
 
                        imem[1] <= imem[0];
 
                end
 
 
 
 
        // Note that we don't check on wait_for_sync or i_sync here.
        // Note that we don't check on wait_for_sync or i_sync here.
        // Why not?  Because iaddr will always be zero until after the
        // Why not?  Because iaddr will always be zero until after the
        // first i_ce, so we are safe.
        // first i_ce, so we are safe.
        initial pipeline = 4'h0;
        initial pipeline = 3'h0;
        always  @(posedge i_clk)
        always  @(posedge i_clk)
                if (i_reset)
                if (i_reset)
                        pipeline <= 4'h0;
                        pipeline <= 3'h0;
                else if (i_ce) // is our pipeline process full?  Which stages?
                else if (i_ce) // is our pipeline process full?  Which stages?
                        pipeline <= { pipeline[2:0], iaddr[0] };
                        pipeline <= { pipeline[1:0], iaddr[1] };
 
 
        // This is the pipeline[-1] stage, pipeline[0] will be set next.
        // This is the pipeline[-1] stage, pipeline[0] will be set next.
        always  @(posedge i_clk)
        always  @(posedge i_clk)
                if ((i_ce)&&(iaddr[0]))
                if ((i_ce)&&(iaddr[1]))
                begin
                begin
                        sum_r  <= imem_r + i_data_r;
                        sum_r  <= imem_r + i_data_r;
                        sum_i  <= imem_i + i_data_i;
                        sum_i  <= imem_i + i_data_i;
                        diff_r <= imem_r - i_data_r;
                        diff_r <= imem_r - i_data_r;
                        diff_i <= imem_i - i_data_i;
                        diff_i <= imem_i - i_data_i;
Line 138... Line 169...
        always  @(posedge i_clk)
        always  @(posedge i_clk)
                if (i_ce)
                if (i_ce)
                begin
                begin
                        ob_a <= { rnd_sum_r, rnd_sum_i };
                        ob_a <= { rnd_sum_r, rnd_sum_i };
                        // on Even, W = e^{-j2pi 1/4 0} = 1
                        // on Even, W = e^{-j2pi 1/4 0} = 1
                        if (ODD == 0)
                        if (!iaddr[0])
                        begin
                        begin
                                ob_b_r <= rnd_diff_r;
                                ob_b_r <= rnd_diff_r;
                                ob_b_i <= rnd_diff_i;
                                ob_b_i <= rnd_diff_i;
                        end else if (INVERSE==0) begin
                        end else if (INVERSE==0) begin
                                // on Odd, W = e^{-j2pi 1/4} = -j
                                // on Odd, W = e^{-j2pi 1/4} = -j
Line 156... Line 187...
                end
                end
 
 
        always  @(posedge i_clk)
        always  @(posedge i_clk)
                if (i_ce)
                if (i_ce)
                begin // In sequence, clock = 3
                begin // In sequence, clock = 3
                        if (pipeline[3])
                        omem[0] <= ob_b;
                        begin
                        omem[1] <= omem[0];
                                omem <= ob_b;
                        if (pipeline[2])
                                o_data <= ob_a;
                                o_data <= ob_a;
                        end else
                        else
                                o_data <= omem;
                                o_data <= omem[1];
                end
                end
 
 
        // Don't forget in the sync check that we are running
 
        // at two clocks per sample.  Thus we need to
 
        // produce a sync every 2^(LGWIDTH-1) clocks.
 
        initial o_sync = 1'b0;
        initial o_sync = 1'b0;
        always  @(posedge i_clk)
        always  @(posedge i_clk)
                if (i_reset)
                if (i_reset)
                        o_sync <= 1'b0;
                        o_sync <= 1'b0;
                else if (i_ce)
                else if (i_ce)
                        o_sync <= &(~iaddr[(LGWIDTH-2):3]) && (iaddr[2:0] == 3'b101);
                        o_sync <= (iaddr[2:0] == 3'b101);
 
 
 
`ifdef  FORMAL
 
        reg     f_past_valid;
 
        initial f_past_valid = 1'b0;
 
        always @(posedge i_clk)
 
                f_past_valid = 1'b1;
 
 
 
`ifdef  QTRSTAGE
 
        always @(posedge i_clk)
 
                assume((i_ce)||($past(i_ce))||($past(i_ce,2)));
 
`endif
 
 
 
        // The below logic only works if the rounding stage does nothing
 
        initial assert(IWIDTH+1 == OWIDTH);
 
 
 
        reg     signed [IWIDTH-1:0]      f_piped_real    [0:7];
 
        reg     signed [IWIDTH-1:0]      f_piped_imag    [0:7];
 
 
 
        always @(posedge i_clk)
 
        if (i_ce)
 
        begin
 
                f_piped_real[0] <= i_data[2*IWIDTH-1:IWIDTH];
 
                f_piped_imag[0] <= i_data[  IWIDTH-1:0];
 
 
 
                f_piped_real[1] <= f_piped_real[0];
 
                f_piped_imag[1] <= f_piped_imag[0];
 
 
 
                f_piped_real[2] <= f_piped_real[1];
 
                f_piped_imag[2] <= f_piped_imag[1];
 
 
 
                f_piped_real[3] <= f_piped_real[2];
 
                f_piped_imag[3] <= f_piped_imag[2];
 
 
 
                f_piped_real[4] <= f_piped_real[3];
 
                f_piped_imag[4] <= f_piped_imag[3];
 
 
 
                f_piped_real[5] <= f_piped_real[4];
 
                f_piped_imag[5] <= f_piped_imag[4];
 
 
 
                f_piped_real[6] <= f_piped_real[5];
 
                f_piped_imag[6] <= f_piped_imag[5];
 
 
 
                f_piped_real[7] <= f_piped_real[6];
 
                f_piped_imag[7] <= f_piped_imag[6];
 
        end
 
 
 
        reg     f_rsyncd;
 
        wire    f_syncd;
 
 
 
        initial f_rsyncd = 0;
 
        always @(posedge i_clk)
 
        if(i_reset)
 
                f_rsyncd <= 1'b0;
 
        else if (!f_rsyncd)
 
                f_rsyncd <= (o_sync);
 
        assign  f_syncd = (f_rsyncd)||(o_sync);
 
 
 
        reg     [1:0]    f_state;
 
 
 
 
 
        initial f_state = 0;
 
        always @(posedge i_clk)
 
        if (i_reset)
 
                f_state <= 0;
 
        else if ((i_ce)&&((!wait_for_sync)||(i_sync)))
 
                f_state <= f_state + 1;
 
 
 
        always @(*)
 
        if (f_state != 0)
 
                assume(!i_sync);
 
 
 
        always @(posedge i_clk)
 
                assert(f_state[1:0] == iaddr[1:0]);
 
 
 
        wire    signed [2*IWIDTH-1:0]    f_i_real, f_i_imag;
 
        assign                  f_i_real = i_data[2*IWIDTH-1:IWIDTH];
 
        assign                  f_i_imag = i_data[  IWIDTH-1:0];
 
 
 
        wire    signed [OWIDTH-1:0]      f_o_real, f_o_imag;
 
        assign                  f_o_real = o_data[2*OWIDTH-1:OWIDTH];
 
        assign                  f_o_imag = o_data[  OWIDTH-1:0];
 
 
 
        always @(posedge i_clk)
 
        if (f_state == 2'b11)
 
        begin
 
                assume(f_piped_real[0] != 3'sb100);
 
                assume(f_piped_real[2] != 3'sb100);
 
                assert(sum_r  == f_piped_real[2] + f_piped_real[0]);
 
                assert(sum_i  == f_piped_imag[2] + f_piped_imag[0]);
 
 
 
                assert(diff_r == f_piped_real[2] - f_piped_real[0]);
 
                assert(diff_i == f_piped_imag[2] - f_piped_imag[0]);
 
        end
 
 
 
        always @(posedge i_clk)
 
        if ((f_state == 2'b00)&&((f_syncd)||(iaddr >= 4)))
 
        begin
 
                assert(rnd_sum_r  == f_piped_real[3]+f_piped_real[1]);
 
                assert(rnd_sum_i  == f_piped_imag[3]+f_piped_imag[1]);
 
                assert(rnd_diff_r == f_piped_real[3]-f_piped_real[1]);
 
                assert(rnd_diff_i == f_piped_imag[3]-f_piped_imag[1]);
 
        end
 
 
 
        always @(posedge i_clk)
 
        if ((f_state == 2'b10)&&(f_syncd))
 
        begin
 
                // assert(o_sync);
 
                assert(f_o_real == f_piped_real[5] + f_piped_real[3]);
 
                assert(f_o_imag == f_piped_imag[5] + f_piped_imag[3]);
 
        end
 
 
 
        always @(posedge i_clk)
 
        if ((f_state == 2'b11)&&(f_syncd))
 
        begin
 
                assert(!o_sync);
 
                assert(f_o_real == f_piped_real[5] + f_piped_real[3]);
 
                assert(f_o_imag == f_piped_imag[5] + f_piped_imag[3]);
 
        end
 
 
 
        always @(posedge i_clk)
 
        if ((f_state == 2'b00)&&(f_syncd))
 
        begin
 
                assert(!o_sync);
 
                assert(f_o_real == f_piped_real[7] - f_piped_real[5]);
 
                assert(f_o_imag == f_piped_imag[7] - f_piped_imag[5]);
 
        end
 
 
 
        always @(*)
 
        if ((iaddr[2:0] == 0)&&(!wait_for_sync))
 
                assume(i_sync);
 
 
 
        always @(*)
 
        if (wait_for_sync)
 
                assert((iaddr == 0)&&(f_state == 2'b00)&&(!o_sync)&&(!f_rsyncd));
 
 
 
        always @(posedge i_clk)
 
        if ((f_past_valid)&&($past(i_ce))&&($past(i_sync))&&(!$past(i_reset)))
 
                assert(!wait_for_sync);
 
 
 
        always @(posedge i_clk)
 
        if ((f_state == 2'b01)&&(f_syncd))
 
        begin
 
                assert(!o_sync);
 
                if (INVERSE)
 
                begin
 
                        assert(f_o_real == -f_piped_imag[7]+f_piped_imag[5]);
 
                        assert(f_o_imag ==  f_piped_real[7]-f_piped_real[5]);
 
                end else begin
 
                        assert(f_o_real ==  f_piped_imag[7]-f_piped_imag[5]);
 
                        assert(f_o_imag == -f_piped_real[7]+f_piped_real[5]);
 
                end
 
        end
 
 
 
`endif
endmodule
endmodule
 
 
 No newline at end of file
 No newline at end of file

powered by: WebSVN 2.1.0

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