diff --git a/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd b/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd index e4cc98a53afa0c25c99646533f225e30c50eca56..42a9cf115ea4a2c4028aba1d85035741d833a3a6 100644 --- a/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd +++ b/libraries/dsp/filter/src/vhdl/fil_ppf_wide.vhd @@ -18,41 +18,77 @@ -- along with this program. If not, see <http://www.gnu.org/licenses/>. -- ------------------------------------------------------------------------------- --- Purpose: Performing a poly phase prefilter (PPF) function on one or multiple wideband data stream. +-- Purpose: Performing a poly phase prefilter (PPF) function on one or more +-- wideband data stream. -- -- Description: --- The poly phase prefilter function is applied on multiple inputs. The --- incoming data must be divided over the inputs as shown in the --- following example for nof_streams=1 and wb_factor is 4: +-- The poly phase prefilter function is applied on multiple inputs. In +-- array notation: -- --- array stream wb time index --- index index index --- 3 0 0 : t0, t4, t8, t12, t16... --- 2 0 1 : t1, t5, t9, t13, t17... --- 1 0 2 : t2, t6, t10, t14, t18... --- 0 0 3 : t3, t7, t11, t15, t19... +-- parallel serial type +-- in_dat_arr [wb_factor][nof_streams] [t][nof_channels] int +-- out_dat_arr [wb_factor][nof_streams] [t][nof_channels] int +-- +-- If g_big_endian_wb_*=true then the time t to wb_factor P mapping for the +-- fil_ppf_wide is t[0,1,2,3] = P[3,2,1,0], else when it is false then the +-- mapping is t[3,2,1,0] = P[3,2,1,0]. The mapping can be selected +-- independently for the in_dat_arr and the out_dat_arr. +-- +-- The incoming data must be divided over the inputs as shown in the +-- following example for nof_streams=1 and wb_factor is 4. The array +-- index I runs from [wb_factor*nof_streams-1:0]. +-- +-- array wb stream time index when g_big_endian_wb_*=true) +-- index index index +-- I P S t +-- 3 3 0 : 0, 4, 8, 12, 16, ... +-- 2 2 0 : 1, 5, 9, 13, 17, ... +-- 1 1 0 : 2, 6, 10, 14, 18, ... +-- 0 0 0 : 3, 7, 11, 15, 19, ... +-- ^ +-- big endian -- -- Every array input will be filtered by a fil_ppf_single instance. It is -- also possible to offer multiple wideband input streams. Those wide -- band input streams will share the filter coefficients. For a system with --- nof_streams=2 and wb_factor=4 the array inputs become (s0t0 means wide --- band stream 0, timestamp 0): +-- nof_streams=2 and wb_factor=4 the array inputs become: +-- +-- array wb stream time index when g_big_endian_wb_*=true) +-- index index index +-- I P S t +-- 7 3 1 : 0, 4, 8, 12, 16, ... +-- 6 3 0 : 0, 4, 8, 12, 16, ... +-- 5 2 1 : 1, 5, 9, 13, 17, ... +-- 4 2 0 : 1, 5, 9, 13, 17, ... +-- 3 1 1 : 2, 6, 10, 14, 18, ... +-- 2 1 0 : 2, 6, 10, 14, 18, ... +-- 1 0 1 : 3, 7, 11, 15, 19, ... +-- 0 0 0 : 3, 7, 11, 15, 19, ... +-- ^ +-- big endian -- --- array stream wb time index --- index index index --- 7 0 0 : s0t0, s0t4, s0t8, s0t12, s0t16... --- 6 1 0 : s1t0, s1t4, s1t8, s1t12, s1t16... --- 5 0 1 : s0t1, s0t5, s0t9, s0t13, s0t17... --- 4 1 1 : s1t1, s1t5, s1t9, s1t13, s1t17... --- 3 0 2 : s0t2, s0t6, s0t10, s0t14, s0t18... --- 2 1 2 : s1t2, s1t6, s1t10, s1t14, s1t18... --- 1 0 3 : s0t3, s0t7, s0t11, s0t15, s0t19... --- 0 1 3 : s1t3, s1t7, s1t11, s1t15, s1t19... +-- Note that I, P and S all increment in the same direction and t increments +-- in the opposite direction of P. This is the g_big_endian_wb_in=true and +-- g_big_endian_wb_out=true format for the in_dat_arr and out_dat_arr. -- --- For fil_ppf_wide with wb_factor > 1 the array index runs from --- [wb_factor*nof_streams-1:0]. However per stream the wb_factor index --- needs to run in big endian order from [0:wb_factor-1], so this needs to --- be accounted for when connecting wide band streams to fil_ppf_wide. +-- If g_big_endian_wb_in=false and g_big_endian_wb_out=false for little endian +-- format, then the time t increments in the same direction as P, for both +-- in_dat_arr and out_dat_arr, so then I, P and S all increment in the same +-- direction: +-- +-- array wb stream time index when g_big_endian_wb_*=false +-- index index index +-- I P S t +-- 7 3 1 : 3, 7, 11, 15, 19, ... +-- 6 3 0 : 3, 7, 11, 15, 19, ... +-- 5 2 1 : 2, 6, 10, 14, 18, ... +-- 4 2 0 : 2, 6, 10, 14, 18, ... +-- 3 1 1 : 1, 5, 9, 13, 17, ... +-- 2 1 0 : 1, 5, 9, 13, 17, ... +-- 1 0 1 : 0, 4, 8, 12, 16, ... +-- 0 0 0 : 0, 4, 8, 12, 16, ... +-- ^ +-- little endian -- -- With wb_factor > 1 and nof_streams > 1 the streams in in_dat_arr and -- out_dat_arr are looped first and then the wb_factor is looped. This @@ -77,6 +113,8 @@ use work.fil_pkg.ALL; entity fil_ppf_wide is generic ( + g_big_endian_wb_in : boolean := true; + g_big_endian_wb_out : boolean := true; g_fil_ppf : t_fil_ppf := c_fil_ppf; g_fil_ppf_pipeline : t_fil_ppf_pipeline := c_fil_ppf_pipeline; g_file_index_arr : t_nat_natural_arr := array_init(0, 128, 1); -- default use the instance index as file index 0, 1, 2, 3, 4 ... @@ -100,8 +138,9 @@ architecture rtl of fil_ppf_wide is type t_fil_ppf_arr is array(integer range <> ) of t_fil_ppf; -- An array of t_fil_ppf's generics. type t_nat_natural_arr2 is array(integer range <> ) of t_nat_natural_arr(127 downto 0); -- An array of arrays, used to point to the right .mif files for the coefficients - type t_out_arr is array(integer range <> ) of std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.out_dat_w -1 downto 0); - type t_in_arr is array(integer range <> ) of std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.in_dat_w -1 downto 0); + + type t_streams_in_arr is array(integer range <> ) of std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.in_dat_w -1 downto 0); + type t_streams_out_arr is array(integer range <> ) of std_logic_vector(g_fil_ppf.nof_streams*g_fil_ppf.out_dat_w -1 downto 0); ---------------------------------------------------------- -- This function creates an array of t_fil_ppf generics @@ -115,22 +154,22 @@ architecture rtl of fil_ppf_wide is variable v_nof_bands : natural := input.nof_bands/input.wb_factor; -- The nof_bands for the single channel poly phase filters variable v_return : t_fil_ppf_arr(input.wb_factor-1 downto 0) := (others => input); -- Variable that holds the return values begin - for I in 0 to input.wb_factor-1 loop - v_return(I).nof_bands := v_nof_bands; -- The new number of bands + for P in 0 to input.wb_factor-1 loop + v_return(P).nof_bands := v_nof_bands; -- The new number of bands end loop; return v_return; end; ---------------------------------------------------------- - -- Function that divids the input file index array into + -- Function that divides the input file index array into -- "wb_factor" new file index arrays. ---------------------------------------------------------- function func_create_file_index_array(input: t_nat_natural_arr; wb_factor: natural; nof_taps: natural) return t_nat_natural_arr2 is variable v_return : t_nat_natural_arr2(wb_factor-1 downto 0) := (others => input); -- Variable that holds the return values begin - for I in 0 to wb_factor-1 loop - for J in 0 to nof_taps-1 loop - v_return(I)(J) := input(I*nof_taps+J); + for P in 0 to wb_factor-1 loop + for T in 0 to nof_taps-1 loop + v_return(P)(T) := input(P*nof_taps+T); end loop; end loop; return v_return; @@ -141,11 +180,12 @@ architecture rtl of fil_ppf_wide is constant c_mem_addr_w : natural := ceil_log2(g_fil_ppf.nof_bands * g_fil_ppf.nof_taps / g_fil_ppf.wb_factor); - signal ram_coefs_mosi_arr : t_mem_mosi_arr(g_fil_ppf.wb_factor-1 downto 0); - signal ram_coefs_miso_arr : t_mem_miso_arr(g_fil_ppf.wb_factor-1 downto 0) := (others => c_mem_miso_rst); - signal out_val_i : std_logic_vector(g_fil_ppf.wb_factor-1 downto 0); - signal out_arr_i : t_out_arr(g_fil_ppf.wb_factor-1 downto 0); - signal in_dat_vect_arr : t_in_arr(g_fil_ppf.wb_factor-1 downto 0); + signal ram_coefs_mosi_arr : t_mem_mosi_arr(g_fil_ppf.wb_factor-1 downto 0); + signal ram_coefs_miso_arr : t_mem_miso_arr(g_fil_ppf.wb_factor-1 downto 0) := (others => c_mem_miso_rst); + + signal streams_in_arr : t_streams_in_arr( g_fil_ppf.wb_factor-1 downto 0); + signal streams_out_arr : t_streams_out_arr(g_fil_ppf.wb_factor-1 downto 0); + signal streams_out_val_arr : std_logic_vector( g_fil_ppf.wb_factor-1 downto 0); begin --------------------------------------------------------------- @@ -165,22 +205,30 @@ begin miso_arr => ram_coefs_miso_arr ); - gen_in_vect_wb : for I in 0 to g_fil_ppf.wb_factor-1 generate - gen_in_vect_streams : for J in 0 to g_fil_ppf.nof_streams-1 generate - --in_dat_vect_arr(I)((J+1)*g_fil_ppf.in_dat_w-1 downto J*g_fil_ppf.in_dat_w) <= in_dat_arr(J*g_fil_ppf.wb_factor+I)(g_fil_ppf.in_dat_w-1 downto 0); - in_dat_vect_arr(I)((J+1)*g_fil_ppf.in_dat_w-1 downto J*g_fil_ppf.in_dat_w) <= in_dat_arr(I*g_fil_ppf.nof_streams+J)(g_fil_ppf.in_dat_w-1 downto 0); - end generate; - end generate; + p_wire_input : process(in_dat_arr) + variable vP : natural; + begin + for P in 0 to g_fil_ppf.wb_factor-1 loop + if g_big_endian_wb_in=true then + vP := P; -- big endian time [0,1,2,3] to P [3,2,1,0] index mapping + else + vP := g_fil_ppf.wb_factor-1-P; -- little endian time [0,1,2,3] to P [0,1,2,3] index mapping + end if; + for S in 0 to g_fil_ppf.nof_streams-1 loop + streams_in_arr(vP)((S+1)*g_fil_ppf.in_dat_w-1 downto S*g_fil_ppf.in_dat_w) <= in_dat_arr(P*g_fil_ppf.nof_streams+S)(g_fil_ppf.in_dat_w-1 downto 0); + end loop; + end loop; + end process; --------------------------------------------------------------- -- INSTANTIATE MULTIPLE SINGLE CHANNEL POLY PHASE FILTERS --------------------------------------------------------------- - gen_ppf_singles : for I in 0 to g_fil_ppf.wb_factor-1 generate - u_single_filter : entity work.fil_ppf_single + gen_fil_ppf_singles : for P in 0 to g_fil_ppf.wb_factor-1 generate + u_fil_ppf_single : entity work.fil_ppf_single generic map ( - g_fil_ppf => c_fil_ppf_arr(I), + g_fil_ppf => c_fil_ppf_arr(P), g_fil_ppf_pipeline => g_fil_ppf_pipeline, - g_file_index_arr => c_file_index_arr2(I), + g_file_index_arr => c_file_index_arr2(P), g_coefs_file_prefix => g_coefs_file_prefix ) port map ( @@ -188,18 +236,30 @@ begin dp_rst => dp_rst, mm_clk => mm_clk, mm_rst => mm_rst, - ram_coefs_mosi => ram_coefs_mosi_arr(I), - ram_coefs_miso => ram_coefs_miso_arr(I), - in_dat => in_dat_vect_arr(I), + ram_coefs_mosi => ram_coefs_mosi_arr(P), + ram_coefs_miso => ram_coefs_miso_arr(P), + in_dat => streams_in_arr(P), in_val => in_val, - out_dat => out_arr_i(I), - out_val => out_val_i(I) + out_dat => streams_out_arr(P), + out_val => streams_out_val_arr(P) ); - gen_in_vect_streams : for J in 0 to g_fil_ppf.nof_streams-1 generate - out_dat_arr(I*g_fil_ppf.nof_streams+J) <= RESIZE_SVEC(out_arr_i(I)((J+1)*g_fil_ppf.out_dat_w-1 downto J*g_fil_ppf.out_dat_w), out_dat_arr(I)'LENGTH); - end generate; end generate; - out_val <= out_val_i(0); + p_wire_output : process(streams_out_arr) + variable vP : natural; + begin + for P in 0 to g_fil_ppf.wb_factor-1 loop + if g_big_endian_wb_in=true then + vP := P; -- big endian time [0,1,2,3] to P [3,2,1,0] index mapping + else + vP := g_fil_ppf.wb_factor-1-P; -- little endian time [0,1,2,3] to P [0,1,2,3] index mapping + end if; + for S in 0 to g_fil_ppf.nof_streams-1 loop + out_dat_arr(vP*g_fil_ppf.nof_streams+S) <= RESIZE_SVEC_32(streams_out_arr(P)((S+1)*g_fil_ppf.out_dat_w-1 downto S*g_fil_ppf.out_dat_w)); + end loop; + end loop; + end process; + + out_val <= streams_out_val_arr(0); end rtl;