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

Subversion Repositories dblclockfft

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

Only display areas with differences | Details | Blame | View Log

Rev 36 Rev 39
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//
//
// Filename:    fftstage.v
// Filename:    fftstage.v
//
//
// Project:     A General Purpose Pipelined FFT Implementation
// Project:     A General Purpose Pipelined FFT Implementation
//
//
// Purpose:     This file is (almost) a Verilog source file.  It is meant to
// Purpose:     This file is (almost) a Verilog source file.  It is meant to
//              be used by a FFT core compiler to generate FFTs which may be
//              be used by a FFT core compiler to generate FFTs which may be
//      used as part of an FFT core.  Specifically, this file encapsulates
//      used as part of an FFT core.  Specifically, this file encapsulates
//      the options of an FFT-stage.  For any 2^N length FFT, there shall be
//      the options of an FFT-stage.  For any 2^N length FFT, there shall be
//      (N-1) of these stages.
//      (N-1) of these stages.
//
//
//
//
// Operation:
// Operation:
//      Given a stream of values, operate upon them as though they were
//      Given a stream of values, operate upon them as though they were
//      value pairs, x[n] and x[n+N/2].  The stream begins when n=0, and ends
//      value pairs, x[n] and x[n+N/2].  The stream begins when n=0, and ends
//      when n=N/2-1 (i.e. there's a full set of N values).  When the value
//      when n=N/2-1 (i.e. there's a full set of N values).  When the value
//      x[0] enters, the synchronization input, i_sync, must be true as well.
//      x[0] enters, the synchronization input, i_sync, must be true as well.
//
//
//      For this stream, produce outputs
//      For this stream, produce outputs
//      y[n    ] = x[n] + x[n+N/2], and
//      y[n    ] = x[n] + x[n+N/2], and
//      y[n+N/2] = (x[n] - x[n+N/2]) * c[n],
//      y[n+N/2] = (x[n] - x[n+N/2]) * c[n],
//                      where c[n] is a complex coefficient found in the
//                      where c[n] is a complex coefficient found in the
//                      external memory file COEFFILE.
//                      external memory file COEFFILE.
//      When y[0] is output, a synchronization bit o_sync will be true as
//      When y[0] is output, a synchronization bit o_sync will be true as
//      well, otherwise it will be zero.
//      well, otherwise it will be zero.
//
//
//      Most of the work to do this is done within the butterfly, whether the
//      Most of the work to do this is done within the butterfly, whether the
//      hardware accelerated butterfly (uses a DSP) or not.
//      hardware accelerated butterfly (uses a DSP) or not.
//
//
// 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  fftstage(i_clk, i_reset, i_ce, i_sync, i_data, o_data, o_sync);
module  fftstage(i_clk, i_reset, i_ce, i_sync, i_data, o_data, o_sync);
        parameter       IWIDTH=15,CWIDTH=20,OWIDTH=16;
        parameter       IWIDTH=15,CWIDTH=20,OWIDTH=16;
        // Parameters specific to the core that should be changed when this
        // Parameters specific to the core that should be changed when this
        // core is built ... Note that the minimum LGSPAN (the base two log
        // core is built ... Note that the minimum LGSPAN (the base two log
        // of the span, or the base two log of the current FFT size) is 3.
        // of the span, or the base two log of the current FFT size) is 3.
        // Smaller spans (i.e. the span of 2) must use the dbl laststage module.
        // Smaller spans (i.e. the span of 2) must use the dbl laststage module.
        parameter       LGWIDTH=10, LGSPAN=8, BFLYSHIFT=0;
        parameter       LGSPAN=10, BFLYSHIFT=0; // LGWIDTH=11
        parameter       [0:0]     OPT_HWMPY = 1;
        parameter       [0:0]     OPT_HWMPY = 1;
        // Clocks per CE.  If your incoming data rate is less than 50% of your
        // Clocks per CE.  If your incoming data rate is less than 50% of your
        // clock speed, you can set CKPCE to 2'b10, make sure there's at least
        // clock speed, you can set CKPCE to 2'b10, make sure there's at least
        // one clock between cycles when i_ce is high, and then use two
        // one clock between cycles when i_ce is high, and then use two
        // multiplies instead of three.  Setting CKPCE to 2'b11, and insisting
        // multiplies instead of three.  Setting CKPCE to 2'b11, and insisting
        // on at least two clocks with i_ce low between cycles with i_ce high,
        // on at least two clocks with i_ce low between cycles with i_ce high,
        // then the hardware optimized butterfly code will used one multiply
        // then the hardware optimized butterfly code will used one multiply
        // instead of two.
        // instead of two.
        parameter               CKPCE = 1;
        parameter               CKPCE = 1;
        // The COEFFILE parameter contains the name of the file containing the
        // The COEFFILE parameter contains the name of the file containing the
        // FFT twiddle factors
        // FFT twiddle factors
        parameter       COEFFILE="cmem_o2048.hex";
        parameter       COEFFILE="cmem_2048.hex";
 
 
