diff --git a/libraries/base/common/tb/vhdl/tb_common_paged_ram_cr_cw.vhd b/libraries/base/common/tb/vhdl/tb_common_paged_ram_cr_cw.vhd new file mode 100644 index 0000000000000000000000000000000000000000..05e526c6838c9c5742008eeaac54cc7af1a214df --- /dev/null +++ b/libraries/base/common/tb/vhdl/tb_common_paged_ram_cr_cw.vhd @@ -0,0 +1,231 @@ +-- ----------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- ----------------------------------------------------------------------------- +-- +-- Author: +-- D.F. Brouwer +-- Purpose: +-- Test bench for common_paged_ram_cr_cw +-- Reference: +-- Based on tb_common_paged_ram_crw_crw.vhd +-- Description: +-- Features: +-- . Use c_gap_sz = 0 to try writing and reading multiple page without idle +-- cycles +-- . Most applications use c_nof_pages = 2, but use > 2 is supported too. +-- Usage: +-- > as 10 +-- > run -all + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.common_pkg.all; +use work.tb_common_pkg.all; + +entity tb_common_paged_ram_cr_cw is +end tb_common_paged_ram_cr_cw; + +architecture tb of tb_common_paged_ram_cr_cw is + constant clk_period : time := 10 ns; + + constant c_data_w : natural := 8; + constant c_nof_pages : natural := 2; -- >= 2 + constant c_page_sz : natural := 8; + constant c_wr_start_page : natural := 0; + constant c_rd_start_page : natural := 1; + constant c_gap_sz : natural := 0; -- >= 0 + constant c_rl : natural := 1; + + signal rst : std_logic; + signal clk : std_logic := '1'; + signal tb_end : std_logic := '0'; + + -- DUT + signal next_page : std_logic; + + signal wr_next_page : std_logic; + signal wr_adr : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0'); + signal wr_en : std_logic; + signal wr_dat : std_logic_vector(c_data_w - 1 downto 0) := (others => '0'); + + signal rd_next_page : std_logic; + signal rd_adr : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0'); + signal rd_en : std_logic := '0'; + + signal mux_rd_dat : std_logic_vector(c_data_w - 1 downto 0); + signal mux_rd_val : std_logic; + + signal adr_rd_dat : std_logic_vector(c_data_w - 1 downto 0); + signal adr_rd_val : std_logic; + + signal ofs_rd_dat : std_logic_vector(c_data_w - 1 downto 0); + signal ofs_rd_val : std_logic; + + -- Verify + signal verify_en : std_logic; + signal ready : std_logic := '1'; + + signal prev_mux_rd_dat : std_logic_vector(c_data_w - 1 downto 0); + signal prev_adr_rd_dat : std_logic_vector(c_data_w - 1 downto 0); + signal prev_ofs_rd_dat : std_logic_vector(c_data_w - 1 downto 0); +begin + clk <= not clk and not tb_end after clk_period / 2; + rst <= '1', '0' after clk_period * 7; + + verify_en <= '0', '1' after clk_period * (15 + (c_nof_pages - 1) * c_page_sz); + + -- Apply stimuli via port 'a', do write 'a' and read 'b', and derive the 'b' stimuli from the 'a' stimuli with 1 clock cycle latency + wr_next_page <= next_page; + rd_next_page <= next_page when rising_edge(clk); + + wr_dat <= INCR_UVEC( wr_dat, 1) when rising_edge(clk) and wr_en = '1'; + wr_adr <= INCR_UVEC( wr_adr, 1) when rising_edge(clk) and wr_en = '1'; + rd_adr <= wr_adr when rising_edge(clk); + rd_en <= wr_en when rising_edge(clk); + + p_stimuli : process + begin + next_page <= '0'; + wr_en <= '0'; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 3); + + -- Access the pages several times + for I in 0 to c_nof_pages * 3 loop + wr_en <= '1'; + proc_common_wait_some_cycles(clk, c_page_sz - 1); + next_page <= '1'; + proc_common_wait_some_cycles(clk, 1); + next_page <= '0'; + wr_en <= '0'; + proc_common_wait_some_cycles(clk, c_gap_sz); -- optinal gap between the pages + end loop; + + wr_en <= '0'; + proc_common_wait_some_cycles(clk, c_page_sz); + tb_end <= '1'; + wait; + end process; + + u_dut_mux : entity work.common_paged_ram_cr_cw + generic map ( + g_str => "use_mux", + g_data_w => c_data_w, + g_nof_pages => c_nof_pages, + g_page_sz => c_page_sz, + g_wr_start_page => c_wr_start_page, + g_rd_start_page => c_rd_start_page + ) + port map ( + -- Write port clock domain + wr_rst => rst, + wr_clk => clk, + wr_clken => '1', + wr_next_page => wr_next_page, + wr_adr => wr_adr, + wr_en => wr_en, + wr_dat => wr_dat, + -- Read port clock domain + rd_rst => rst, + rd_clk => clk, + rd_clken => '1', + rd_next_page => rd_next_page, + rd_adr => rd_adr, + rd_en => rd_en, + rd_dat => mux_rd_dat, + rd_val => mux_rd_val + ); + + u_dut_adr : entity work.common_paged_ram_cr_cw + generic map ( + g_str => "use_adr", + g_data_w => c_data_w, + g_nof_pages => c_nof_pages, + g_page_sz => c_page_sz, + g_wr_start_page => c_wr_start_page, + g_rd_start_page => c_rd_start_page + ) + port map ( + -- Write port clock domain + wr_rst => rst, + wr_clk => clk, + wr_clken => '1', + wr_next_page => wr_next_page, + wr_adr => wr_adr, + wr_en => wr_en, + wr_dat => wr_dat, + -- Read port clock domain + rd_rst => rst, + rd_clk => clk, + rd_clken => '1', + rd_next_page => rd_next_page, + rd_adr => rd_adr, + rd_en => rd_en, + rd_dat => adr_rd_dat, + rd_val => adr_rd_val + ); + + u_dut_ofs : entity work.common_paged_ram_cr_cw + generic map ( + g_str => "use_ofs", + g_data_w => c_data_w, + g_nof_pages => c_nof_pages, + g_page_sz => c_page_sz, + g_wr_start_page => c_wr_start_page, + g_rd_start_page => c_rd_start_page + ) + port map ( + -- Write port clock domain + wr_rst => rst, + wr_clk => clk, + wr_clken => '1', + wr_next_page => wr_next_page, + wr_adr => wr_adr, + wr_en => wr_en, + wr_dat => wr_dat, + -- Read port clock domain + rd_rst => rst, + rd_clk => clk, + rd_clken => '1', + rd_next_page => rd_next_page, + rd_adr => rd_adr, + rd_en => rd_en, + rd_dat => ofs_rd_dat, + rd_val => ofs_rd_val + ); + + -- Verify that the read data is incrementing data + proc_common_verify_data(c_rl, clk, verify_en, ready, mux_rd_val, mux_rd_dat, prev_mux_rd_dat); + proc_common_verify_data(c_rl, clk, verify_en, ready, adr_rd_val, adr_rd_dat, prev_adr_rd_dat); + proc_common_verify_data(c_rl, clk, verify_en, ready, ofs_rd_val, ofs_rd_dat, prev_ofs_rd_dat); + + -- Verify that the read data is the same for all three DUT variants + p_verify_equal : process(clk) + begin + if rising_edge(clk) then + if unsigned(mux_rd_dat) /= unsigned(adr_rd_dat) or unsigned(mux_rd_dat) /= unsigned(ofs_rd_dat) then + report "DUT : read data differs between two implementations" severity ERROR; + end if; + if mux_rd_val /= adr_rd_val or mux_rd_val /= ofs_rd_val then + report "DUT : read valid differs between two implementations" severity ERROR; + end if; + end if; + end process; +end tb; diff --git a/libraries/base/common/tb/vhdl/tb_common_paged_ram_rw_rw.vhd b/libraries/base/common/tb/vhdl/tb_common_paged_ram_rw_rw.vhd new file mode 100644 index 0000000000000000000000000000000000000000..2de05fffb45fc79828ab8ff58ced5d5406787234 --- /dev/null +++ b/libraries/base/common/tb/vhdl/tb_common_paged_ram_rw_rw.vhd @@ -0,0 +1,231 @@ +-- ----------------------------------------------------------------------------- +-- +-- Copyright 2023 +-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/> +-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +-- ----------------------------------------------------------------------------- +-- +-- Author: +-- D.F. Brouwer +-- Purpose: +-- Test bench for common_paged_ram_rw_rw +-- Reference: +-- Based on tb_common_paged_ram_crw_crw.vhd +-- Description: +-- Features: +-- . Use c_gap_sz = 0 to try writing and reading multiple page without idle +-- cycles +-- . Most applications use c_nof_pages = 2, but use > 2 is supported too. +-- Usage: +-- > as 10 +-- > run -all + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.common_pkg.all; +use work.tb_common_pkg.all; + +entity tb_common_paged_ram_rw_rw is +end tb_common_paged_ram_rw_rw; + +architecture tb of tb_common_paged_ram_rw_rw is + constant clk_period : time := 10 ns; + + constant c_data_w : natural := 8; + constant c_nof_pages : natural := 2; -- >= 2 + constant c_page_sz : natural := 8; + constant c_start_page_a : natural := 0; + constant c_start_page_b : natural := 1; + constant c_gap_sz : natural := 0; -- >= 0 + constant c_rl : natural := 1; + + signal rst : std_logic; + signal clk : std_logic := '1'; + signal tb_end : std_logic := '0'; + + -- DUT + signal next_page : std_logic; + + signal next_page_a : std_logic; + signal adr_a : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0'); + signal wr_en_a : std_logic; + signal wr_dat_a : std_logic_vector(c_data_w - 1 downto 0) := (others => '0'); + + signal next_page_b : std_logic; + signal adr_b : std_logic_vector(ceil_log2(c_page_sz) - 1 downto 0) := (others => '0'); + signal rd_en_b : std_logic := '0'; + + signal mux_rd_dat_b : std_logic_vector(c_data_w - 1 downto 0); + signal mux_rd_val_b : std_logic; + + signal adr_rd_dat_b : std_logic_vector(c_data_w - 1 downto 0); + signal adr_rd_val_b : std_logic; + + signal ofs_rd_dat_b : std_logic_vector(c_data_w - 1 downto 0); + signal ofs_rd_val_b : std_logic; + + -- Verify + signal verify_en : std_logic; + signal ready : std_logic := '1'; + + signal prev_mux_rd_dat_b : std_logic_vector(c_data_w - 1 downto 0); + signal prev_adr_rd_dat_b : std_logic_vector(c_data_w - 1 downto 0); + signal prev_ofs_rd_dat_b : std_logic_vector(c_data_w - 1 downto 0); +begin + clk <= not clk and not tb_end after clk_period / 2; + rst <= '1', '0' after clk_period * 7; + + verify_en <= '0', '1' after clk_period * (15 + (c_nof_pages - 1) * c_page_sz); + + -- Apply stimuli via port 'a', do write 'a' and read 'b', and derive the 'b' stimuli from the 'a' stimuli with 1 clock cycle latency + next_page_a <= next_page; + next_page_b <= next_page when rising_edge(clk); + + wr_dat_a <= INCR_UVEC(wr_dat_a, 1) when rising_edge(clk) and wr_en_a = '1'; + adr_a <= INCR_UVEC( adr_a, 1) when rising_edge(clk) and wr_en_a = '1'; + adr_b <= adr_a when rising_edge(clk); + rd_en_b <= wr_en_a when rising_edge(clk); + + p_stimuli : process + begin + next_page <= '0'; + wr_en_a <= '0'; + proc_common_wait_until_low(clk, rst); + proc_common_wait_some_cycles(clk, 3); + + -- Access the pages several times + for I in 0 to c_nof_pages * 3 loop + wr_en_a <= '1'; + proc_common_wait_some_cycles(clk, c_page_sz - 1); + next_page <= '1'; + proc_common_wait_some_cycles(clk, 1); + next_page <= '0'; + wr_en_a <= '0'; + proc_common_wait_some_cycles(clk, c_gap_sz); -- optinal gap between the pages + end loop; + + wr_en_a <= '0'; + proc_common_wait_some_cycles(clk, c_page_sz); + tb_end <= '1'; + wait; + end process; + + u_dut_mux : entity work.common_paged_ram_rw_rw + generic map ( + g_str => "use_mux", + g_data_w => c_data_w, + g_nof_pages => c_nof_pages, + g_page_sz => c_page_sz, + g_start_page_a => c_start_page_a, + g_start_page_b => c_start_page_b + ) + port map ( + rst => rst, + clk => clk, + clken => '1', + next_page_a => next_page_a, + adr_a => adr_a, + wr_en_a => wr_en_a, + wr_dat_a => wr_dat_a, + rd_en_a => '0', + rd_dat_a => OPEN, + rd_val_a => OPEN, + next_page_b => next_page_b, + adr_b => adr_b, + wr_en_b => '0', + wr_dat_b => (others => '0'), + rd_en_b => rd_en_b, + rd_dat_b => mux_rd_dat_b, + rd_val_b => mux_rd_val_b + ); + + u_dut_adr : entity work.common_paged_ram_rw_rw + generic map ( + g_str => "use_adr", + g_data_w => c_data_w, + g_nof_pages => c_nof_pages, + g_page_sz => c_page_sz, + g_start_page_a => c_start_page_a, + g_start_page_b => c_start_page_b + ) + port map ( + rst => rst, + clk => clk, + clken => '1', + next_page_a => next_page_a, + adr_a => adr_a, + wr_en_a => wr_en_a, + wr_dat_a => wr_dat_a, + rd_en_a => '0', + rd_dat_a => OPEN, + rd_val_a => OPEN, + next_page_b => next_page_b, + adr_b => adr_b, + wr_en_b => '0', + wr_dat_b => (others => '0'), + rd_en_b => rd_en_b, + rd_dat_b => adr_rd_dat_b, + rd_val_b => adr_rd_val_b + ); + + u_dut_ofs : entity work.common_paged_ram_rw_rw + generic map ( + g_str => "use_ofs", + g_data_w => c_data_w, + g_nof_pages => c_nof_pages, + g_page_sz => c_page_sz, + g_start_page_a => c_start_page_a, + g_start_page_b => c_start_page_b + ) + port map ( + rst => rst, + clk => clk, + clken => '1', + next_page_a => next_page_a, + adr_a => adr_a, + wr_en_a => wr_en_a, + wr_dat_a => wr_dat_a, + rd_en_a => '0', + rd_dat_a => OPEN, + rd_val_a => OPEN, + next_page_b => next_page_b, + adr_b => adr_b, + wr_en_b => '0', + wr_dat_b => (others => '0'), + rd_en_b => rd_en_b, + rd_dat_b => ofs_rd_dat_b, + rd_val_b => ofs_rd_val_b + ); + + -- Verify that the read data is incrementing data + proc_common_verify_data(c_rl, clk, verify_en, ready, mux_rd_val_b, mux_rd_dat_b, prev_mux_rd_dat_b); + proc_common_verify_data(c_rl, clk, verify_en, ready, adr_rd_val_b, adr_rd_dat_b, prev_adr_rd_dat_b); + proc_common_verify_data(c_rl, clk, verify_en, ready, ofs_rd_val_b, ofs_rd_dat_b, prev_ofs_rd_dat_b); + + -- Verify that the read data is the same for all three DUT variants + p_verify_equal : process(clk) + begin + if rising_edge(clk) then + if unsigned(mux_rd_dat_b) /= unsigned(adr_rd_dat_b) or unsigned(mux_rd_dat_b) /= unsigned(ofs_rd_dat_b) then + report "DUT : read data differs between two implementations" severity ERROR; + end if; + if mux_rd_val_b /= adr_rd_val_b or mux_rd_val_b /= ofs_rd_val_b then + report "DUT : read valid differs between two implementations" severity ERROR; + end if; + end if; + end process; +end tb;