diff --git a/libraries/dsp/si/hdllib.cfg b/libraries/dsp/si/hdllib.cfg index 218fb87f7a66bf69a85dd6ab648f882d3ccb7dbc..b9c5b293a1aec62f6d333dd08119ea202fc3ca15 100755 --- a/libraries/dsp/si/hdllib.cfg +++ b/libraries/dsp/si/hdllib.cfg @@ -11,7 +11,7 @@ test_bench_files = tb/vhdl/tb_si.vhd regression_test_vhdl = - #tb/vhdl/tb_si.vhd -- tb is not self checking yet + tb/vhdl/tb_si.vhd [modelsim_project_file] diff --git a/libraries/dsp/si/src/vhdl/si.vhd b/libraries/dsp/si/src/vhdl/si.vhd index f4230bfecee6688021854090a4185d7adb30aade..14d61189ce30513a56070e74e5c0680a2387f789 100755 --- a/libraries/dsp/si/src/vhdl/si.vhd +++ b/libraries/dsp/si/src/vhdl/si.vhd @@ -29,26 +29,22 @@ -- where n = 0 is the first sample in the FFT block. For more information -- see section 4.19 in LOFAR_ASTRON_SDD_018_RSP_Firmware_DD.pdf. -- Remark: --- . Ported from LOFAR1 rsp +-- . Ported from LOFAR1 rsp. Then rewrote code to use t_dp_sosi. ------------------------------------------------------------------------------- -LIBRARY IEEE; +LIBRARY IEEE, common_lib, dp_lib; USE IEEE.STD_LOGIC_1164.ALL; -USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; ENTITY si IS GENERIC ( + g_pipeline : NATURAL := 1; -- 0 for wires, 1 for output pipeline g_dat_w : NATURAL := 18 ); PORT ( - in_dat : IN STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); - in_val : IN STD_LOGIC; - in_sop : IN STD_LOGIC; - in_sync : IN STD_LOGIC; - out_dat : OUT STD_LOGIC_VECTOR(g_dat_w-1 DOWNTO 0); - out_val : OUT STD_LOGIC; - out_sop : OUT STD_LOGIC; - out_sync : OUT STD_LOGIC; + in_sosi : IN t_dp_sosi; + out_sosi : OUT t_dp_sosi; si_en : IN STD_LOGIC; clk : IN STD_LOGIC; rst : IN STD_LOGIC @@ -57,54 +53,56 @@ END si; ARCHITECTURE rtl OF si IS - CONSTANT c_dat_max : INTEGER := 2**(g_dat_w-1)-1; - CONSTANT c_dat_min : INTEGER := -2**(g_dat_w-1); - - SIGNAL nxt_out_dat : STD_LOGIC_VECTOR(out_dat'RANGE); SIGNAL plus : STD_LOGIC; - SIGNAL nxt_plus : STD_LOGIC; + SIGNAL plus_reg : STD_LOGIC; SIGNAL si_plus : STD_LOGIC; + SIGNAL si_sosi : t_dp_sosi; BEGIN - reg_si : PROCESS(rst, clk) + p_reg : PROCESS(rst, clk) BEGIN IF rst='1' THEN - out_val <= '0'; - out_sop <= '0'; - out_sync <= '0'; - plus <= '1'; + plus_reg <= '1'; ELSIF rising_edge(clk) THEN - out_dat <= nxt_out_dat; - out_val <= in_val; - out_sop <= in_sop; - out_sync <= in_sync; - plus <= nxt_plus; + plus_reg <= plus; END IF; END PROCESS; - - si_control : PROCESS (plus, in_sop, in_val) + + -- Control -1**n to start with +1 at sop and then toggle at every valid + p_si_control : PROCESS (plus_reg, in_sosi) BEGIN - nxt_plus <= plus; - IF in_sop = '1' THEN - nxt_plus <= '1'; - ELSIF in_val = '1' THEN - nxt_plus <= NOT plus; + plus <= plus_reg; + IF in_sosi.sop = '1' THEN + plus <= '1'; + ELSIF in_sosi.valid = '1' THEN + plus <= NOT plus_reg; END IF; END PROCESS; + -- Use SI when enabled, else pass on input si_plus <= plus WHEN si_en = '1' ELSE '1'; - si_data : PROCESS (si_plus, in_dat) + si_data : PROCESS (si_plus, in_sosi) BEGIN - nxt_out_dat <= in_dat; + si_sosi <= in_sosi; IF si_plus = '0' THEN - nxt_out_dat <= STD_LOGIC_VECTOR(-SIGNED(in_dat)); - -- Clip -c_dat_min to c_dat_max instead of wrapping to c_dat_min - IF SIGNED(in_dat) = c_dat_min THEN - nxt_out_dat <= STD_LOGIC_VECTOR(TO_SIGNED(c_dat_max, g_dat_w)); - END IF; + si_sosi.data <= NEGATE_SVEC(in_sosi.data, g_dat_w); + si_sosi.re <= NEGATE_SVEC(in_sosi.re, g_dat_w); + si_sosi.im <= NEGATE_SVEC(in_sosi.im, g_dat_w); END IF; END PROCESS; + + -- Output + u_pipeline : ENTITY dp_lib.dp_pipeline + GENERIC MAP ( + g_pipeline => g_pipeline + ) + PORT MAP ( + rst => rst, + clk => clk, + snk_in => si_sosi, + src_out => out_sosi + ); END rtl; diff --git a/libraries/dsp/si/tb/vhdl/tb_si.vhd b/libraries/dsp/si/tb/vhdl/tb_si.vhd index 1a455af2cadb8be83d011922424a7a7ebdc667e9..462b6b6a8a1b9a671e1b3ed8852ea70431f384d8 100755 --- a/libraries/dsp/si/tb/vhdl/tb_si.vhd +++ b/libraries/dsp/si/tb/vhdl/tb_si.vhd @@ -25,12 +25,13 @@ -- Description: -- Test bench for si.vhd. -- Remark: --- . Ported from LOFAR1 rsp --- . The tb is self-stopping, but not self checking. +-- . Ported from LOFAR1 rsp. Made the tb self-stopping and self-checking. -LIBRARY IEEE, common_lib; +LIBRARY IEEE, common_lib, dp_lib; USE IEEE.STD_LOGIC_1164.ALL; USE common_lib.common_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; ENTITY tb_si IS END tb_si; @@ -40,10 +41,14 @@ ARCHITECTURE tb OF tb_si IS CONSTANT c_clk_period : TIME := 10 ns; CONSTANT c_dat_w : NATURAL := 5; - CONSTANT c_block_size : NATURAL := 19; + CONSTANT c_max : INTEGER := 2**(c_dat_w-1)-1; + CONSTANT c_min : INTEGER := -2**(c_dat_w-1); + CONSTANT c_block_size : NATURAL := 9; - SIGNAL in_dat : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); - SIGNAL nxt_in_dat : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0); + SIGNAL in_sosi : t_dp_sosi; + SIGNAL out_sosi : t_dp_sosi; + + SIGNAL in_dat : STD_LOGIC_VECTOR(c_dat_w-1 DOWNTO 0) := (OTHERS => '0'); SIGNAL in_val : STD_LOGIC; SIGNAL in_sop : STD_LOGIC; SIGNAL in_sync : STD_LOGIC; @@ -57,7 +62,8 @@ ARCHITECTURE tb OF tb_si IS SIGNAL tb_end : STD_LOGIC := '0'; SIGNAL toggle : STD_LOGIC; - SIGNAL nxt_toggle : STD_LOGIC; + SIGNAL clip_even : STD_LOGIC; + SIGNAL clip_odd : STD_LOGIC; BEGIN @@ -65,45 +71,48 @@ BEGIN clk <= NOT(clk) OR tb_end AFTER c_clk_period/2; u_si : ENTITY work.si - GENERIC MAP( + GENERIC MAP ( + g_pipeline => 0, g_dat_w => c_dat_w ) PORT MAP( - in_dat => in_dat, - in_val => in_val, - in_sop => in_sop, - in_sync => in_sync, - out_dat => out_dat, - out_val => out_val, - out_sop => out_sop, - out_sync => out_sync, + in_sosi => in_sosi, + out_sosi => out_sosi, si_en => si_en, clk => clk, rst => rst ); - reg_stimuli : PROCESS(rst, clk) + -- wires + in_sosi.sync <= in_sync; + in_sosi.sop <= in_sop; + in_sosi.valid <= in_val; + in_sosi.data <= RESIZE_DP_SDATA(in_dat); + in_sosi.re <= TO_DP_DSP_DATA(0); + in_sosi.im <= TO_DP_DSP_DATA(0); + + out_sync <= out_sosi.sync; + out_sop <= out_sosi.sop; + out_val <= out_sosi.valid; + out_dat <= out_sosi.data(c_dat_w-1 DOWNTO 0); + + -- Create in_dat with equal value per pair + p_clk : PROCESS(rst, clk) BEGIN IF rst='1' THEN in_dat <= (OTHERS => '0'); toggle <= '0'; ELSIF rising_edge(clk) THEN - in_dat <= nxt_in_dat; - toggle <= nxt_toggle; + IF in_val='1' THEN + IF toggle='1' THEN + in_dat <= INCR_UVEC(in_dat, 1); + END IF; + toggle <= NOT toggle; + END IF; END IF; END PROCESS; - nxt_toggle <= NOT toggle; - - data_counter : PROCESS (toggle, in_dat) - BEGIN - nxt_in_dat <= in_dat; - IF toggle = '1' THEN - nxt_in_dat <= INCR_UVEC(in_dat, 1); - END IF; - END PROCESS; - - PROCESS + p_stimuli : PROCESS BEGIN si_en <= '1'; in_sop <= '0'; @@ -112,42 +121,63 @@ BEGIN WAIT FOR 10*c_clk_period; -- pulse in_sync, to check that it is passed on - -- sop followed by valid data + -- pulse sop and continue with valid data in_sync <= '1'; in_sop <= '1'; - in_val <= '0'; + in_val <= '1'; WAIT FOR c_clk_period; in_sync <= '0'; in_sop <= '0'; - in_val <= '1'; WAIT FOR c_block_size*c_clk_period; - -- insert a single valid low cycle + -- insert some valid low cycles in_val <= '0'; - WAIT FOR c_clk_period; - in_val <= '1'; - WAIT FOR c_block_size*c_clk_period; - - -- insert an out of phase resync sop cycle - in_sop <= '1'; + WAIT FOR 3*c_clk_period; in_val <= '1'; - WAIT FOR c_clk_period; - in_sop <= '0'; - in_val <= '1'; - WAIT FOR c_block_size*c_clk_period; - - -- insert an in phase resync sop cycle - in_sop <= '1'; - in_val <= '1'; - WAIT FOR c_clk_period; - in_sop <= '0'; - in_val <= '1'; - WAIT FOR c_block_size*c_clk_period; + + -- some more blocks + FOR I IN 0 TO 15 LOOP + in_sop <= '1'; + WAIT FOR c_clk_period; + in_sop <= '0'; + WAIT FOR c_block_size*c_clk_period; + END LOOP; tb_end <= '1'; WAIT; - END PROCESS; + + p_verify : PROCESS + VARIABLE v_even : INTEGER; + VARIABLE v_odd : INTEGER; + VARIABLE v_clip_even : STD_LOGIC; + VARIABLE v_clip_odd : STD_LOGIC; + BEGIN + -- verify per pair + WAIT FOR c_clk_period; + proc_common_wait_until_high(clk, out_val); + v_even := TO_SINT(out_dat); + WAIT FOR c_clk_period; + proc_common_wait_until_high(clk, out_val); + v_odd := TO_SINT(out_dat); + -- identify clip wrap of -c_min to +c_max + IF v_even = c_max AND v_odd = c_min THEN v_clip_even := '1'; ELSE v_clip_even := '0'; END IF; + IF v_even = c_min AND v_odd = c_max THEN v_clip_odd := '1'; ELSE v_clip_odd := '0'; END IF; + clip_even <= v_clip_even; -- show in wave window (only cycle late) + clip_odd <= v_clip_odd; -- show in wave window (only cycle late) + -- compare pair + IF tb_end = '0' THEN + IF v_even /= -v_odd THEN + IF NOT (v_clip_even = '1') THEN + IF NOT (v_clip_odd = '1') THEN + REPORT "Wrong negate value" SEVERITY ERROR; + END IF; + END IF; + END IF; + ELSE + WAIT; + END IF; + END PROCESS; END tb;