`ifdef  VERILATOR
`ifdef  VERILATOR
        parameter [0:0] ZERO_ON_IDLE = 1'b0;
        parameter [0:0] ZERO_ON_IDLE = 1'b0;
`else
`else
        localparam [0:0] ZERO_ON_IDLE = 1'b0;
        localparam [0:0] ZERO_ON_IDLE = 1'b0;
`endif // VERILATOR
`endif // VERILATOR
 
 
        input                                   i_clk, i_reset, i_ce, i_sync;
        input   wire                            i_clk, i_reset, i_ce, i_sync;
        input           [(2*IWIDTH-1):0] i_data;
        input   wire    [(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;
 
 
 
        // I am using the prefixes
 
        //      ib_*    to reference the inputs to the butterfly, and
 
        //      ob_*    to reference the outputs from the butterfly
        reg     wait_for_sync;
        reg     wait_for_sync;
        reg     [(2*IWIDTH-1):0] ib_a, ib_b;
        reg     [(2*IWIDTH-1):0] ib_a, ib_b;
        reg     [(2*CWIDTH-1):0] ib_c;
        reg     [(2*CWIDTH-1):0] ib_c;
        reg     ib_sync;
        reg     ib_sync;
 
 
        reg     b_started;
        reg     b_started;
        wire    ob_sync;
        wire    ob_sync;
        wire    [(2*OWIDTH-1):0] ob_a, ob_b;
        wire    [(2*OWIDTH-1):0] ob_a, ob_b;
 
 
        // cmem is defined as an array of real and complex values,
        // cmem is defined as an array of real and complex values,
        // where the top CWIDTH bits are the real value and the bottom
        // where the top CWIDTH bits are the real value and the bottom
        // CWIDTH bits are the imaginary value.
        // CWIDTH bits are the imaginary value.
        //
        //
        // cmem[i] = { (2^(CWIDTH-2)) * cos(2*pi*i/(2^LGWIDTH)),
        // cmem[i] = { (2^(CWIDTH-2)) * cos(2*pi*i/(2^LGWIDTH)),
        //              (2^(CWIDTH-2)) * sin(2*pi*i/(2^LGWIDTH)) };
        //              (2^(CWIDTH-2)) * sin(2*pi*i/(2^LGWIDTH)) };
        //
        //
        reg     [(2*CWIDTH-1):0] cmem [0:((1<<LGSPAN)-1)];
        reg     [(2*CWIDTH-1):0] cmem [0:((1<<LGSPAN)-1)];
 
`ifdef  FORMAL
 
// Let the formal tool pick the coefficients
 
`else
        initial $readmemh(COEFFILE,cmem);
        initial $readmemh(COEFFILE,cmem);
 
 
 
`endif
 
 
        reg     [(LGSPAN):0]             iaddr;
        reg     [(LGSPAN):0]             iaddr;
        reg     [(2*IWIDTH-1):0] imem    [0:((1<<LGSPAN)-1)];
        reg     [(2*IWIDTH-1):0] imem    [0:((1<<LGSPAN)-1)];
 
 
        reg     [LGSPAN:0]               oB;
        reg     [LGSPAN:0]               oaddr;
        reg     [(2*OWIDTH-1):0] omem    [0:((1<<LGSPAN)-1)];
        reg     [(2*OWIDTH-1):0] omem    [0:((1<<LGSPAN)-1)];
 
 
        initial wait_for_sync = 1'b1;
        initial wait_for_sync = 1'b1;
        initial iaddr = 0;
        initial iaddr = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (i_reset)
        if (i_reset)
        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
                //
                //
                // First step: Record what we're not ready to use yet
                // First step: Record what we're not ready to use yet
                //
                //
                iaddr <= iaddr + { {(LGSPAN){1'b0}}, 1'b1 };
                iaddr <= iaddr + { {(LGSPAN){1'b0}}, 1'b1 };
                wait_for_sync <= 1'b0;
                wait_for_sync <= 1'b0;
        end
        end
        always @(posedge i_clk) // Need to make certain here that we don't read
        always @(posedge i_clk) // Need to make certain here that we don't read
        if ((i_ce)&&(!iaddr[LGSPAN])) // and write the same address on
        if ((i_ce)&&(!iaddr[LGSPAN])) // and write the same address on
                imem[iaddr[(LGSPAN-1):0]] <= i_data; // the same clk
                imem[iaddr[(LGSPAN-1):0]] <= i_data; // the same clk
 
 
        //
        //
        // Now, we have all the inputs, so let's feed the butterfly
        // Now, we have all the inputs, so let's feed the butterfly
        //
        //
 
        // ib_sync is the synchronization bit to the butterfly.  It will
 
        // be tracked within the butterfly, and used to create the o_sync
 
        // value when the results from this output are produced
        initial ib_sync = 1'b0;
        initial ib_sync = 1'b0;
        always @(posedge i_clk)
        always @(posedge i_clk)
        if (i_reset)
        if (i_reset)
                ib_sync <= 1'b0;
                ib_sync <= 1'b0;
        else if (i_ce)
        else if (i_ce)
        begin
        begin
                // Set the sync to true on the very first
                // Set the sync to true on the very first
                // valid input in, and hence on the very
                // valid input in, and hence on the very
                // first valid data out per FFT.
                // first valid data out per FFT.
                ib_sync <= (iaddr==(1<<(LGSPAN)));
                ib_sync <= (iaddr==(1<<(LGSPAN)));
        end
        end
 
 
 
        // Read the values from our input memory, and use them to feed first of two
 
        // butterfly inputs
        always  @(posedge i_clk)
        always  @(posedge i_clk)
        if (i_ce)
        if (i_ce)
        begin
        begin
                // One input from memory, ...
                // One input from memory, ...
                ib_a <= imem[iaddr[(LGSPAN-1):0]];
                ib_a <= imem[iaddr[(LGSPAN-1):0]];
                // One input clocked in from the top
                // One input clocked in from the top
                ib_b <= i_data;
                ib_b <= i_data;
                // and the coefficient or twiddle factor
                // and the coefficient or twiddle factor
                ib_c <= cmem[iaddr[(LGSPAN-1):0]];
                ib_c <= cmem[iaddr[(LGSPAN-1):0]];
        end
        end
 
 
        // The idle register is designed to keep track of when an input
        // The idle register is designed to keep track of when an input
        // to the butterfly is important and going to be used.  It's used
        // to the butterfly is important and going to be used.  It's used
        // in a flag following, so that when useful values are placed
        // in a flag following, so that when useful values are placed
        // into the butterfly they'll be non-zero (idle=0), otherwise when
        // into the butterfly they'll be non-zero (idle=0), otherwise when
        // the inputs to the butterfly are irrelevant and will be ignored,
        // the inputs to the butterfly are irrelevant and will be ignored,
        // then (idle=1) those inputs will be set to zero.  This
        // then (idle=1) those inputs will be set to zero.  This
        // functionality is not designed to be used in operation, but only
        // functionality is not designed to be used in operation, but only
        // within a Verilator simulation context when chasing a bug.
        // within a Verilator simulation context when chasing a bug.
        // In this limited environment, the non-zero answers will stand
        // In this limited environment, the non-zero answers will stand
        // in a trace making it easier to highlight a bug.
        // in a trace making it easier to highlight a bug.
        reg     idle;
        reg     idle;
        generate if (ZERO_ON_IDLE)
        generate if (ZERO_ON_IDLE)
        begin
        begin
                initial idle = 1;
                initial idle = 1;
                always @(posedge i_clk)
                always @(posedge i_clk)
                if (i_reset)
                if (i_reset)
                        idle <= 1'b1;
                        idle <= 1'b1;
                else if (i_ce)
                else if (i_ce)
                        idle <= (!iaddr[LGSPAN])&&(!wait_for_sync);
                        idle <= (!iaddr[LGSPAN])&&(!wait_for_sync);
 
 
        end else begin
        end else begin
 
 
                always @(*) idle = 0;
                always @(*) idle = 0;
 
 
        end endgenerate
        end endgenerate
 
 
 
// For the formal proof, we'll assume the outputs of hwbfly and/or
 
// butterfly, rather than actually calculating them.  This will simplify
 
// the proof and (if done properly) will be equivalent.  Be careful of
 
// defining FORMAL if you want the full logic!
 
`ifndef FORMAL
 
        //
        generate if (OPT_HWMPY)
        generate if (OPT_HWMPY)
        begin : HWBFLY
        begin : HWBFLY
                hwbfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),
                hwbfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),
                                .CKPCE(CKPCE), .SHIFT(BFLYSHIFT))
                                .CKPCE(CKPCE), .SHIFT(BFLYSHIFT))
                        bfly(i_clk, i_reset, i_ce, (idle)?0:ib_c,
                        bfly(i_clk, i_reset, i_ce, (idle)?0:ib_c,
                                (idle || (!i_ce)) ? 0:ib_a,
                                (idle || (!i_ce)) ? 0:ib_a,
                                (idle || (!i_ce)) ? 0:ib_b,
                                (idle || (!i_ce)) ? 0:ib_b,
                                (ib_sync)&&(i_ce),
                                (ib_sync)&&(i_ce),
                                ob_a, ob_b, ob_sync);
                                ob_a, ob_b, ob_sync);
        end else begin : FWBFLY
        end else begin : FWBFLY
                butterfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),
                butterfly #(.IWIDTH(IWIDTH),.CWIDTH(CWIDTH),.OWIDTH(OWIDTH),
                                .CKPCE(CKPCE),.SHIFT(BFLYSHIFT))
                                .CKPCE(CKPCE),.SHIFT(BFLYSHIFT))
                        bfly(i_clk, i_reset, i_ce,
                        bfly(i_clk, i_reset, i_ce,
                                        (idle||(!i_ce))?0:ib_c,
                                        (idle||(!i_ce))?0:ib_c,
                                        (idle||(!i_ce))?0:ib_a,
                                        (idle||(!i_ce))?0:ib_a,
                                        (idle||(!i_ce))?0:ib_b,
                                        (idle||(!i_ce))?0:ib_b,
                                        (ib_sync&&i_ce),
                                        (ib_sync&&i_ce),
                                        ob_a, ob_b, ob_sync);
                                        ob_a, ob_b, ob_sync);
        end endgenerate
        end endgenerate
 
