diff --git a/libraries/dsp/correlator/src/vhdl/corr_accumulator.vhd b/libraries/dsp/correlator/src/vhdl/corr_accumulator.vhd index 4d80e5106f9f13403e8961ac68a59c0be0c28733..102434984b1dc609bc3b119c45ce89ac3ba34595 100644 --- a/libraries/dsp/correlator/src/vhdl/corr_accumulator.vhd +++ b/libraries/dsp/correlator/src/vhdl/corr_accumulator.vhd @@ -30,14 +30,14 @@ USE dp_lib.dp_stream_pkg.ALL; -- Description: -- . A RAM-block is used to store the running sums as wel as to output the -- corresponding previous running sum so both align at the adder inputs. --- . g_nof_words_to_acc=0 connects the source to the sink. +-- . g_integration_period=0 connects the source to the sink. ENTITY corr_accumulator IS GENERIC ( - g_nof_inputs : NATURAL; -- Number of input streams - g_nof_acc_per_input : NATURAL; -- Number of accumulators to keep per input stream (a.k.a. channels) - g_nof_words_to_acc : NATURAL; -- Number of words to accumulate - g_data_w : NATURAL -- Complex input data width + g_nof_inputs : NATURAL; -- Number of input streams + g_nof_channels : NATURAL; -- Number of accumulators to keep per input stream + g_integration_period : NATURAL; -- Number of timesamples to accumulate + g_data_w : NATURAL -- Complex input data width ); PORT ( rst : IN STD_LOGIC; @@ -50,22 +50,22 @@ END corr_accumulator; ARCHITECTURE str OF corr_accumulator IS - -- Complex accumulator data width: wide enough to support g_nof_words_to_acc accumulations - CONSTANT c_acc_data_w : NATURAL := ceil_log2(g_nof_words_to_acc*(pow2(g_data_w)-1)); + -- Complex accumulator data width: wide enough to support g_integration_period accumulations + CONSTANT c_acc_data_w : NATURAL := ceil_log2(g_integration_period*(pow2(g_data_w)-1)); -- c_shiftram_delay is such that common_shiftram output aligns exactly with snk_in_arr. Functionally this -- means we aligned the current word to the corresponding previous word at the adder inputs. CONSTANT c_shiftram_io_delay : NATURAL := 4; -- common_shiftram data_in takes 4 cycles to emerge as data_out -- Note: Increase corr_adder pipelining by n = decrease c_shiftram_io_delay by n and vice versa. - CONSTANT c_shiftram_delay : NATURAL := g_nof_acc_per_input-c_shiftram_io_delay-2; + CONSTANT c_shiftram_delay : NATURAL := g_nof_channels-c_shiftram_io_delay-2; - CONSTANT c_shift_w : NATURAL := ceil_log2(g_nof_acc_per_input); + CONSTANT c_shift_w : NATURAL := ceil_log2(g_nof_channels); CONSTANT c_common_shiftram_shift_in : STD_LOGIC_VECTOR(c_shift_w-1 DOWNTO 0) := TO_UVEC(c_shiftram_delay, c_shift_w); -- Counter to keep track of the total numer of accumulations so we know when to reset accumulator to zero - SIGNAL acc_cnt : STD_LOGIC_VECTOR(ceil_log2(g_nof_acc_per_input*g_nof_words_to_acc)-1 DOWNTO 0); - SIGNAL nxt_acc_cnt : STD_LOGIC_VECTOR(ceil_log2(g_nof_acc_per_input*g_nof_words_to_acc)-1 DOWNTO 0); + SIGNAL acc_cnt : STD_LOGIC_VECTOR(ceil_log2(g_nof_channels*g_integration_period)-1 DOWNTO 0); + SIGNAL nxt_acc_cnt : STD_LOGIC_VECTOR(ceil_log2(g_nof_channels*g_integration_period)-1 DOWNTO 0); SIGNAL corr_adder_snk_in_2arr_2 : t_dp_sosi_2arr_2(g_nof_inputs-1 DOWNTO 0); -- Array of pairs SIGNAL nxt_corr_adder_snk_in_2arr_2 : t_dp_sosi_2arr_2(g_nof_inputs-1 DOWNTO 0); -- Array of pairs @@ -88,15 +88,15 @@ BEGIN -- we'll feed zeros into the second adder input to reset the accumulator value -- for each channel. ----------------------------------------------------------------------------- - nxt_acc_cnt <= (OTHERS=>'0') WHEN TO_UINT(acc_cnt)=g_nof_acc_per_input*g_nof_words_to_acc-1 ELSE + nxt_acc_cnt <= (OTHERS=>'0') WHEN TO_UINT(acc_cnt)=g_nof_channels*g_integration_period-1 ELSE INCR_UVEC(acc_cnt, 1) WHEN snk_in_arr(0).valid = '1' ELSE acc_cnt; gen_adder_inputs : FOR i IN 0 TO g_nof_inputs-1 GENERATE nxt_corr_adder_snk_in_2arr_2(i)(0) <= snk_in_arr(i); nxt_corr_adder_snk_in_2arr_2(i)(1).valid <= common_shiftram_src_out_arr(i).valid; - nxt_corr_adder_snk_in_2arr_2(i)(1).re(c_acc_data_w-1 DOWNTO 0) <= (OTHERS=>'0') WHEN TO_UINT(acc_cnt)<=g_nof_acc_per_input-1 ELSE + nxt_corr_adder_snk_in_2arr_2(i)(1).re(c_acc_data_w-1 DOWNTO 0) <= (OTHERS=>'0') WHEN TO_UINT(acc_cnt)<=g_nof_channels-1 ELSE common_shiftram_src_out_arr(i).data(2*c_acc_data_w-1 DOWNTO c_acc_data_w); - nxt_corr_adder_snk_in_2arr_2(i)(1).im(c_acc_data_w-1 DOWNTO 0) <= (OTHERS=>'0') WHEN TO_UINT(acc_cnt)<=g_nof_acc_per_input-1 ELSE + nxt_corr_adder_snk_in_2arr_2(i)(1).im(c_acc_data_w-1 DOWNTO 0) <= (OTHERS=>'0') WHEN TO_UINT(acc_cnt)<=g_nof_channels-1 ELSE common_shiftram_src_out_arr(i).data( c_acc_data_w-1 DOWNTO 0); END GENERATE; @@ -132,7 +132,7 @@ BEGIN u_common_shiftram : ENTITY common_lib.common_shiftram GENERIC MAP ( g_data_w => 2*c_acc_data_w, - g_nof_words => pow2(ceil_log2(g_nof_acc_per_input)), + g_nof_words => pow2(ceil_log2(g_nof_channels)), g_output_invalid_during_shift_incr => TRUE, g_fixed_shift => TRUE ) @@ -151,8 +151,8 @@ BEGIN END GENERATE; ----------------------------------------------------------------------------- - -- Output g_nof_words_to_acc per stream once per integration period - -- . The first g_nof_acc_per_input words are output. At the same time, the + -- Output g_integration_period per stream once per integration period + -- . The first g_nof_channels words are output. At the same time, the -- accumulators are reset (zeros) at the adder inputs. -- . Make sure the shiftram output is valid too so we don't output a block -- of zeros initially. @@ -161,9 +161,9 @@ BEGIN nxt_src_out_arr(i).re(c_acc_data_w-1 DOWNTO 0) <= common_shiftram_src_out_arr(i).data(2*c_acc_data_w-1 DOWNTO c_acc_data_w); nxt_src_out_arr(i).im(c_acc_data_w-1 DOWNTO 0) <= common_shiftram_src_out_arr(i).data( c_acc_data_w-1 DOWNTO 0); - nxt_src_out_arr(i).valid <= '1' WHEN TO_UINT(acc_cnt)<g_nof_acc_per_input AND common_shiftram_src_out_arr(0).valid='1' ELSE '0'; - nxt_src_out_arr(i).sop <= '1' WHEN TO_UINT(acc_cnt)=0 AND common_shiftram_src_out_arr(0).valid='1' ELSE '0'; - nxt_src_out_arr(i).eop <= '1' WHEN TO_UINT(acc_cnt)=g_nof_acc_per_input-1 AND common_shiftram_src_out_arr(0).valid='1' ELSE '0'; + nxt_src_out_arr(i).valid <= '1' WHEN TO_UINT(acc_cnt)<g_nof_channels AND common_shiftram_src_out_arr(0).valid='1' ELSE '0'; + nxt_src_out_arr(i).sop <= '1' WHEN TO_UINT(acc_cnt)=0 AND common_shiftram_src_out_arr(0).valid='1' ELSE '0'; + nxt_src_out_arr(i).eop <= '1' WHEN TO_UINT(acc_cnt)=g_nof_channels-1 AND common_shiftram_src_out_arr(0).valid='1' ELSE '0'; END GENERATE; ----------------------------------------------------------------------------- diff --git a/libraries/dsp/correlator/src/vhdl/correlator.vhd b/libraries/dsp/correlator/src/vhdl/correlator.vhd index 94f11bafa6bdddd5bb1f7c826488acfaf0a4e7c7..715e115a74f42afd3ded8c0401c2f43709e2a5f3 100644 --- a/libraries/dsp/correlator/src/vhdl/correlator.vhd +++ b/libraries/dsp/correlator/src/vhdl/correlator.vhd @@ -32,12 +32,12 @@ USE dp_lib.dp_stream_pkg.ALL; ENTITY correlator IS GENERIC ( - g_nof_inputs : NATURAL; - g_nof_mults : NATURAL; - g_data_w : NATURAL := 16; - g_conjugate : BOOLEAN := TRUE; - g_nof_acc_per_input : NATURAL := 64; -- aka channels - g_nof_words_to_acc : NATURAL := 55 -- Internally forced to g_nof_mults as a minimum unless zero + g_nof_inputs : NATURAL; + g_nof_pre_mult_folds : NATURAL := 0; -- Number of pre-multiplier stage folds. + g_data_w : NATURAL := 16; -- Complex data width + g_conjugate : BOOLEAN := TRUE; + g_nof_channels : NATURAL := 64; -- Number of (serial) channels per (parallel) input + g_integration_period : NATURAL := 0 -- Expressed as the number of samples per channel to accumulate ); PORT ( rst : IN STD_LOGIC; @@ -51,21 +51,34 @@ END correlator; ARCHITECTURE str OF correlator IS + CONSTANT c_nof_visibilities : NATURAL := (g_nof_inputs*(g_nof_inputs+1))/2; + + ----------------------------------------------------------------------------- + -- The array of multiplier input streams can be folded, e.g.: + -- . c_nof_visibilities=10, g_nof_pre_mult_folds=0 -> c_nof_mults=10 + -- . c_nof_visibilities=10, g_nof_pre_mult_folds=1 -> c_nof_mults= 5 + -- . c_nof_visibilities=10, g_nof_pre_mult_folds=2 -> c_nof_mults= 3 + -- . c_nof_visibilities=10, g_nof_pre_mult_folds=3 -> c_nof_mults= 2 + -- . c_nof_visibilities=10, g_nof_pre_mult_folds=4 -> c_nof_mults= 1 + -- . c_nof_visibilities=10, g_nof_pre_mult_folds<0 -> c_nof_mults= 1 + ----------------------------------------------------------------------------- + CONSTANT c_nof_mults : NATURAL := sel_a_b(g_nof_pre_mult_folds>=0, ceil_div(c_nof_visibilities, ceil_pow2(g_nof_pre_mult_folds)), 1); + -- We can multiplex the accumulator outputs onto one stream as long as the integration period is -- equal to or larger than the number of accumulator outputs. - CONSTANT c_nof_words_to_acc : NATURAL := largest(g_nof_words_to_acc, g_nof_mults); + CONSTANT c_integration_period : NATURAL := largest(g_integration_period, c_nof_mults); - CONSTANT c_acc_data_w : NATURAL := ceil_log2(c_nof_words_to_acc*(pow2(g_data_w)-1)); + CONSTANT c_acc_data_w : NATURAL := ceil_log2(c_integration_period*(pow2(g_data_w)-1)); SIGNAL corr_permutator_src_out_2arr_2 : t_dp_sosi_2arr_2(g_nof_inputs*(g_nof_inputs+1)/2-1 DOWNTO 0); -- Array of pairs SIGNAL corr_folder_snk_in_2arr_2 : t_dp_sosi_2arr_2(g_nof_inputs*(g_nof_inputs+1)/2-1 DOWNTO 0); -- Array of pairs, not folded yet SIGNAL corr_folder_src_out_2arr_2 : t_dp_sosi_2arr_2(g_nof_inputs*(g_nof_inputs+1)/2-1 DOWNTO 0); -- Array of pairs, not folded yet - SIGNAL corr_multiplier_src_out_arr : t_dp_sosi_arr(g_nof_mults-1 DOWNTO 0); - SIGNAL corr_accumulator_snk_in_arr : t_dp_sosi_arr(g_nof_mults-1 DOWNTO 0); - SIGNAL corr_accumulator_src_out_arr : t_dp_sosi_arr(g_nof_mults-1 DOWNTO 0); - SIGNAL dp_fifo_sc_snk_in_arr : t_dp_sosi_arr(g_nof_mults-1 DOWNTO 0); - SIGNAL dp_fifo_sc_src_out_arr : t_dp_sosi_arr(g_nof_mults-1 DOWNTO 0); - SIGNAL dp_fifo_sc_src_in_arr : t_dp_siso_arr(g_nof_mults-1 DOWNTO 0); + SIGNAL corr_multiplier_src_out_arr : t_dp_sosi_arr(c_nof_mults-1 DOWNTO 0); + SIGNAL corr_accumulator_snk_in_arr : t_dp_sosi_arr(c_nof_mults-1 DOWNTO 0); + SIGNAL corr_accumulator_src_out_arr : t_dp_sosi_arr(c_nof_mults-1 DOWNTO 0); + SIGNAL dp_fifo_sc_snk_in_arr : t_dp_sosi_arr(c_nof_mults-1 DOWNTO 0); + SIGNAL dp_fifo_sc_src_out_arr : t_dp_sosi_arr(c_nof_mults-1 DOWNTO 0); + SIGNAL dp_fifo_sc_src_in_arr : t_dp_siso_arr(c_nof_mults-1 DOWNTO 0); SIGNAL corr_folder_src_out_arr : t_dp_sosi_arr(1-1 DOWNTO 0); BEGIN @@ -88,7 +101,7 @@ BEGIN ----------------------------------------------------------------------------- -- Permutator -> folder pipeline ----------------------------------------------------------------------------- - gen_dp_pipeline_corr_permutator_src_out_2arr2 : FOR i IN 0 TO g_nof_mults-1 GENERATE + gen_dp_pipeline_corr_permutator_src_out_2arr2 : FOR i IN 0 TO c_nof_mults-1 GENERATE gen_dp_pipeline : FOR j IN 0 TO 2-1 GENERATE u_dp_pipeline : ENTITY dp_lib.dp_pipeline GENERIC MAP ( @@ -105,7 +118,7 @@ BEGIN END GENERATE; ----------------------------------------------------------------------------- - -- Fold the streams if g_nof_mults < g_nof_inputs + -- Fold the streams if c_nof_mults < g_nof_inputs -- . Folder not implemented yet; section bypassed. ----------------------------------------------------------------------------- corr_folder_src_out_2arr_2 <= corr_folder_snk_in_2arr_2; @@ -115,7 +128,7 @@ BEGIN ----------------------------------------------------------------------------- u_corr_multiplier : ENTITY work.corr_multiplier GENERIC MAP ( - g_nof_inputs => g_nof_mults, + g_nof_inputs => c_nof_mults, g_data_w => g_data_w, g_conjugate => g_conjugate ) @@ -130,7 +143,7 @@ BEGIN ----------------------------------------------------------------------------- -- Multiplier -> Accumulator pipeline ----------------------------------------------------------------------------- - gen_dp_pipeline_corr_multiplier_src_out_arr : FOR i IN 0 TO g_nof_mults-1 GENERATE + gen_dp_pipeline_corr_multiplier_src_out_arr : FOR i IN 0 TO c_nof_mults-1 GENERATE u_dp_pipeline : ENTITY dp_lib.dp_pipeline GENERIC MAP ( g_pipeline => 0 @@ -149,10 +162,10 @@ BEGIN ----------------------------------------------------------------------------- u_corr_accumulator : ENTITY work.corr_accumulator GENERIC MAP ( - g_nof_inputs => g_nof_mults, - g_nof_acc_per_input => g_nof_acc_per_input, - g_nof_words_to_acc => c_nof_words_to_acc, - g_data_w => g_data_w + g_nof_inputs => c_nof_mults, + g_nof_channels => g_nof_channels, + g_integration_period => c_integration_period, + g_data_w => g_data_w ) PORT MAP ( clk => clk, @@ -165,7 +178,7 @@ BEGIN ----------------------------------------------------------------------------- -- Accumulator -> FIFO pipeline ----------------------------------------------------------------------------- - gen_dp_pipeline_corr_accumulator_src_out_arr : FOR i IN 0 TO g_nof_mults-1 GENERATE + gen_dp_pipeline_corr_accumulator_src_out_arr : FOR i IN 0 TO c_nof_mults-1 GENERATE u_dp_pipeline : ENTITY dp_lib.dp_pipeline GENERIC MAP ( g_pipeline => 0 @@ -185,7 +198,7 @@ BEGIN -- to buffer the visibilities so we can take our time to multiplex them -- onto one stream. ------------------------------------------------------------------------------ - gen_dp_fifo_sc : FOR i IN 0 TO g_nof_mults-1 GENERATE + gen_dp_fifo_sc : FOR i IN 0 TO c_nof_mults-1 GENERATE u_dp_fifo_sc : ENTITY dp_lib.dp_fifo_sc GENERIC MAP ( g_data_w => 2*c_acc_data_w, @@ -232,11 +245,11 @@ BEGIN -- 14) | [0] . [1] -- 15) |<---g_init_valid_delay(15)-->[0] [1] ------------------------------------------------------------------------------ - gen_dp_src_out_timer : FOR i IN 0 TO g_nof_mults-1 GENERATE + gen_dp_src_out_timer : FOR i IN 0 TO c_nof_mults-1 GENERATE u_dp_src_out_timer : ENTITY dp_lib.dp_src_out_timer GENERIC MAP ( g_init_valid_delay => i, --relative to dp_fifo_sc_src_out_arr(i).valid - g_nof_invalid_per_valid => g_nof_mults + g_nof_invalid_per_valid => c_nof_mults ) PORT MAP ( rst => rst, @@ -254,7 +267,7 @@ BEGIN ------------------------------------------------------------------------------ u_corr_folder : ENTITY work.corr_folder GENERIC MAP ( - g_nof_inputs => c_nof_words_to_acc, + g_nof_inputs => c_integration_period, g_nof_folds => -1 ) PORT MAP ( @@ -268,12 +281,12 @@ BEGIN ----------------------------------------------------------------------------- -- Add proper SOP and EOP to mux output - -- . Output one block of g_nof_mults for each channel + -- . Output one block of c_nof_mults for each channel ----------------------------------------------------------------------------- dp_block_gen: ENTITY dp_lib.dp_block_gen GENERIC MAP ( g_use_src_in => FALSE, - g_nof_data => g_nof_mults, + g_nof_data => c_nof_mults, g_nof_blk_per_sync => 10 -- Randomly chosen sync interval ) PORT MAP ( diff --git a/libraries/dsp/correlator/tb/vhdl/tb_correlator.vhd b/libraries/dsp/correlator/tb/vhdl/tb_correlator.vhd index a65e002c13d59fd253c50698eea8dde2679f6c13..adce654f818c73dd93b2ad1b8974d5e5805f894a 100644 --- a/libraries/dsp/correlator/tb/vhdl/tb_correlator.vhd +++ b/libraries/dsp/correlator/tb/vhdl/tb_correlator.vhd @@ -36,7 +36,6 @@ END tb_correlator; ARCHITECTURE tb OF tb_correlator IS CONSTANT c_nof_inputs : NATURAL := 10; - CONSTANT c_nof_mults : NATURAL := (c_nof_inputs*(c_nof_inputs+1))/2; CONSTANT c_nof_channels : NATURAL := 64; CONSTANT c_dp_clk_period : TIME := 10 ns; @@ -131,9 +130,7 @@ BEGIN u_correlator : ENTITY work.correlator GENERIC MAP ( g_nof_inputs => c_nof_inputs, - g_nof_mults => c_nof_mults, - g_data_w => c_complex_data_w, - g_nof_words_to_acc => c_nof_mults + g_data_w => c_complex_data_w ) PORT MAP ( clk => dp_clk,