diff --git a/libraries/base/diag/hdllib.cfg b/libraries/base/diag/hdllib.cfg index 6976c4da96ea3f03cd2624952b9bc8b407d7e8ea..18df3bdaa63f7f67560e1975ec7a0aeeb06c38e7 100644 --- a/libraries/base/diag/hdllib.cfg +++ b/libraries/base/diag/hdllib.cfg @@ -42,3 +42,7 @@ test_bench_files = $UNB/Firmware/modules/Lofar/diag/tb/vhdl/tb_mms_diag_seq.vhd $UNB/Firmware/modules/Lofar/diag/tb/vhdl/tb_mms_diag_block_gen.vhd tb/vhdl/tb_diag_regression.vhd + +modelsim_copy_files = + $UNB/Firmware/modules/Lofar/diag/src/data/bf_in_data.dat . + $UNB/Firmware/modules/Lofar/diag/src/data/diag_block.hex . \ No newline at end of file diff --git a/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd b/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd new file mode 100644 index 0000000000000000000000000000000000000000..9c7d3d5353ea66b718f56d90ab8397a5be77892b --- /dev/null +++ b/libraries/base/diag/tb/vhdl/tb_diag_block_gen.vhd @@ -0,0 +1,212 @@ +-------------------------------------------------------------------------------- +-- +-- Copyright (C) 2011 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +-------------------------------------------------------------------------------- + +-- Purpose: test bench for diag_block_gen +-- The tb is self-stopping and self-checking. +-- Usage: +-- > as 5 +-- > run -all + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; +USE work.diag_pkg.ALL; + +ENTITY tb_diag_block_gen IS + GENERIC ( + g_buf_adr_w : NATURAL := 7; -- Waveform buffer address width (requires corresponding c_buf_file) + g_buf_dat_w : NATURAL := 32 -- Waveform buffer stored data width (requires corresponding c_buf_file) + ); +END tb_diag_block_gen; + + +ARCHITECTURE tb OF tb_diag_block_gen IS + + CONSTANT clk_period : TIME := 10 ns; + + -- Default settings + CONSTANT c_buf : t_c_mem := (latency => 1, + adr_w => g_buf_adr_w, + dat_w => g_buf_dat_w, + nof_dat => 2**g_buf_adr_w, -- = 2**adr_w + init_sl => '0'); + + CONSTANT c_buf_file : STRING := sel_a_b(c_buf.adr_w=7 AND c_buf.dat_w=32, "diag_block.hex", "UNUSED"); + + CONSTANT c_cntr_init : INTEGER := 0; + CONSTANT c_cntr_incr : INTEGER := 1; + CONSTANT c_cntr_arr : t_slv_32_arr(c_buf.nof_dat-1 DOWNTO 0) := flip(array_init(c_cntr_init, c_buf.nof_dat, c_cntr_incr)); + + CONSTANT c_bg_ctrl : t_diag_block_gen := ( '0', + '0', + TO_UVEC(96, c_diag_bg_samples_per_packet_w), + TO_UVEC(10, c_diag_bg_blocks_per_sync_w), + TO_UVEC(32, c_diag_bg_gapsize_w), + TO_UVEC( 0, c_diag_bg_mem_low_adrs_w), + TO_UVEC(95, c_diag_bg_mem_high_adrs_w), + TO_UVEC(42, c_diag_bg_bsn_init_w)); + + CONSTANT c_alternative_samples_per_packet : NATURAL := c_buf.nof_dat; + CONSTANT c_alternative_mem_high_adrs : NATURAL := 64; + CONSTANT c_alternative_data_gap : NATURAL := TO_UINT(c_bg_ctrl.mem_high_adrs)-c_alternative_mem_high_adrs; + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '1'; + + SIGNAL verify_en : STD_LOGIC := '0'; + + SIGNAL mm_buf_arr : t_slv_32_arr(c_buf.nof_dat-1 DOWNTO 0); + SIGNAL mm_buf_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL mm_buf_miso : t_mem_miso; + + SIGNAL bg_buf_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL bg_buf_miso : t_mem_miso; + + SIGNAL bg_ctrl : t_diag_block_gen; + + SIGNAL out_sosi : t_dp_sosi; + SIGNAL prev_out_sosi : t_dp_sosi; + SIGNAL hold_sop : STD_LOGIC; + SIGNAL exp_size : NATURAL; + SIGNAL cnt_size : NATURAL; + +BEGIN + + rst <= '1', '0' AFTER clk_period/10; + clk <= NOT clk OR tb_end AFTER clk_period/2; + + p_stimuli : PROCESS + BEGIN + bg_ctrl <= c_bg_ctrl; + proc_common_wait_until_low(clk, rst); -- Wait until reset has finished + proc_common_wait_some_cycles(clk, 10); + + -- Write waveform buffer + proc_mem_write_ram(c_cntr_arr, clk, mm_buf_mosi); + + -- Readback waveform buffer + proc_mem_read_ram(clk, mm_buf_mosi, mm_buf_miso, mm_buf_arr); + ASSERT c_cntr_arr=mm_buf_arr REPORT "Error: Wrong BG buffer readback" SEVERITY FAILURE; + + -- Run with a gap + bg_ctrl.enable <= '1'; + proc_dp_verify_run_some_cycles(5, 1500, 0, clk, verify_en); + + -- Run without gap + bg_ctrl.enable <= '0'; + proc_common_wait_some_cycles(clk, 100); + bg_ctrl.gapsize <= TO_UVEC(0, c_diag_bg_gapsize_w); + bg_ctrl.enable <= '1'; + proc_dp_verify_run_some_cycles(5, 1500, 0, clk, verify_en); + + -- Run with non-aligned memory settings + bg_ctrl.enable <= '0'; + proc_common_wait_some_cycles(clk, 100); + bg_ctrl.gapsize <= c_bg_ctrl.gapsize; + bg_ctrl.mem_high_adrs <= TO_UVEC(c_alternative_mem_high_adrs, c_diag_bg_mem_high_adrs_w); + bg_ctrl.enable <= '1'; + proc_dp_verify_run_some_cycles(5, 1500, 0, clk, verify_en); + + -- Run and change bg_ctrl dynamically + bg_ctrl.enable <= '0'; + proc_common_wait_some_cycles(clk, 100); + bg_ctrl <= c_bg_ctrl; + bg_ctrl.mem_high_adrs <= TO_UVEC(c_alternative_mem_high_adrs, c_diag_bg_mem_high_adrs_w); + bg_ctrl.enable <= '1'; + proc_dp_verify_run_some_cycles(5, 1500, 0, clk, verify_en); + + -- . change gapsize dynamically + bg_ctrl.gapsize <= c_bg_ctrl.gapsize; + proc_dp_verify_run_some_cycles(0, 1500, 0, clk, verify_en); + + -- . change mem_high_adrs dynamically + bg_ctrl.mem_high_adrs <= c_bg_ctrl.mem_high_adrs; -- increase, because decreasing could yield an verify data error + proc_dp_verify_run_some_cycles(0, 1500, 0, clk, verify_en); + + -- . change samples_per_packet dynamically + bg_ctrl.samples_per_packet <= TO_UVEC(c_alternative_samples_per_packet, c_diag_bg_samples_per_packet_w); -- increase, because decreasing could yield an verify data error + proc_dp_verify_run_some_cycles(0, 1500, 0, clk, verify_en); + + -- End simulation + tb_end <= '1'; + WAIT; + END PROCESS; + + -- Verification + exp_size <= TO_UINT(bg_ctrl.samples_per_packet); + + proc_dp_verify_data("BSN", clk, verify_en, out_sosi.sop, out_sosi.bsn, prev_out_sosi.bsn); + proc_dp_verify_data("DATA", TO_UINT(c_bg_ctrl.mem_high_adrs), c_alternative_data_gap, clk, verify_en, out_sosi.valid, out_sosi.data, prev_out_sosi.data); + + proc_dp_verify_sop_and_eop(clk, out_sosi.valid, out_sosi.sop, out_sosi.eop, hold_sop); + proc_dp_verify_block_size(exp_size, clk, out_sosi.valid, out_sosi.sop, out_sosi.eop, cnt_size); + + -- Waveform buffer + u_buf : ENTITY common_lib.common_ram_crw_crw + GENERIC MAP ( + g_ram => c_buf, + g_init_file => c_buf_file + ) + PORT MAP ( + rst_a => '0', + rst_b => '0', + clk_a => clk, + clk_b => clk, + wr_en_a => mm_buf_mosi.wr, + wr_en_b => '0', + wr_dat_a => mm_buf_mosi.wrdata(c_buf.dat_w-1 DOWNTO 0), + wr_dat_b => (OTHERS=>'0'), + adr_a => mm_buf_mosi.address(c_buf.adr_w-1 DOWNTO 0), + adr_b => bg_buf_mosi.address(c_buf.adr_w-1 DOWNTO 0), + rd_en_a => mm_buf_mosi.rd, + rd_en_b => bg_buf_mosi.rd, + rd_dat_a => mm_buf_miso.rddata(c_buf.dat_w-1 DOWNTO 0), + rd_dat_b => bg_buf_miso.rddata(c_buf.dat_w-1 DOWNTO 0), + rd_val_a => mm_buf_miso.rdval, + rd_val_b => bg_buf_miso.rdval + ); + + u_dut : ENTITY work.diag_block_gen + GENERIC MAP( + g_buf_dat_w => c_buf.dat_w, + g_buf_addr_w => c_buf.adr_w + ) + PORT MAP ( + rst => rst, + clk => clk, + buf_addr => bg_buf_mosi.address(c_buf.adr_w-1 DOWNTO 0), + buf_rden => bg_buf_mosi.rd, + buf_rddat => bg_buf_miso.rddata(c_buf.dat_w-1 DOWNTO 0), + buf_rdval => bg_buf_miso.rdval, + ctrl => bg_ctrl, + out_sosi => out_sosi + ); + +END tb; + diff --git a/libraries/base/diag/tb/vhdl/tb_mms_diag_block_gen.vhd b/libraries/base/diag/tb/vhdl/tb_mms_diag_block_gen.vhd new file mode 100644 index 0000000000000000000000000000000000000000..4dacecd9470f95a20c49787eece3df9b172b9420 --- /dev/null +++ b/libraries/base/diag/tb/vhdl/tb_mms_diag_block_gen.vhd @@ -0,0 +1,221 @@ +----------------------------------------------------------------------------- +-- +-- Copyright (C) 2010 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- This program is free software: you can redistribute it and/or modify +-- it under the terms of the GNU General Public License as published by +-- the Free Software Foundation, either version 3 of the License, or +-- (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-- GNU General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program. If not, see <http://www.gnu.org/licenses/>. +-- +------------------------------------------------------------------------------- + +-- Purpose: Test bench for mms_diag_block_gen +-- The tb is self-stopping and self-checking. +-- Usage: +-- > do wave_mms_diag_block_gen.do +-- > run -all +-- Observe tb_state and check the out_sosi fields if data is OK. +-- Try both c_gap_size = 0 and 160 + +LIBRARY IEEE, common_lib, dp_lib; +USE IEEE.std_logic_1164.ALL; +USE IEEE.numeric_std.ALL; +USE std.textio.all; +USE common_lib.common_pkg.ALL; +USE common_lib.common_mem_pkg.ALL; +USE common_lib.tb_common_pkg.ALL; +USE common_lib.tb_common_mem_pkg.ALL; +USE dp_lib.dp_stream_pkg.ALL; +USE dp_lib.tb_dp_pkg.ALL; +USE work.diag_pkg.ALL; + +ENTITY tb_mms_diag_block_gen IS + GENERIC ( + g_nof_inputs : POSITIVE := 64; + g_nof_subbands : POSITIVE := 24; + g_nof_streams : NATURAL := 16; + g_buf_dat_w : NATURAL := 32; + g_buf_addr_w : NATURAL := 7; + g_file_name_prefix : STRING := "bf_in_data"; + g_sim : BOOLEAN := TRUE + ); +END tb_mms_diag_block_gen; + +ARCHITECTURE tb OF tb_mms_diag_block_gen IS + + CONSTANT clk_period : TIME := 10 ns; + + CONSTANT c_block_size : NATURAL := 96; + --CONSTANT c_gap_size : NATURAL := 0; + CONSTANT c_gap_size : NATURAL := 160; + CONSTANT c_period_size : NATURAL := c_block_size + c_gap_size; + + --CONSTANT c_blk_sync : BOOLEAN := FALSE; + CONSTANT c_blk_sync : BOOLEAN := TRUE; + + CONSTANT c_pend_period : NATURAL := 200; + CONSTANT c_on_period : NATURAL := 1500; + CONSTANT c_off_period : NATURAL := 550; + CONSTANT c_end_period : NATURAL := 5000; + + CONSTANT c_bsn_max : UNSIGNED(c_dp_stream_bsn_w-1 DOWNTO 0) := (OTHERS=>'1'); + CONSTANT c_bsn_gap : UNSIGNED(c_dp_stream_bsn_w-1 DOWNTO 0) := TO_UNSIGNED(ceil_div(c_off_period, c_period_size), c_dp_stream_bsn_w); -- depends on c_off_period + + TYPE t_tb_state IS (s_init, s_enable_sync, s_enable, s_disable, s_xoff, s_xon); + + SIGNAL tb_end : STD_LOGIC := '0'; + SIGNAL rst : STD_LOGIC; + SIGNAL clk : STD_LOGIC := '1'; + SIGNAL en_sync : STD_LOGIC; + SIGNAL tb_state : t_tb_state; + + SIGNAL ram_bg_data_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL ram_bg_data_miso : t_mem_miso := c_mem_miso_rst; + SIGNAL reg_bg_ctrl_mosi : t_mem_mosi := c_mem_mosi_rst; + SIGNAL reg_bg_ctrl_miso : t_mem_miso := c_mem_miso_rst; + + SIGNAL out_siso_arr : t_dp_siso_arr(g_nof_streams-1 DOWNTO 0) := (OTHERS=>c_dp_siso_rdy); + SIGNAL out_sosi_arr : t_dp_sosi_arr(g_nof_streams-1 DOWNTO 0); + + SIGNAL verify_en : STD_LOGIC := '1'; + SIGNAL out_sosi : t_dp_sosi; + SIGNAL prev_out_sosi : t_dp_sosi; + +BEGIN + + clk <= NOT clk OR tb_end AFTER clk_period/2; + rst <= '1', '0' AFTER clk_period*5; + + p_write_bg_ctrl : PROCESS + BEGIN + en_sync <= '0'; + out_siso_arr <= (OTHERS=>c_dp_siso_rdy); -- Flow control XON + + -- BG init + tb_state <= s_init; + proc_common_wait_until_low(clk, rst); -- Wait until reset has finished + proc_common_wait_some_cycles(clk, 10); -- Wait an additional amount of cycles + proc_mem_mm_bus_wr(1, c_block_size, clk, reg_bg_ctrl_mosi); -- Set the nof samples per block + proc_mem_mm_bus_wr(2, 10, clk, reg_bg_ctrl_mosi); -- Set the nof blocks per sync + proc_mem_mm_bus_wr(3, c_gap_size, clk, reg_bg_ctrl_mosi); -- Set the gapsize + proc_mem_mm_bus_wr(4, 0, clk, reg_bg_ctrl_mosi); -- Set the mem low address + proc_mem_mm_bus_wr(5, 95, clk, reg_bg_ctrl_mosi); -- Set the mem high address + proc_mem_mm_bus_wr(6, 42, clk, reg_bg_ctrl_mosi); -- Set the lower part of the initial bsn + proc_mem_mm_bus_wr(7, 0, clk, reg_bg_ctrl_mosi); -- Set the higher part of the initial bsn + + -- BG enable at en_sync pulse + proc_mem_mm_bus_wr(0, 3, clk, reg_bg_ctrl_mosi); -- Enable the block generator at en_sync pulse. + tb_state <= s_enable_sync; + proc_common_wait_some_cycles(clk, c_pend_period); -- Wait an additional amount of cycles + proc_common_gen_pulse(clk, en_sync); -- Issue the en_sync pulse to start the enabled block generator + proc_common_wait_some_cycles(clk, c_on_period); -- On time + proc_common_wait_until_high(clk, out_sosi_arr(0).valid); -- Wait until block generator is active + proc_common_wait_some_cycles(clk, 20); -- Wait an additional amount of cycles + + -- BG disable + proc_mem_mm_bus_wr(0, 0, clk, reg_bg_ctrl_mosi); -- Disable the block generator. + tb_state <= s_disable; + proc_common_wait_some_cycles(clk, c_off_period); -- Off time + + -- BG enable + proc_mem_mm_bus_wr(0, 1, clk, reg_bg_ctrl_mosi); -- Enable the block generator. + tb_state <= s_enable; + proc_common_wait_some_cycles(clk, c_on_period); -- On time + proc_common_wait_until_high(clk, out_sosi_arr(0).valid); -- Wait until block generator is active + proc_common_wait_some_cycles(clk, 20); -- Wait an additional amount of cycles + + -- BG flow off + out_siso_arr <= (OTHERS=>c_dp_siso_rst); -- Flow control XOFF + tb_state <= s_xoff; + proc_common_wait_some_cycles(clk, c_off_period); -- Off time + + -- BG flow on + out_siso_arr <= (OTHERS=>c_dp_siso_rdy); -- Flow control XON + tb_state <= s_xon; + proc_common_wait_some_cycles(clk, c_end_period); -- On time + tb_end <= '1'; + WAIT; + END PROCESS; + + ------------------------------------------------- + -- Instantiation of the device under test + ------------------------------------------------- + u_dut : ENTITY work.mms_diag_block_gen + GENERIC MAP ( + g_blk_sync => c_blk_sync, + g_nof_output_streams => g_nof_streams, + g_buf_dat_w => g_buf_dat_w, + g_buf_addr_w => g_buf_addr_w, + g_file_name_prefix => g_file_name_prefix + ) + PORT MAP ( + -- System + mm_rst => rst, + mm_clk => clk, + dp_rst => rst, + dp_clk => clk, + en_sync => en_sync, + -- MM interface + ram_bg_data_mosi => ram_bg_data_mosi, + ram_bg_data_miso => ram_bg_data_miso, + reg_bg_ctrl_mosi => reg_bg_ctrl_mosi, + reg_bg_ctrl_miso => reg_bg_ctrl_miso, + -- ST interface + out_siso_arr => out_siso_arr, + out_sosi_arr => out_sosi_arr + ); + + ------------------------------------------------- + -- Verification + ------------------------------------------------- + + p_compare_out_sosi_arr : PROCESS(clk) + BEGIN + IF rising_edge(clk) THEN + IF rst='0' THEN + FOR I IN 0 TO g_nof_streams-1 LOOP + -- All outputs have the same framing + ASSERT out_sosi_arr(0).sync =out_sosi_arr(I).sync REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).sync"; + ASSERT out_sosi_arr(0).bsn =out_sosi_arr(I).bsn REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).bsn"; + ASSERT out_sosi_arr(0).im =out_sosi_arr(I).im REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).im"; + ASSERT out_sosi_arr(0).valid=out_sosi_arr(I).valid REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).valid"; + ASSERT out_sosi_arr(0).sop =out_sosi_arr(I).sop REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).sop"; + ASSERT out_sosi_arr(0).eop =out_sosi_arr(I).eop REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).eop"; + + -- Only the re part differs per output given the BG buffer data from g_file_name_prefix + ASSERT TO_UINT(out_sosi_arr(0).re)=TO_UINT(out_sosi_arr(I).re)-I*4 REPORT "tb_mms_diag_block_gen: Wrong out_sosi_arr(*).re"; + END LOOP; + END IF; + END IF; + END PROCESS; + + out_sosi <= out_sosi_arr(0); + + p_verify_en : PROCESS + BEGIN + -- t_tb_state = s_init, s_enable_sync, s_enable + verify_en <= '0'; + proc_common_wait_some_cycles(clk, 400); + verify_en <= '1'; + proc_common_wait_some_cycles(clk, c_on_period); + -- t_tb_state = s_disable + verify_en <= '0'; + proc_common_wait_some_cycles(clk, c_off_period); + -- t_tb_state = s_xoff, s_xon + verify_en <= '1'; -- use c_bsn_gap to cover gap in BSN during s_xoff + WAIT; + END PROCESS; + + proc_dp_verify_data("BSN", c_bsn_max, c_bsn_gap, clk, verify_en, out_sosi.sop, out_sosi.bsn, prev_out_sosi.bsn); + +END tb; \ No newline at end of file