diff --git a/libraries/dsp/fft/src/vhdl/fft_pkg.vhd b/libraries/dsp/fft/src/vhdl/fft_pkg.vhd index a177c9b2360167cb6ca9a00f118b3f452a61de4c..4f9f25c459d3701cb593baa455b649287b7609a9 100644 --- a/libraries/dsp/fft/src/vhdl/fft_pkg.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_pkg.vhd @@ -69,7 +69,12 @@ package fft_pkg is -- Check consistancy of the FFT parameters function fft_r2_parameter_asserts(g_fft : t_fft) return boolean; -- the return value is void, because always true or abort due to failure - + + -- FFT input and output widths + function func_fft_in_scale_w(g_fft : t_fft) return natural; + function func_fft_raw_dat_w(g_fft : t_fft) return natural; + function func_fft_raw_fraction_w(g_fft : t_fft) return natural; + -- Definitions for fft slv array (an array can not have unconstraint elements, so choose sufficiently wide 32 bit slv elements) subtype t_fft_slv_arr is t_slv_32_arr; -- use subtype to ease interfacing to existing types and to have central definition for rtwo components constant c_fft_slv_w : natural := 32; -- match slv width of t_fft_slv_arr @@ -106,7 +111,31 @@ package body fft_pkg is assert g_fft.use_fft_shift=false report "fft_r2 : with use_separate there cannot be use_fft_shift for two real inputs" severity failure; end if; return true; - end; + end; + + -- Scale input data to MSbits of stage data, with g_fft.guard_w bits backoff if g_fft.guard_enable = true + function func_fft_in_scale_w(g_fft : t_fft) return natural is + constant c_in_scale_w : natural := g_fft.stage_dat_w - g_fft.in_dat_w - sel_a_b(g_fft.guard_enable, g_fft.guard_w, 0); + begin + return c_in_scale_w; + end func_fft_in_scale_w; + + -- Raw output data width is equal to the internal data width of the FFT + function func_fft_raw_dat_w(g_fft : t_fft) return natural is + constant c_sepa_growth_w : natural := sel_a_b(g_fft.use_separate, 1, 0); -- add one bit for add sub growth in separate + constant c_raw_dat_w : natural := g_fft.stage_dat_w + c_sepa_growth_w; + begin + return c_raw_dat_w; + end func_fft_raw_dat_w; + + -- Number of LSbits in the raw output data that represent the fraction bits in c_raw_dat_w. + function func_fft_raw_fraction_w(g_fft : t_fft) return natural is + constant c_raw_dat_w : natural := func_fft_raw_dat_w(g_fft); + constant c_raw_fraction_w : natural := c_raw_dat_w - g_fft.out_dat_w - g_fft.out_gain_w; + begin + return c_raw_fraction_w; + end func_fft_raw_fraction_w; + function to_fft_svec(n : integer) return std_logic_vector is begin diff --git a/libraries/dsp/fft/src/vhdl/fft_r2_par.vhd b/libraries/dsp/fft/src/vhdl/fft_r2_par.vhd index 02bf10f3cdc378575e093c4651fad58d5891f3ff..aca22cb6ad028a06e9c358b338d56b84a5ac1fb6 100644 --- a/libraries/dsp/fft/src/vhdl/fft_r2_par.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_r2_par.vhd @@ -127,15 +127,12 @@ architecture str of fft_r2_par is constant c_pipeline_remove_lsb : natural := 1; constant c_nof_stages : natural := ceil_log2(g_fft.nof_points); - constant c_nof_bf_per_stage : natural := g_fft.nof_points/2; - constant c_in_scale_w_tester : integer := g_fft.stage_dat_w - g_fft.in_dat_w - sel_a_b(g_fft.guard_enable, g_fft.guard_w, 0); - constant c_in_scale_w : natural := sel_a_b(c_in_scale_w_tester > 0, c_in_scale_w_tester, 0); -- Only scale when in_dat_w is not too big. - - constant c_out_scale_w : integer := g_fft.stage_dat_w - g_fft.out_dat_w - g_fft.out_gain_w; -- Estimate number of LSBs to throw away when > 0 or insert when < 0 + constant c_nof_bf_per_stage : natural := g_fft.nof_points/2; + + constant c_in_scale_w : natural := func_fft_in_scale_w(g_fft); + constant c_raw_fraction_w : natural := func_fft_raw_fraction_w(g_fft); + constant c_raw_dat_w : natural := func_fft_raw_dat_w(g_fft); - constant c_sepa_growth_w : natural := sel_a_b(g_fft.use_separate, 1, 0); -- add one bit for add sub growth in separate - constant c_raw_dat_w : natural := g_fft.stage_dat_w + c_sepa_growth_w; - type t_stage_dat_arr is array (integer range <>) of std_logic_vector(g_fft.stage_dat_w-1 downto 0); type t_stage_raw_arr is array (integer range <>) of std_logic_vector(c_raw_dat_w-1 downto 0); type t_data_arr2 is array(c_nof_stages downto 0) of t_stage_dat_arr(g_fft.nof_points-1 downto 0); @@ -158,6 +155,12 @@ architecture str of fft_r2_par is signal fft_im_arr : t_stage_raw_arr(g_fft.nof_points-1 downto 0); signal fft_val : std_logic; + -- debug signals to view parameters in Wave Window + signal dbg_g_g_fft : t_fft := g_fft; + signal dbg_c_in_scale_w : natural := c_in_scale_w; + signal dbg_c_raw_fraction_w : natural := c_raw_fraction_w; + signal dbg_c_raw_dat_w : natural := c_raw_dat_w; + begin ------------------------------------------------------------------------------ @@ -378,7 +381,7 @@ begin u_requantize_re : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", - g_lsb_w => c_out_scale_w + c_sepa_growth_w, + g_lsb_w => c_raw_fraction_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, g_msb_clip => FALSE, @@ -398,7 +401,7 @@ begin u_requantize_im : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", - g_lsb_w => c_out_scale_w + c_sepa_growth_w, + g_lsb_w => c_raw_fraction_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, g_msb_clip => FALSE, diff --git a/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd b/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd index a121630cc5a7d4cfae4612e8131265005feea65d..fb54876255fc2dc4474ef12659c55ec7b8b3fd41 100644 --- a/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd @@ -56,7 +56,19 @@ -- -- c0f0 c0f1 c0f2 ... c0f15 c1f0 c1f1 c1f2 ... c1f15 (c0f0 means channel 0, frequency bin 0) -- --- +-- . Output subband widths: +-- - out_quant_re/im : g_fft.out_dat_w bits (within c_32 word) +-- - out_raw_re/im : c_raw_dat_w bits (within c_32 word) +-- The out_quant carries subbands of g_fft.out_dat_w bits, so the +-- c_raw_fraction_w fraction bits in c_raw_dat_w have been rounded. +-- The out_raw carries subbands of c_raw_dat_w bits, that still have the +-- c_raw_fraction_w fraction bits. The out_raw subbands are suitable for +-- further weighting or alternative rounding. +-- Note that c_raw_dat_w and c_raw_fraction_w depend on g_fft.use_separate. +-- For real input data FFT there is one fraction bit more than for complex +-- input FFT, due to the adder stage in the separate function. +-- Both out_quant and out_raw use FFT out_val, so they have the same timing. +-- library ieee, common_lib, rTwoSDF_lib; use IEEE.std_logic_1164.all; @@ -88,7 +100,7 @@ end entity fft_r2_pipe; architecture str of fft_r2_pipe is - constant c_pipeline_remove_lsb : natural := 0; + constant c_pipeline_remove_lsb : natural := 1; -- to easy timing closure constant c_switch_en : boolean := g_fft.use_separate; -- default do apply switch/unswitch per real input to mitigate quantization crosstalk constant c_switch_sz_w : natural := ceil_log2(g_fft.nof_points) + g_fft.nof_chan; @@ -96,11 +108,12 @@ architecture str of fft_r2_pipe is constant c_switch_seed1 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := fft_switch_new_seed(c_fft_switch_seed1, g_instance_index); constant c_switch_seed2 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := fft_switch_new_seed(c_fft_switch_seed2, g_instance_index); constant c_nof_stages : natural := ceil_log2(g_fft.nof_points); - constant c_stage_offset : natural := true_log2(g_fft.wb_factor); -- Stage offset is required for twiddle generation in wideband fft - constant c_in_scale_w : natural := g_fft.stage_dat_w - g_fft.in_dat_w - sel_a_b(g_fft.guard_enable, g_fft.guard_w, 0); - constant c_out_scale_w : integer := g_fft.stage_dat_w - g_fft.out_dat_w - g_fft.out_gain_w; -- Estimate number of LSBs to throw throw away when > 0 or insert when < 0 - constant c_sepa_growth_w : natural := sel_a_b(g_fft.use_separate, 1, 0); -- add one bit for add sub growth in separate - constant c_raw_dat_w : natural := g_fft.stage_dat_w + c_sepa_growth_w; + constant c_stage_offset : natural := true_log2(g_fft.wb_factor); -- Stage offset is required for twiddle generation in wideband fft + + constant c_in_scale_w : natural := func_fft_in_scale_w(g_fft); + constant c_raw_fraction_w : natural := func_fft_raw_fraction_w(g_fft); + constant c_raw_dat_w : natural := func_fft_raw_dat_w(g_fft); + constant c_unswitch_dat_w : natural := c_raw_dat_w; -- no need for extra bit, because most negative value cannot occur in FFT output -- number the stage instances from c_nof_stages:1 @@ -134,8 +147,7 @@ architecture str of fft_r2_pipe is -- debug signals to view parameters in Wave Window signal dbg_g_g_fft : t_fft := g_fft; signal dbg_c_in_scale_w : natural := c_in_scale_w; - signal dbg_c_out_scale_w : integer := c_out_scale_w; - signal dbg_c_sepa_growth_w : natural := c_sepa_growth_w; + signal dbg_c_raw_fraction_w : natural := c_raw_fraction_w; signal dbg_c_raw_dat_w : natural := c_raw_dat_w; begin @@ -286,7 +298,7 @@ begin u_requantize_re : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", - g_lsb_w => c_out_scale_w + c_sepa_growth_w, + g_lsb_w => c_raw_fraction_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, g_msb_clip => FALSE, @@ -306,7 +318,7 @@ begin u_requantize_im : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", - g_lsb_w => c_out_scale_w + c_sepa_growth_w, + g_lsb_w => c_raw_fraction_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, g_msb_clip => FALSE, @@ -336,9 +348,10 @@ begin ------------------------------------------------------------------------------ -- Pipelined FFT raw output register - -- . Pipeline out_raw_* to align with out_quant_*, so they can share out_val ------------------------------------------------------------------------------ + -- . Pipeline out_raw to align with out_quant, so they can share + -- out_val. u_out_raw_re : entity common_lib.common_pipeline generic map ( g_representation => "SIGNED", diff --git a/libraries/dsp/fft/src/vhdl/fft_r2_wide.vhd b/libraries/dsp/fft/src/vhdl/fft_r2_wide.vhd index 0a2be83321af8634aee38c7b1ab681930c40db62..209ac150ba20fbde3b23005f8a1eaf9716fc53fd 100644 --- a/libraries/dsp/fft/src/vhdl/fft_r2_wide.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_r2_wide.vhd @@ -148,12 +148,9 @@ architecture rtl of fft_r2_wide is constant c_fft_r2_pipe_arr : t_fft_arr(g_fft.wb_factor-1 downto 0) := func_create_generic_for_pipe_fft(g_fft); constant c_fft_r2_par : t_fft := func_create_generic_for_par_fft(g_fft); - constant c_in_scale_w : natural := g_fft.stage_dat_w - g_fft.in_dat_w - sel_a_b(g_fft.guard_enable, g_fft.guard_w, 0); - - constant c_out_scale_w : integer := c_fft_r2_par.out_dat_w - g_fft.out_dat_w - g_fft.out_gain_w; -- Estimate number of LSBs to throw away when > 0 or insert when < 0 - - constant c_sepa_growth_w : natural := sel_a_b(g_fft.use_separate, 1, 0); -- add one bit for add sub growth in separate - constant c_raw_dat_w : natural := g_fft.stage_dat_w + c_sepa_growth_w; + constant c_in_scale_w : natural := func_fft_in_scale_w(g_fft); + constant c_raw_fraction_w : natural := func_fft_raw_fraction_w(g_fft); + constant c_raw_dat_w : natural := func_fft_raw_dat_w(g_fft); -- g_fft.wb_factor = 1 signal fft_pipe_out_re : std_logic_vector(g_fft.out_dat_w-1 downto 0); @@ -182,8 +179,7 @@ architecture rtl of fft_r2_wide is -- debug signals to view parameters in Wave Window signal dbg_g_g_fft : t_fft := g_fft; signal dbg_c_in_scale_w : natural := c_in_scale_w; - signal dbg_c_out_scale_w : integer := c_out_scale_w; - signal dbg_c_sepa_growth_w : natural := c_sepa_growth_w; + signal dbg_c_raw_fraction_w : natural := c_raw_fraction_w; signal dbg_c_raw_dat_w : natural := c_raw_dat_w; begin @@ -328,7 +324,7 @@ begin u_requantize_output_re : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", - g_lsb_w => c_out_scale_w + c_sepa_growth_w, + g_lsb_w => c_raw_fraction_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, g_msb_clip => FALSE, @@ -348,7 +344,7 @@ begin u_requantize_output_im : entity common_lib.common_requantize generic map ( g_representation => "SIGNED", - g_lsb_w => c_out_scale_w + c_sepa_growth_w, + g_lsb_w => c_raw_fraction_w, g_lsb_round => TRUE, g_lsb_round_clip => FALSE, g_msb_clip => FALSE,