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

Subversion Repositories fft2_size

[/] [fft2_size/] [fft_int_size/] [fft_int_size.sv] - Rev 7

Compare with Previous | Blame | View Log

/*
Streaming FFT module with resizable FFT length
*/

`ifndef _fft_int_size_
`define _fft_int_size_
`include "size_ctrl.sv"
`include "cascade_0.sv"
`include "cascade_n.sv"

// Integer resizable streaming FFT
module fft_int_size #(parameter
        POW = 9, // max fft size 2**POW
        DATA_WIDTH = 32,
        POW_WIDTH = (2**$clog2(POW) > POW - 1) ? $clog2(POW) : $clog2(POW) + 1,
        RES_WIDTH = DATA_WIDTH + POW
)(
        input clk, aclr,
        
        // input data stream
        input sink_sop, sink_eop, sink_valid, // valid signal must be solid between sop and eop
        input signed [DATA_WIDTH-1:0] sink_Re, sink_Im,
        
        // FFT length 2**pow
        input [POW_WIDTH-1:0] pow, // 4..POW
        output pow_ready, // pow ready to change
        
        // Result data stream
        output reg source_sop, source_eop, source_valid,
        output reg signed [RES_WIDTH-1:0] source_Re, source_Im,
        
        output error
);
        wire [POW-1:0][POW-1:0] fft_rdaddr;
        wire [POW-1:0] fft_rdack;
        wire [POW:0] ready;
        
        logic [POW:0][POW-1:0] rdaddr;
        logic [POW:0] rdack;
        
        genvar k;
        generate for (k = 0; k <= POW; k++)
                begin :res
                        wire signed [DATA_WIDTH + k - 1:0] re, im;
                end
        endgenerate
        
        wire [POW_WIDTH-1:0] pow_reg;
        wire [POW-1:0] addr_max;
        wire [1:0] err;
        
        wire sop_reg, eop_reg, valid_reg;
        wire signed [DATA_WIDTH-1:0] re_reg, im_reg;
        
        size_ctrl #(.POW(POW), .DATA_WIDTH(DATA_WIDTH)) size_inst(
                .clk, .aclr, .pow, .source_eop,         
                .pow_reg, .addr_max,    .pow_ready, .error(err[0]),
                
                .sink_sop, .sink_eop, .sink_valid, .sink_Re, .sink_Im,  
                .sop_reg, .eop_reg, .valid_reg, .re_reg, .im_reg
        );
        
        // input controller
        cascade_0 #(.ADDR_WIDTH(POW), .DATA_WIDTH(DATA_WIDTH)) c0(
                .clk, .aclr,
                .sink_sop(sop_reg), .sink_eop(eop_reg), .sink_valid(valid_reg), .sink_Re(re_reg), .sink_Im(im_reg),
                .pow(pow_reg), .addr_max,
                
                .rdaddr(rdaddr[0]),
                .q_Re(res[0].re), .q_Im(res[0].im),
                .ready(ready[0]),
                .rdack(rdack[0]),
                .error(err[1])
        );
        
        always_comb begin
                rdaddr[0] = fft_rdaddr[0];
                rdack[0] = fft_rdack[0];
        end
        
        reg [POW-1:0] cnt = '0;
        genvar i;       
        generate
                for (i = 1; i <= POW; i++)
                        begin :gen
                                cascade_n #(.ADDR_WIDTH(POW), .DATA_WIDTH(DATA_WIDTH + i - 1), .POW(i)) cn(
                                        .clk, .aclr, .sink_ready(ready[i-1] && pow_reg >= i),
                                        .sink_rdaddr(fft_rdaddr[i-1]),
                                        .sink_Re(res[i-1].re), .sink_Im(res[i-1].im),
                                        .sink_rdack(fft_rdack[i-1]),
                                        .pow(pow_reg), .addr_max,
                                        
                                        .source_rdaddr(rdaddr[i]),
                                        .source_rdack(rdack[i]),
                                        .source_Re(res[i].re), .source_Im(res[i].im),
                                        .source_ready(ready[i])
                                );
                                
                                if (i < 4)
                                        begin
                                                always_comb
                                                        begin
                                                                rdaddr[i] = fft_rdaddr[i];
                                                                rdack[i] = fft_rdack[i];
                                                        end
                                        end
                                else if (i == POW)
                                        begin
                                                always_comb begin
                                                        rdaddr[POW] = cnt;
                                                        rdack[POW] = cnt == '1;
                                                end
                                        end
                                else
                                        begin
                                                always_comb
                                                        if (pow_reg > i)
                                                                begin // todo: use 2 ports memory to read data
                                                                        rdaddr[i] = fft_rdaddr[i];
                                                                        rdack[i] = fft_rdack[i];
                                                                end
                                                        else
                                                                begin
                                                                        rdaddr[i] = cnt;
                                                                        rdack[i] = cnt == addr_max;
                                                                end
                                        end
                        end
        endgenerate
        
        // Read data from last cascade
        always_ff @(posedge clk, posedge aclr)
                if (aclr)
                        cnt <= '0;
                else if (!ready[pow_reg] || cnt == addr_max)
                        cnt <= '0;
                else
                        cnt <= cnt + 1'b1;
        
        reg res_sop, res_eop, res_valid = 1'b0;
        
        always_ff @(posedge clk) begin
                res_sop <= ready[pow_reg] && cnt == '0;
                res_eop <= cnt == addr_max;
        end
        
        always_ff @(posedge clk, posedge aclr)
                res_valid <= (aclr) ? 1'b0 : ready[pow_reg] || rdack[pow_reg];
        
        // form result
        // todo: 2 regs
        wire signed [RES_WIDTH - 1:0] res_re[2**POW_WIDTH], res_im[2**POW_WIDTH];
        
        genvar m;
        generate for (m = 0; m < 2**POW_WIDTH; m++)
                begin :gen_res
                        if (m >= 4 && m <= POW)
                                begin
                                        assign res_re[m] = RES_WIDTH'('sh0) + signed'(res[m].re);
                                        assign res_im[m] = RES_WIDTH'('sh0) + signed'(res[m].im);
                                end
                        else
                                begin
                                        assign res_re[m] = 'sh0;
                                        assign res_im[m] = 'sh0;
                                end
                end
        endgenerate
        
        always_ff @(posedge clk) begin
                source_sop <= res_sop;
                source_eop <= res_eop;
                
                source_Re <= res_re[pow_reg];
                source_Im <= res_im[pow_reg];
        end
        
        always_ff @(posedge clk, posedge aclr)
                source_valid <= (aclr) ? 1'b0 : res_valid;
        
        assign error = |err;
        
endmodule :fft_int_size

`endif

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

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