`endif
 
 
        //
        //
        // Next step: recover the outputs from the butterfly
        // Next step: recover the outputs from the butterfly
        //
        //
        initial oB        = 0;
        // The first output can go immediately to the output of this routine
 
        // The second output must wait until this time in the idle cycle
 
        // oaddr is the output memory address, keeping track of where we are
 
        // in this output cycle.
 
        initial oaddr     = 0;
        initial o_sync    = 0;
        initial o_sync    = 0;
        initial b_started = 0;
        initial b_started = 0;
        always @(posedge i_clk)
        always @(posedge i_clk)
                if (i_reset)
        if (i_reset)
        begin
        begin
                oB <= 0;
                oaddr     <= 0;
                o_sync <= 0;
                o_sync <= 0;
 
                // b_started will be true once we've seen the first ob_sync
                b_started <= 0;
                b_started <= 0;
        end else if (i_ce)
        end else if (i_ce)
        begin
        begin
                o_sync <= (!oB[LGSPAN])?ob_sync : 1'b0;
                o_sync <= (!oaddr[LGSPAN])?ob_sync : 1'b0;
                if (ob_sync||b_started)
                if (ob_sync||b_started)
                        oB <= oB + { {(LGSPAN){1'b0}}, 1'b1 };
                        oaddr <= oaddr + 1'b1;
                if ((ob_sync)&&(!oB[LGSPAN]))
                if ((ob_sync)&&(!oaddr[LGSPAN]))
                // A butterfly output is available
                        // If b_started is true, then a butterfly output is available
                        b_started <= 1'b1;
                        b_started <= 1'b1;
        end
        end
 
 
        reg     [(LGSPAN-1):0]           dly_addr;
        reg     [(LGSPAN-1):0]           nxt_oaddr;
        reg     [(2*OWIDTH-1):0] dly_value;
        reg     [(2*OWIDTH-1):0] pre_ovalue;
        always @(posedge i_clk)
        always @(posedge i_clk)
        if (i_ce)
        if (i_ce)
 
                nxt_oaddr[0] <= oaddr[0];
 
        generate if (LGSPAN>1)
        begin
        begin
                dly_addr <= oB[(LGSPAN-1):0];
 
                dly_value <= ob_b;
 
        end
 
        always @(posedge i_clk)
        always @(posedge i_clk)
        if (i_ce)
        if (i_ce)
                omem[dly_addr] <= dly_value;
                        nxt_oaddr[LGSPAN-1:1] <= oaddr[LGSPAN-1:1] + 1'b1;
 
 
 
        end endgenerate
 
 
 
        // Only write to the memory on the first half of the outputs
 
        // We'll use the memory value on the second half of the outputs
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(!oaddr[LGSPAN]))
 
                omem[oaddr[(LGSPAN-1):0]] <= ob_b;
 
 
 
        always @(posedge i_clk)
 
        if (i_ce)
 
                pre_ovalue <= omem[nxt_oaddr[(LGSPAN-1):0]];
 
 
        always @(posedge i_clk)
        always @(posedge i_clk)
        if (i_ce)
        if (i_ce)
                o_data <= (!oB[LGSPAN])?ob_a : omem[oB[(LGSPAN-1):0]];
                o_data <= (!oaddr[LGSPAN]) ? ob_a : pre_ovalue;
 
 
 
`ifdef  FORMAL
 
        // An arbitrary processing delay from butterfly input to
 
        // butterfly output(s)
 
        (* anyconst *) reg      [LGSPAN:0]       f_mpydelay;
 
        always @(*)
 
                assume(f_mpydelay > 1);
 
 
 
        reg     f_past_valid;
 
        initial f_past_valid = 1'b0;
 
        always @(posedge i_clk)
 
                f_past_valid <= 1'b1;
 
 
 
        always @(posedge i_clk)
 
        if ((!f_past_valid)||($past(i_reset)))
 
        begin
 
                assert(iaddr == 0);
 
                assert(wait_for_sync);
 
                assert(o_sync == 0);
 
                assert(oaddr == 0);
 
                assert(!b_started);
 
                assert(!o_sync);
 
        end
 
 
 
        /////////////////////////////////////////
 
        //
 
        // Formally verify the input half, from the inputs to this module
 
        // to the inputs of the butterfly
 
        //
 
        /////////////////////////////////////////
 
        //
 
        // Let's  verify a specific set of inputs
 
        (* anyconst *)  reg     [LGSPAN:0]       f_addr;
 
        reg     [2*IWIDTH-1:0]                   f_left, f_right;
 
        wire    [LGSPAN:0]                       f_next_addr;
 
 
 
        always @(posedge i_clk)
 
        if ((!$past(i_ce))&&(!$past(i_ce,2))&&(!$past(i_ce,3))&&(!$past(i_ce,4)))
 
        assume(!i_ce);
 
 
 
        always @(*)
 
                assume(f_addr[LGSPAN]==1'b0);
 
 
 
        assign  f_next_addr = f_addr + 1'b1;
 
 
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(iaddr[LGSPAN:0] == f_addr))
 
                f_left <= i_data;
 
 
 
        always @(*)
 
        if (wait_for_sync)
 
                assert(iaddr == 0);
 
 
 
        wire    [LGSPAN:0]       f_last_addr = iaddr - 1'b1;
 
 
 
        always @(posedge i_clk)
 
        if ((!wait_for_sync)&&(f_last_addr >= { 1'b0, f_addr[LGSPAN-1:0]}))
 
                assert(f_left == imem[f_addr[LGSPAN-1:0]]);
 
 
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(iaddr == { 1'b1, f_addr[LGSPAN-1:0]}))
 
                f_right <= i_data;
 
 
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(!wait_for_sync)&&(f_last_addr == { 1'b1, f_addr[LGSPAN-1:0]}))
 
        begin
 
                assert(ib_a == f_left);
 
                assert(ib_b == f_right);
 
                assert(ib_c == cmem[f_addr[LGSPAN-1:0]]);
 
        end
 
 
 
        /////////////////////////////////////////
 
        //
 
        // Formally verify the output half, from the output of the butterfly
 
        // to the outputs of this module
 
        //
 
        /////////////////////////////////////////
 
        reg     [2*OWIDTH-1:0]   f_oleft, f_oright;
 
        reg     [LGSPAN:0]       f_oaddr;
 
        wire    [LGSPAN:0]       f_oaddr_m1 = f_oaddr - 1'b1;
 
 
 
        always @(*)
 
                f_oaddr = iaddr - f_mpydelay + {1'b1,{(LGSPAN-1){1'b0}}};
 
 
 
        assign  f_oaddr_m1 = f_oaddr - 1'b1;
 
 
 
        reg     f_output_active;
 
        initial f_output_active = 1'b0;
 
        always @(posedge i_clk)
 
        if (i_reset)
 
                f_output_active <= 1'b0;
 
        else if ((i_ce)&&(ob_sync))
 
                f_output_active <= 1'b1;
 
 
 
        always @(*)
 
                assert(f_output_active == b_started);
 
 
 
        always @(*)
 
        if (wait_for_sync)
 
                assert(!f_output_active);
 
 
 
        always @(*)
 
        if (f_output_active)
 
                assert(oaddr == f_oaddr);
 
        else
 
                assert(oaddr == 0);
 
 
 
        always @(*)
 
        if (wait_for_sync)
 
                assume(!ob_sync);
 
 
 
        always @(*)
 
                assume(ob_sync == (f_oaddr == 0));
 
 
 
        always @(posedge i_clk)
 
        if ((f_past_valid)&&(!$past(i_ce)))
 
        begin
 
                assume($stable(ob_a));
 
                assume($stable(ob_b));
 
        end
 
 
 
        initial f_oleft  = 0;
 
        initial f_oright = 0;
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(f_oaddr == f_addr))
 
        begin
 
                f_oleft  <= ob_a;
 
                f_oright <= ob_b;
 
        end
 
 
 
        always @(posedge i_clk)
 
        if ((f_output_active)&&(f_oaddr_m1 >= { 1'b0, f_addr[LGSPAN-1:0]}))
 
                assert(omem[f_addr[LGSPAN-1:0]] == f_oright);
 
 
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(f_oaddr_m1 == 0)&&(f_output_active))
 
                assert(o_sync);
 
        else if ((i_ce)||(!f_output_active))
 
                assert(!o_sync);
 
 
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(f_output_active)&&(f_oaddr_m1 == f_addr))
 
                assert(o_data == f_oleft);
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(f_output_active)&&(f_oaddr[LGSPAN])
 
                        &&(f_oaddr[LGSPAN-1:0] == f_addr[LGSPAN-1:0]))
 
                assert(pre_ovalue == f_oright);
 
        always @(posedge i_clk)
 
        if ((i_ce)&&(f_output_active)&&(f_oaddr_m1[LGSPAN])
 
                        &&(f_oaddr_m1[LGSPAN-1:0] == f_addr[LGSPAN-1:0]))
 
                assert(o_data == f_oright);
 
 
 
`endif
endmodule
endmodule
 
 

powered by: WebSVN 2.1.0

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