diff --git a/libraries/base/common/src/vhdl/common_pkg.vhd b/libraries/base/common/src/vhdl/common_pkg.vhd index 6153caf04a8c55f7cfdb2b77674b7407161229a4..13d8042484abd05f906b0b30d243174e12139cb2 100644 --- a/libraries/base/common/src/vhdl/common_pkg.vhd +++ b/libraries/base/common/src/vhdl/common_pkg.vhd @@ -473,7 +473,9 @@ PACKAGE common_pkg IS FUNCTION SHIFT_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR; -- < 0 shift left, > 0 shift right FUNCTION SHIFT_SVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR; -- < 0 shift left, > 0 shift right - + + FUNCTION ROTATE_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR; -- < 0 rotate left, > 0 rotate right + FUNCTION offset_binary(a : STD_LOGIC_VECTOR) RETURN STD_LOGIC_VECTOR; FUNCTION truncate( vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR; -- remove n LSBits from vec, so result has width vec'LENGTH-n @@ -2271,6 +2273,17 @@ PACKAGE BODY common_pkg IS END IF; END; + FUNCTION ROTATE_UVEC(vec : STD_LOGIC_VECTOR; shift : INTEGER) RETURN STD_LOGIC_VECTOR IS + BEGIN + IF shift < 0 THEN + RETURN STD_LOGIC_VECTOR(ROTATE_LEFT(UNSIGNED(vec), -shift)); -- /<-- vec <--\ + -- \---------->/ + ELSE + RETURN STD_LOGIC_VECTOR(ROTATE_RIGHT(UNSIGNED(vec), shift)); -- /--> vec -->\ + -- \<----------/ + END IF; + END; + -- -- offset_binary() : maps offset binary to or from two-complement binary. -- diff --git a/libraries/dsp/fft/hdllib.cfg b/libraries/dsp/fft/hdllib.cfg index a75778467bbdea6b49354de1f431115a5b5dd9d8..aee1489da150feebf22084542d8ebd71b86484e8 100644 --- a/libraries/dsp/fft/hdllib.cfg +++ b/libraries/dsp/fft/hdllib.cfg @@ -21,7 +21,8 @@ synth_files = test_bench_files = tb/vhdl/tb_fft_pkg.vhd - tb/vhdl/tb_fft_functions.vhd + tb/vhdl/tb_fft_functions.vhd + tb/vhdl/tb_fft_lfsr.vhd tb/vhdl/tb_fft_switch.vhd tb/vhdl/tb_fft_sepa.vhd tb/vhdl/tb_fft_reorder_sepa_pipe.vhd @@ -32,11 +33,12 @@ test_bench_files = tb/vhdl/tb_fft_wide_unit.vhd tb/vhdl/tb_mmf_fft_r2.vhd tb/vhdl/tb_mmf_fft_wide_unit.vhd - tb/vhdl/tb_tb_fft_r2_pipe.vhd + tb/vhdl/tb_tb_fft_r2_pipe.vhd tb/vhdl/tb_tb_fft_r2_par.vhd tb/vhdl/tb_tb_fft_r2_wide.vhd regression_test_vhdl = + tb/vhdl/tb_fft_lfsr.vhd tb/vhdl/tb_fft_switch.vhd tb/vhdl/tb_tb_fft_r2_pipe.vhd tb/vhdl/tb_tb_fft_r2_par.vhd diff --git a/libraries/dsp/fft/src/vhdl/fft_lfsr.vhd b/libraries/dsp/fft/src/vhdl/fft_lfsr.vhd index 56f5b5e453f9a2e009a05c2418f6890ee6aa22e3..7f53b0a398f8dddef39cc056eb7225767d53362b 100644 --- a/libraries/dsp/fft/src/vhdl/fft_lfsr.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_lfsr.vhd @@ -21,12 +21,20 @@ -- Author: ported by E. Kooistra, original 2004 by W. Lubberhuizen / W. Poeisz -- Purpose: Scramble quantization noise crosstalk between two real inputs -- Description: Ported from LOFAR1, see readme_lofar1.txt --- Remark: Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_lfsr.vhd +-- Remark: +-- . Copy from applications/lofar1/RSP/pft2/src/vhdl/pft_lfsr.vhd +-- . The g_seed must be > 0 for LFSR period is 2**c_fft_lfsr_len - 1. Value +-- g_seed = 0 causes the LFSR to remain stuck at 0. LIBRARY IEEE; USE IEEE.std_logic_1164.ALL; +USE work.fft_pkg.ALL; ENTITY fft_lfsr IS + GENERIC ( + g_seed1 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := c_fft_switch_seed1; + g_seed2 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := c_fft_switch_seed2 + ); PORT ( in_en : IN STD_LOGIC; out_bit1 : OUT STD_LOGIC; @@ -43,23 +51,23 @@ ARCHITECTURE rtl OF fft_lfsr IS -- x^41 + x^20 + 1 and x^41 + x^3 + 1 -- see XAPP217 - CONSTANT c_max : NATURAL := 41; + CONSTANT c_len : NATURAL := c_fft_lfsr_len; -- = 41, same for both trinomials CONSTANT c1 : NATURAL := 20; CONSTANT c2 : NATURAL := 3; - SIGNAL s1 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); - SIGNAL nxt_s1 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); - - SIGNAL s2 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); - SIGNAL nxt_s2 : STD_LOGIC_VECTOR(c_max-1 DOWNTO 0); - + SIGNAL s1 : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0); + SIGNAL nxt_s1 : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0); + SIGNAL s2 : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0); + SIGNAL nxt_s2 : STD_LOGIC_VECTOR(c_len-1 DOWNTO 0); + BEGIN + p_reg : PROCESS(rst,clk) BEGIN IF rst='1' THEN - s1 <= "01000101011101110101001011111000101100001"; - s2 <= "11011001000101001011011001110101100101100"; + s1 <= g_seed1; + s2 <= g_seed2; ELSIF rising_edge(clk) THEN s1 <= nxt_s1; s2 <= nxt_s2; @@ -69,22 +77,22 @@ BEGIN out_bit1 <= s1(s1'HIGH); out_bit2 <= s2(s2'HIGH); - p_seed : PROCESS(in_en,s1,s2) + p_seed : PROCESS(in_en, s1, s2) BEGIN nxt_s1 <= s1; nxt_s2 <= s2; - IF in_en='1' THEN + IF in_en = '1' THEN -- shift - nxt_s1(c_max-1 DOWNTO 1) <= s1(c_max-2 DOWNTO 0); - nxt_s2(c_max-1 DOWNTO 1) <= s2(c_max-2 DOWNTO 0); + nxt_s1(c_len-1 DOWNTO 1) <= s1(c_len-2 DOWNTO 0); + nxt_s2(c_len-1 DOWNTO 1) <= s2(c_len-2 DOWNTO 0); -- feedback 1 - nxt_s1(0) <= s1(c_max-1); - nxt_s2(0) <= s2(c_max-1); + nxt_s1(0) <= s1(c_len-1); + nxt_s2(0) <= s2(c_len-1); -- feedback 2 - nxt_s1(c1) <= s1(c_max-1) xor s1(c1-1); - nxt_s2(c2) <= s2(c_max-1) xor s2(c2-1); + nxt_s1(c1) <= s1(c_len-1) xor s1(c1-1); + nxt_s2(c2) <= s2(c_len-1) xor s2(c2-1); END IF; END PROCESS; diff --git a/libraries/dsp/fft/src/vhdl/fft_pkg.vhd b/libraries/dsp/fft/src/vhdl/fft_pkg.vhd index 4b4a00f80ba00c619efabaf1b8c5be9995588636..05eaa1ffb226920d9127c5d69ea56bdd2ecacefe 100644 --- a/libraries/dsp/fft/src/vhdl/fft_pkg.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_pkg.vhd @@ -25,6 +25,13 @@ use common_lib.common_pkg.all; package fft_pkg is + -- Default FFT switch and unswitch seeds from LOFAR1 + constant c_fft_lfsr_len : natural := 41; + constant c_fft_switch_seed1 : std_logic_vector(c_fft_lfsr_len-1 DOWNTO 0) := "01000101011101110101001011111000101100001"; + constant c_fft_switch_seed2 : std_logic_vector(c_fft_lfsr_len-1 DOWNTO 0) := "11011001000101001011011001110101100101100"; + + function fft_switch_new_seed(seed : std_logic_vector; offset : natural) return std_logic_vector; + -- FFT parameters for pipelined FFT (fft_pipe), parallel FFT (fft_par) and wideband FFT (fft_wide) type t_fft is record use_reorder : boolean; -- = false for bit-reversed output, true for normal output @@ -68,6 +75,11 @@ end package fft_pkg; package body fft_pkg is + function fft_switch_new_seed(seed : std_logic_vector; offset : natural) return std_logic_vector is + begin + return INCR_UVEC(seed, offset); -- make new unique seed + end; + function fft_r2_parameter_asserts(g_fft : t_fft) return boolean is begin -- nof_points diff --git a/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd b/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd index c9ed7f72c558ac588935c3670265363a810f4b5f..00c2007bd8a4bb7bafb6ca126bf1a11b5f602755 100644 --- a/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_r2_pipe.vhd @@ -66,6 +66,7 @@ use work.fft_pkg.all; entity fft_r2_pipe is generic ( + g_instance_index : natural := 0; -- used for FFT switch seed g_fft : t_fft := c_fft; -- generics for the FFT g_pipeline : t_fft_pipeline := c_fft_pipeline; -- generics for pipelining in each stage, defined in rTwoSDF_lib.rTwoSDFPkg g_dont_flip_channels : boolean := false; -- generic to prevent re-ordering of the channels @@ -92,6 +93,8 @@ architecture str of fft_r2_pipe is constant c_switch_sz_w : natural := ceil_log2(g_fft.nof_points) + g_fft.nof_chan; constant c_switch_dat_w : natural := g_fft.in_dat_w + 1; -- add 1 extra bit to fit negation of most negative value per real input switch function constant c_unswitch_dat_w : natural := g_fft.out_dat_w; -- no need for extra bit, because most negative value cannot occur in output + 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); @@ -143,6 +146,8 @@ begin u_switch : ENTITY work.fft_switch GENERIC MAP ( g_switch_en => c_switch_en, + g_seed1 => c_switch_seed1, + g_seed2 => c_switch_seed2, g_fft_sz_w => c_switch_sz_w, g_dat_w => c_switch_dat_w ) @@ -303,6 +308,8 @@ begin u_unswitch : ENTITY work.fft_unswitch GENERIC MAP ( g_switch_en => c_switch_en, + g_seed1 => c_switch_seed1, + g_seed2 => c_switch_seed2, g_fft_sz_w => c_switch_sz_w, g_dat_w => c_unswitch_dat_w ) diff --git a/libraries/dsp/fft/src/vhdl/fft_switch.vhd b/libraries/dsp/fft/src/vhdl/fft_switch.vhd index cad57405ab3b2c03ed84834171fab082b2ed6b51..9da13b566ede8834d55739437b8515417fac3bf5 100644 --- a/libraries/dsp/fft/src/vhdl/fft_switch.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_switch.vhd @@ -46,10 +46,13 @@ LIBRARY IEEE, common_lib; USE IEEE.std_logic_1164.ALL; USE common_lib.common_pkg.ALL; +USE work.fft_pkg.ALL; ENTITY fft_switch IS GENERIC ( g_switch_en : BOOLEAN := FALSE; + g_seed1 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := c_fft_switch_seed1; + g_seed2 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := c_fft_switch_seed2; g_fft_sz_w : NATURAL; g_dat_w : NATURAL ); @@ -156,6 +159,10 @@ BEGIN END PROCESS; u_fft_lfsr: ENTITY work.fft_lfsr + GENERIC MAP ( + g_seed1 => g_seed1, + g_seed2 => g_seed2 + ) PORT MAP ( clk => clk, rst => rst, diff --git a/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd b/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd index 6d9f561a15e7ca184f70c418810bd85f9b1ac6d6..f94f12e7f0954a3b6af011504a33052e471bef90 100644 --- a/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd +++ b/libraries/dsp/fft/src/vhdl/fft_unswitch.vhd @@ -31,10 +31,13 @@ LIBRARY IEEE, common_lib; USE IEEE.std_logic_1164.ALL; USE common_lib.common_pkg.ALL; +USE work.fft_pkg.ALL; ENTITY fft_unswitch IS GENERIC ( g_switch_en : BOOLEAN := FALSE; + g_seed1 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := c_fft_switch_seed1; + g_seed2 : STD_LOGIC_VECTOR(c_fft_lfsr_len-1 DOWNTO 0) := c_fft_switch_seed2; g_fft_sz_w : NATURAL; g_dat_w : NATURAL ); @@ -147,6 +150,10 @@ BEGIN END PROCESS; u_fft_lfsr: ENTITY work.fft_lfsr + GENERIC MAP ( + g_seed1 => g_seed1, + g_seed2 => g_seed2 + ) PORT MAP ( clk => clk, rst => rst, diff --git a/libraries/dsp/fft/tb/vhdl/tb_fft_lfsr.vhd b/libraries/dsp/fft/tb/vhdl/tb_fft_lfsr.vhd new file mode 100644 index 0000000000000000000000000000000000000000..23791ba61bcdf56d68adae81c6b3d1672fb22166 --- /dev/null +++ b/libraries/dsp/fft/tb/vhdl/tb_fft_lfsr.vhd @@ -0,0 +1,92 @@ +------------------------------------------------------------------------------- +-- +-- Copyright 2021 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +------------------------------------------------------------------------------- +-- +-- Author: E. Kooistra +-- Purpose: Verify fft_lsfr for different seeds +-- Description: +-- Check that after c_fft_lfsr_len = 41 blocks the LFSR1 and LFSR2 bits of +-- the two instances u0 and u1 indeed start to differ. +-- +-- Usage: +-- > as 4 +-- > run -all +-- # Not self checking, manually compare that u0_lfsr_bit1 and u1_lfsr_bit1 +-- start to differ after about c_fft_lfsr_len blocks. Similar for +-- u0_lfsr_bit1 and u1_lfsr_bit1. +LIBRARY IEEE, common_lib; +USE IEEE.std_logic_1164.ALL; +USE work.fft_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; + +ENTITY tb_fft_lfsr IS +END tb_fft_lfsr; + +ARCHITECTURE tb OF tb_fft_lfsr IS + + CONSTANT clk_period : TIME := 10 ns; + + CONSTANT c_block_period : NATURAL := 10; + CONSTANT c_nof_block : NATURAL := 1000; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC := '1'; + SIGNAL clk : STD_LOGIC := '0'; + + SIGNAL in_en : STD_LOGIC := '0'; + SIGNAL u0_lfsr_bit1 : STD_LOGIC; + SIGNAL u1_lfsr_bit1 : STD_LOGIC; + SIGNAL u0_lfsr_bit2 : STD_LOGIC; + SIGNAL u1_lfsr_bit2 : STD_LOGIC; + +BEGIN + + clk <= NOT clk OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER 10 * clk_period; + tb_end <= '0', '1' AFTER c_nof_block * c_block_period * clk_period; + + proc_common_gen_pulse(1, c_block_period, '1', rst, clk, in_en); + + u0 : ENTITY work.fft_lfsr + GENERIC MAP ( + g_seed1 => fft_switch_new_seed(c_fft_switch_seed1, 0), + g_seed2 => fft_switch_new_seed(c_fft_switch_seed2, 0) + ) + PORT MAP ( + in_en => in_en, + out_bit1 => u0_lfsr_bit1, + out_bit2 => u0_lfsr_bit2, + clk => clk, + rst => rst + ); + + u1 : ENTITY work.fft_lfsr + GENERIC MAP ( + g_seed1 => fft_switch_new_seed(c_fft_switch_seed1, 1), + g_seed2 => fft_switch_new_seed(c_fft_switch_seed2, 1) + ) + PORT MAP ( + in_en => in_en, + out_bit1 => u1_lfsr_bit1, + out_bit2 => u1_lfsr_bit2, + clk => clk, + rst => rst + ); + +END tb; diff --git a/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd b/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd index 08d04ee3e9bae1ffaea762e535be0d38d97395f6..981f017da2af2a9125e6155283168f6e17d83542 100644 --- a/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd +++ b/libraries/dsp/fft/tb/vhdl/tb_fft_switch.vhd @@ -52,9 +52,11 @@ LIBRARY IEEE, common_lib; USE IEEE.std_logic_1164.ALL; USE common_lib.common_pkg.ALL; USE common_lib.tb_common_pkg.ALL; +USE work.fft_pkg.ALL; ENTITY tb_fft_switch IS GENERIC ( + g_instance_index : NATURAL := 0; g_switch_en : BOOLEAN := TRUE; g_in_val_gaps : BOOLEAN := TRUE; g_increment_at_val : BOOLEAN := TRUE; @@ -66,9 +68,9 @@ END tb_fft_switch; ARCHITECTURE tb OF tb_fft_switch IS - CONSTANT clk_period : TIME := 10 ns; + CONSTANT clk_period : TIME := 10 ns; - CONSTANT c_dat_w : NATURAL := 16; + CONSTANT c_dat_w : NATURAL := 16; CONSTANT c_nof_clk_per_block : NATURAL := 2**g_fft_size_w; CONSTANT c_nof_block_per_sync_max : NATURAL := ceil_div(g_nof_clk_per_sync, c_nof_clk_per_block); @@ -76,6 +78,9 @@ ARCHITECTURE tb OF tb_fft_switch IS CONSTANT c_dly : NATURAL := 4; -- pipeling in fft_switch, mux, fft_unswitch and demux + 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); + SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL rst : STD_LOGIC := '1'; SIGNAL clk : STD_LOGIC := '0'; @@ -185,6 +190,8 @@ BEGIN u_fft_switch : ENTITY work.fft_switch GENERIC MAP ( g_switch_en => g_switch_en, + g_seed1 => c_switch_seed1, + g_seed2 => c_switch_seed2, g_fft_sz_w => g_fft_size_w, g_dat_w => c_dat_w ) @@ -227,6 +234,8 @@ BEGIN u_fft_unswitch : ENTITY work.fft_unswitch GENERIC MAP ( g_switch_en => g_switch_en, + g_seed1 => c_switch_seed1, + g_seed2 => c_switch_seed2, g_fft_sz_w => g_fft_size_w, g_dat_w => c_dat_w ) diff --git a/libraries/dsp/wpfb/src/vhdl/wpfb_unit_dev.vhd b/libraries/dsp/wpfb/src/vhdl/wpfb_unit_dev.vhd index 158f3cb747fb60b86fb13e8ba917f330920df0d1..c12d89665762e8451ba9e6e337e367d3bb72f11f 100644 --- a/libraries/dsp/wpfb/src/vhdl/wpfb_unit_dev.vhd +++ b/libraries/dsp/wpfb/src/vhdl/wpfb_unit_dev.vhd @@ -597,6 +597,7 @@ begin gen_fft_r2_pipe_streams: for S in 0 to g_wpfb.nof_wb_streams-1 generate u_fft_r2_pipe : entity fft_lib.fft_r2_pipe generic map( + g_instance_index => S, g_fft => c_fft, g_pipeline => g_wpfb.fft_pipeline, g_dont_flip_channels => g_dont_flip_channels,