diff --git a/libraries/dsp/st/src/vhdl/mms_st_histogram.vhd b/libraries/dsp/st/src/vhdl/mms_st_histogram.vhd index 31d3b70a152fd97337a7ec43299150333147f3a2..a17010950a6dd5c84c5cbece7105364dd6d51c08 100644 --- a/libraries/dsp/st/src/vhdl/mms_st_histogram.vhd +++ b/libraries/dsp/st/src/vhdl/mms_st_histogram.vhd @@ -35,9 +35,8 @@ -- 3) User reads ram_filling status until it reads zero via reg_mosi -- 4) User reads freshly filled RAM contents via ram_mosi -- . Clearing the RAMs: --- 1) User writes to bit 0 of ram_clear register to clear RAMs of all --- g_nof_instances --- . ram_clearing status will go high +-- . The inactive RAM is cleared automatically just before the next input sync. +-- . ram_clearing status will go high during this time. LIBRARY IEEE, common_lib, mm_lib, technology_lib, dp_lib; USE IEEE.std_logic_1164.ALL; @@ -90,13 +89,9 @@ ARCHITECTURE str OF mms_st_histogram IS SIGNAL common_ram_cr_cw_rd_mosi : t_mem_mosi; SIGNAL common_ram_cr_cw_rd_miso : t_mem_miso; --- SIGNAL reg_mosi_arr : t_mem_mosi_arr(g_nof_instances-1 DOWNTO 0); --- SIGNAL reg_miso_arr : t_mem_miso_arr(g_nof_instances-1 DOWNTO 0); - SIGNAL ram_mosi_arr : t_mem_mosi_arr(g_nof_instances-1 DOWNTO 0); SIGNAL ram_miso_arr : t_mem_miso_arr(g_nof_instances-1 DOWNTO 0); - SIGNAL ram_clear : STD_LOGIC; SIGNAL ram_clearing_arr : STD_LOGIC_VECTOR(g_nof_instances-1 DOWNTO 0); SIGNAL ram_fill_inst : STD_LOGIC_VECTOR(ceil_log2(g_nof_instances)-1 DOWNTO 0); @@ -126,7 +121,6 @@ BEGIN snk_in => snk_in_arr(i), - ram_clear => ram_clear, ram_clearing => ram_clearing_arr(i), ram_mosi => ram_mosi_arr(i), @@ -148,7 +142,6 @@ BEGIN mm_clk => mm_clk, mm_rst => mm_rst, - ram_clear => ram_clear, ram_fill_inst => ram_fill_inst, ram_fill => ram_fill, @@ -157,22 +150,6 @@ BEGIN ); --- ------------------------------------------------------------------------------- --- -- MM multiplexer from g_nof_instances to 1 --- ------------------------------------------------------------------------------- --- u_common_mem_mux_reg : ENTITY common_lib.common_mem_mux --- GENERIC MAP ( --- g_nof_mosi => g_nof_instances, --- g_mult_addr_w => c_reg_adr_w --- ) --- PORT MAP ( --- mosi => reg_mosi, --- miso => reg_miso, --- mosi_arr => reg_mosi_arr, --- miso_arr => reg_miso_arr --- ); - - ------------------------------------------------------------------------------- -- Dual clock RAM: DP write side, MM read side ------------------------------------------------------------------------------- diff --git a/libraries/dsp/st/src/vhdl/st_histogram.vhd b/libraries/dsp/st/src/vhdl/st_histogram.vhd index ec236d67b9fd5ab79542d78396d8ed8cce31c30f..61c2df65bd31b6886a78c05079846fcbff4d3d9b 100644 --- a/libraries/dsp/st/src/vhdl/st_histogram.vhd +++ b/libraries/dsp/st/src/vhdl/st_histogram.vhd @@ -50,10 +50,10 @@ -- | | -- bin_writer_mosi bin_arbiter_wr_mosi -- Usage: --- . The ram_mosi and ram_clear inputs apply to the RAM page that is inactive (not +-- . The ram_mosi input applies to the RAM page that is inactive (not -- being written to from data path) *at that time*. The user should take care to -- time these controls such that the active RAM page does not swap before these --- operations (ram_mosi readout, ram_clear) have finished. +-- operation (ram_mosi readout) has finished. -- Remarks: -- . common_ram_r_w -- . Why common_ram_r_w was selected: it uses a single clock @@ -85,7 +85,6 @@ ENTITY st_histogram IS snk_in : IN t_dp_sosi; -- Active RAM page swaps on snk_in.sync - ram_clear : IN STD_LOGIC; -- Control input: Pulse high to clear the inactive RAM page ram_clearing : OUT STD_LOGIC; -- Status output: high while RAM is being cleared ram_mosi : IN t_mem_mosi; -- MM access to the inactive RAM page @@ -164,6 +163,13 @@ ARCHITECTURE rtl OF st_histogram IS ------------------------------------------------------------------------------- -- ram_clear ------------------------------------------------------------------------------- + CONSTANT c_data_cnt_w : NATURAL := ceil_log2(g_nof_data_per_sync); + + SIGNAL data_cnt : STD_LOGIC_VECTOR(c_data_cnt_w-1 DOWNTO 0); + SIGNAL nxt_data_cnt : STD_LOGIC_VECTOR(c_data_cnt_w-1 DOWNTO 0); + + SIGNAL ram_clear : STD_LOGIC; + SIGNAL ram_clear_address : STD_LOGIC_VECTOR(c_ram_adr_w-1 DOWNTO 0); SIGNAL nxt_ram_clear_address : STD_LOGIC_VECTOR(c_ram_adr_w-1 DOWNTO 0); @@ -365,6 +371,12 @@ BEGIN -- for user being late (the ram pointer is checked only the very moment -- ram_clear is set) ------------------------------------------------------------------------------- + -- Count input data for automatic RAM clear before next sync interval + nxt_data_cnt <= (OTHERS=>'0') WHEN TO_UINT(data_cnt)=g_nof_data_per_sync-1 ELSE INCR_UVEC(data_cnt, 1) WHEN snk_in.valid='1' ELSE data_cnt; + + -- Clear all g_nof_bins RAM addresses just before the next sync + ram_clear <= '1' WHEN TO_UINT(data_cnt)=g_nof_data_per_sync-g_nof_bins-1 ELSE '0'; + -- Signal to indicate when RAM is being cleared nxt_ram_clearing <= '1' WHEN ram_clear='1' ELSE '0' WHEN TO_UINT(ram_clear_address)=g_nof_bins-1 ELSE i_ram_clearing; @@ -381,10 +393,12 @@ BEGIN BEGIN IF dp_rst = '1' THEN ram_clear_address <= (OTHERS=>'0'); - i_ram_clearing <= '0'; + i_ram_clearing <= '0'; + data_cnt <= (OTHERS=>'0'); ELSIF RISING_EDGE(dp_clk) THEN ram_clear_address <= nxt_ram_clear_address; - i_ram_clearing <= nxt_ram_clearing; + i_ram_clearing <= nxt_ram_clearing; + data_cnt <= nxt_data_cnt; END IF; END PROCESS; diff --git a/libraries/dsp/st/tb/vhdl/tb_mms_st_histogram.vhd b/libraries/dsp/st/tb/vhdl/tb_mms_st_histogram.vhd index 85c43527be329f9427479d72818f9febc89cf4d6..0e8fea35b4f7ce3e88e4db243d208345db39ef2a 100644 --- a/libraries/dsp/st/tb/vhdl/tb_mms_st_histogram.vhd +++ b/libraries/dsp/st/tb/vhdl/tb_mms_st_histogram.vhd @@ -45,10 +45,11 @@ USE dp_lib.tb_dp_pkg.ALL; ENTITY tb_mms_st_histogram IS GENERIC( - g_nof_instances : NATURAL := 1; - g_data_w : NATURAL := 8; - g_nof_bins : NATURAL := 256; - g_nof_data_per_sync : NATURAL := 1024 + g_nof_sync : NATURAL := 4; + g_nof_instances : NATURAL := 12; + g_data_w : NATURAL := 14; + g_nof_bins : NATURAL := 512; + g_nof_data_per_sync : NATURAL := 40000 ); END tb_mms_st_histogram; @@ -68,18 +69,40 @@ ARCHITECTURE tb OF tb_mms_st_histogram IS SIGNAL mm_rst : STD_LOGIC; SIGNAL tb_end : STD_LOGIC := '0'; + + ---------------------------------------------------------------------------- + -- stimuli + ---------------------------------------------------------------------------- + SIGNAL stimuli_en : STD_LOGIC := '1'; + + SIGNAL stimuli_src_out : t_dp_sosi; + SIGNAL stimuli_src_in : t_dp_siso; ---------------------------------------------------------------------------- -- st_histogram ---------------------------------------------------------------------------- - SIGNAL st_histogram_snk_in : t_dp_sosi; + SIGNAL st_histogram_snk_in_arr : t_dp_sosi_arr(g_nof_instances-1 DOWNTO 0); + + SIGNAL st_histogram_reg_mosi : t_mem_mosi; + SIGNAL st_histogram_reg_miso : t_mem_miso; + + SIGNAL st_histogram_ram_mosi : t_mem_mosi; + SIGNAL st_histogram_ram_miso : t_mem_miso; + + + ---------------------------------------------------------------------------- + -- Readout & verification + ---------------------------------------------------------------------------- + CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync)+1; - SIGNAL st_histogram_reg_mosi : t_mem_mosi; - SIGNAL st_histogram_reg_miso : t_mem_miso; + CONSTANT c_expected_ram_content : NATURAL := g_nof_data_per_sync/g_nof_bins; - SIGNAL st_histogram_ram_mosi : t_mem_mosi; - SIGNAL st_histogram_ram_miso : t_mem_miso; + SIGNAL ram_filling : STD_LOGIC; + SIGNAL ram_rd_word : STD_LOGIC_VECTOR(c_ram_dat_w-1 DOWNTO 0); + SIGNAL ram_rd_word_int : NATURAL; + SIGNAL ram_rd_word_valid : STD_LOGIC; + SIGNAL nxt_ram_rd_word_valid : STD_LOGIC; BEGIN @@ -93,9 +116,37 @@ BEGIN mm_rst <= '1', '0' AFTER c_mm_clk_period*10; + ---------------------------------------------------------------------------- + -- DP Stimuli: generate st_histogram input data + ---------------------------------------------------------------------------- + stimuli_src_in <= c_dp_siso_rdy; + + -- Generate g_nof_sync packets of g_nof_data_per_sync words + p_generate_packets : PROCESS + VARIABLE v_sosi : t_dp_sosi := c_dp_sosi_rst; + BEGIN + stimuli_src_out <= c_dp_sosi_rst; + proc_common_wait_until_low(dp_clk, dp_rst); + proc_common_wait_some_cycles(dp_clk, 5); + + FOR I IN 0 TO g_nof_sync-1 LOOP + v_sosi.sync := '1'; + v_sosi.data := RESIZE_DP_DATA(v_sosi.data(g_data_w-1 DOWNTO 0)); -- wrap when >= 2**g_data_w + proc_dp_gen_block_data(g_data_w, TO_UINT(v_sosi.data), g_nof_data_per_sync, TO_UINT(v_sosi.channel), TO_UINT(v_sosi.err), v_sosi.sync, v_sosi.bsn, dp_clk, stimuli_en, stimuli_src_in, stimuli_src_out); + END LOOP; + + proc_common_wait_some_cycles(dp_clk, 50); + tb_end <= '1'; + WAIT; + END PROCESS; + ---------------------------------------------------------------------------- -- mms_st_histogram ---------------------------------------------------------------------------- + gen_snk_in_arr: FOR i IN 0 TO g_nof_instances-1 GENERATE + st_histogram_snk_in_arr(i) <= stimuli_src_out; + END GENERATE; + u_mms_st_histogram : ENTITY work.mms_st_histogram GENERIC MAP( g_nof_instances => g_nof_instances, @@ -110,7 +161,7 @@ BEGIN mm_clk => mm_clk, mm_rst => mm_rst, - snk_in_arr(0)=> st_histogram_snk_in, + snk_in_arr => st_histogram_snk_in_arr, reg_mosi => st_histogram_reg_mosi, reg_miso => st_histogram_reg_miso, @@ -119,27 +170,81 @@ BEGIN ram_miso => st_histogram_ram_miso ); + ---------------------------------------------------------------------------- - -- Readout of RAM - ---------------------------------------------------------------------------- - -- Perform MM read - p_verify_mm_read : PROCESS + -- MM Readout of st_histogram instances + ---------------------------------------------------------------------------- + p_ram_clear : PROCESS BEGIN + st_histogram_ram_mosi <= c_mem_mosi_rst; st_histogram_reg_mosi <= c_mem_mosi_rst; - proc_common_wait_until_low(mm_clk, mm_rst); - proc_common_wait_some_cycles(mm_clk, 10); - - -- Start RAM filling - proc_mem_mm_bus_wr(2, 1, mm_clk, st_histogram_reg_mosi); + ram_filling <= '0'; + ram_rd_word <= (OTHERS=>'0'); + -- The first sync indicates start of incoming data - let it pass + proc_common_wait_until_high(dp_clk, stimuli_src_out.sync); + proc_common_wait_some_cycles(mm_clk, 10); + FOR i IN 0 TO g_nof_sync-2 LOOP + -- Wiat for a full sync period of data + proc_common_wait_until_high(dp_clk, stimuli_src_out.sync); + -- The sync has passed, we can start reading the resulting histogram + FOR j IN 0 TO g_nof_instances-1 LOOP + -- Select st_histogram instance to read out + proc_mem_mm_bus_wr(1, j, mm_clk, st_histogram_reg_mosi); + proc_common_wait_some_cycles(mm_clk, 2); + + -- Enable RAM filling + proc_mem_mm_bus_wr(2, 1, mm_clk, st_histogram_reg_mosi); + proc_common_wait_some_cycles(mm_clk, 10); + + -- Wait until RAM filling is done + proc_mem_mm_bus_rd(2, mm_clk, st_histogram_reg_mosi); + ram_filling <= st_histogram_reg_miso.rddata(0); + proc_common_wait_some_cycles(mm_clk, 2); + WHILE ram_filling='1' LOOP + -- Read filling status + proc_mem_mm_bus_rd(2, mm_clk, st_histogram_reg_mosi); + ram_filling <= st_histogram_reg_miso.rddata(0); + proc_common_wait_some_cycles(mm_clk, 1); + END LOOP; + + -- Read out the RAM contents + FOR k IN 0 TO g_nof_bins-1 LOOP + proc_mem_mm_bus_rd(k, mm_clk, st_histogram_ram_mosi); + ram_rd_word <= st_histogram_ram_miso.rddata(c_ram_dat_w-1 DOWNTO 0); + ram_rd_word_int <= TO_UINT(ram_rd_word); + END LOOP; + END LOOP; + END LOOP; + END PROCESS; - proc_common_wait_some_cycles(mm_clk, 10); + -- Register st_histogram_ram_miso.rdval so we read only valid data + p_nxt_ram_rd_word_valid : PROCESS(mm_rst, mm_clk) + BEGIN + IF mm_rst = '1' THEN + ram_rd_word_valid <= '0'; + ELSIF RISING_EDGE(mm_clk) THEN + ram_rd_word_valid <= nxt_ram_rd_word_valid; + END IF; + END PROCESS; + nxt_ram_rd_word_valid <= st_histogram_ram_miso.rdval; - -- Read filling status - proc_mem_mm_bus_rd(2, mm_clk, st_histogram_reg_mosi); - proc_common_wait_some_cycles(mm_clk, 1000); - tb_end <= '1'; - WAIT; + ---------------------------------------------------------------------------- + -- Perform verification of ram_rd_word when ram_rd_word_valid + ---------------------------------------------------------------------------- + p_verify_assert : PROCESS + BEGIN + FOR i IN 0 TO g_nof_sync-1 LOOP + proc_common_wait_until_high(dp_clk, stimuli_src_out.sync); + proc_common_wait_until_high(dp_clk, ram_rd_word_valid); + IF i=0 THEN -- Sync period 0: we expect RAM to contain zeros + ASSERT ram_rd_word_int=0 REPORT "RAM contains wrong bin count (expected 0, actual " & INTEGER'IMAGE(ram_rd_word_int) & ")" SEVERITY ERROR; + ELSE -- Sync period 1 onwards + ASSERT ram_rd_word_int=c_expected_ram_content REPORT "RAM contains wrong bin count (expected " & INTEGER'IMAGE(c_expected_ram_content) & ", actual " & INTEGER'IMAGE(ram_rd_word_int) & ")" SEVERITY ERROR; + END IF; + END LOOP; + WAIT FOR 5 ns; END PROCESS; + END tb; diff --git a/libraries/dsp/st/tb/vhdl/tb_st_histogram.vhd b/libraries/dsp/st/tb/vhdl/tb_st_histogram.vhd index 8720672d3a9700c87e40b7e693969450fc227eac..6b4d3eeadd9b5807ab58e9ae606dcd72d3df91c7 100644 --- a/libraries/dsp/st/tb/vhdl/tb_st_histogram.vhd +++ b/libraries/dsp/st/tb/vhdl/tb_st_histogram.vhd @@ -69,7 +69,6 @@ ARCHITECTURE tb OF tb_st_histogram IS --------------------------------------------------------------------------- -- Constants derived from generics --------------------------------------------------------------------------- - CONSTANT c_nof_data_before_ram_clear : NATURAL := largest(1, g_nof_data_per_sync-g_nof_bins); -- Clear RAM just before next Sync interval CONSTANT c_expected_ram_content : NATURAL := g_nof_data_per_sync/g_nof_bins; CONSTANT c_ram_dat_w : NATURAL := ceil_log2(g_nof_data_per_sync)+1; @@ -98,7 +97,6 @@ ARCHITECTURE tb OF tb_st_histogram IS SIGNAL st_histogram_snk_in : t_dp_sosi; SIGNAL st_histogram_ram_mosi : t_mem_mosi; SIGNAL st_histogram_ram_miso : t_mem_miso; - SIGNAL st_histogram_ram_clear : STD_LOGIC; ---------------------------------------------------------------------------- -- Automatic verification of RAM readout @@ -141,22 +139,6 @@ BEGIN WAIT; END PROCESS; - -- Clear the RAM - p_ram_clear : PROCESS - BEGIN - FOR I IN 0 TO g_nof_sync-1 LOOP - -- Sync up with p_generate_packets above by waiting for stimuli_src_out.sync - proc_common_wait_until_high(dp_clk, stimuli_src_out.sync); - -- Wait until c_nof_data_before_ram_clear cycles have passed - st_histogram_ram_clear <= '0'; - proc_common_wait_some_cycles(dp_clk, c_nof_data_before_ram_clear-1); - -- Toggle RAM clear for 1 cycle - st_histogram_ram_clear <= '1'; - proc_common_wait_some_cycles(dp_clk, 1); - st_histogram_ram_clear <= '0'; - END LOOP; - END PROCESS; - ---------------------------------------------------------------------------- -- st_histogram @@ -174,8 +156,6 @@ BEGIN dp_rst => dp_rst, snk_in => st_histogram_snk_in, - - ram_clear => st_histogram_ram_clear, ram_mosi => st_histogram_ram_mosi, ram_miso => st_histogram_ram_miso