diff --git a/sim/L0_mem_ctrl_test1.do b/sim/L0_mem_ctrl_test1.do new file mode 100644 index 0000000..9969d0f --- /dev/null +++ b/sim/L0_mem_ctrl_test1.do @@ -0,0 +1,51 @@ +onerror {resume} +quietly WaveActivateNextPane {} 0 +add wave -noupdate -divider SYSTEM +add wave -noupdate /l0_mem_ctrl_test1/uut/clk +add wave -noupdate /l0_mem_ctrl_test1/uut/reset +add wave -noupdate -divider INPUT +add wave -noupdate /l0_mem_ctrl_test1/uut/ready_in +add wave -noupdate /l0_mem_ctrl_test1/uut/valid_in +add wave -noupdate -radix unsigned /l0_mem_ctrl_test1/uut/addr +add wave -noupdate -radix hexadecimal /l0_mem_ctrl_test1/uut/data_in +add wave -noupdate /l0_mem_ctrl_test1/uut/read +add wave -noupdate -divider MEMORY +add wave -noupdate -expand -group MEMORY -radix unsigned /l0_mem_ctrl_test1/uut/ram_inst/addr +add wave -noupdate -expand -group MEMORY -radix hexadecimal /l0_mem_ctrl_test1/uut/ram_inst/rd_data +add wave -noupdate -expand -group MEMORY /l0_mem_ctrl_test1/uut/ram_inst/ren +add wave -noupdate -expand -group MEMORY /l0_mem_ctrl_test1/uut/ram_inst/wen +add wave -noupdate -expand -group MEMORY -radix hexadecimal /l0_mem_ctrl_test1/uut/ram_inst/wr_data +add wave -noupdate -divider OUTPUT +add wave -noupdate /l0_mem_ctrl_test1/uut/ready_out +add wave -noupdate -radix hexadecimal /l0_mem_ctrl_test1/uut/data_out +add wave -noupdate /l0_mem_ctrl_test1/uut/valid_out +add wave -noupdate -divider MISC +add wave -noupdate /l0_mem_ctrl_test1/uut/delay_line +add wave -noupdate -radix unsigned /l0_mem_ctrl_test1/uut/delay_cnt +add wave -noupdate /l0_mem_ctrl_test1/uut/burst_fifo_inst/free +add wave -noupdate -divider FIFO +add wave -noupdate -group FIFO -radix hexadecimal /l0_mem_ctrl_test1/uut/burst_fifo_inst/data_in +add wave -noupdate -group FIFO /l0_mem_ctrl_test1/uut/burst_fifo_inst/read +add wave -noupdate -group FIFO /l0_mem_ctrl_test1/uut/burst_fifo_inst/write +add wave -noupdate -group FIFO -radix hexadecimal /l0_mem_ctrl_test1/uut/burst_fifo_inst/data_out +add wave -noupdate -group FIFO /l0_mem_ctrl_test1/uut/burst_fifo_inst/empty +add wave -noupdate -group FIFO /l0_mem_ctrl_test1/uut/burst_fifo_inst/free +add wave -noupdate -group FIFO /l0_mem_ctrl_test1/uut/burst_fifo_inst/full +TreeUpdate [SetDefaultTree] +WaveRestoreCursors {{Cursor 1} {574535 ps} 0} +quietly wave cursor active 1 +configure wave -namecolwidth 149 +configure wave -valuecolwidth 144 +configure wave -justifyvalue left +configure wave -signalnamewidth 1 +configure wave -snapdistance 10 +configure wave -datasetprefix 0 +configure wave -rowmargin 4 +configure wave -childrowmargin 2 +configure wave -gridoffset 0 +configure wave -gridperiod 1 +configure wave -griddelta 40 +configure wave -timeline 0 +configure wave -timelineunits ps +update +WaveRestoreZoom {0 ps} {1148342 ps} diff --git a/src/Tests/Level_0/L0_mem_ctrl_test1.vhd b/src/Tests/Level_0/L0_mem_ctrl_test1.vhd new file mode 100644 index 0000000..94ac760 --- /dev/null +++ b/src/Tests/Level_0/L0_mem_ctrl_test1.vhd @@ -0,0 +1,233 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library osvvm; -- Utility Library +context osvvm.OsvvmContext; + +use work.rtps_test_package.all; + +entity L0_mem_ctrl_test1 is +end entity; + +architecture testbench of L0_mem_ctrl_test1 is + + -- *CONSTANT DECLARATION* + constant WORD_WIDTH : natural := 32; + constant ADDR_WIDTH : natural := 3; + constant MEMORY_DEPTH : natural := 2**ADDR_WIDTH; + constant BURST_LENGTH : natural := MEMORY_DEPTH; + + -- *TYPE DECLARATION* + type TEST_ARRAY_TYPE is array (0 to MEMORY_DEPTH-1) of std_logic_vector(WORD_WIDTH-1 downto 0); + + -- *SIGNAL DECLARATION* + signal clk, read, ready_in, valid_in, ready_out, valid_out : std_logic := '0'; + signal data_in, data_out : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + signal addr : std_logic_vector(ADDR_WIDTH-1 downto 0) := (others => '0'); + signal reset : std_logic := '1'; + shared variable SB : osvvm.ScoreBoardPkg_slv.ScoreBoardPType; + +begin + + + -- Unit Under Test + uut : entity work.mem_ctrl(arch) + generic map ( + ADDR_WIDTH => ADDR_WIDTH, + DATA_WIDTH => WORD_WIDTH, + MEMORY_DEPTH => MEMORY_DEPTH, + MAX_BURST_LENGTH => BURST_LENGTH + ) + port map ( + clk => clk, + reset => reset, + addr => addr, + read => read, + ready_in => ready_in, + valid_in => valid_in, + data_in => data_in, + ready_out => ready_out, + valid_out => valid_out, + data_out => data_out + ); + + stimulus_prc : process + variable RV : RandomPType; + variable test_array : TEST_ARRAY_TYPE := (others => (others => '0')); + variable tmp : std_logic_vector(WORD_WIDTH-1 downto 0) := (others => '0'); + begin + SetAlertLogName("mem_ctrl - Level 0 - Generic"); + SetAlertEnable(FAILURE, TRUE); + SetAlertEnable(ERROR, TRUE); + SetAlertEnable(WARNING, TRUE); + SetLogEnable(DEBUG, FALSE); + SetLogEnable(PASSED, FALSE); + SetLogEnable(INFO, TRUE); + RV.InitSeed(RV'instance_name); + + Log("Initiating Test", INFO); + valid_in <= '0'; + data_in <= (others => '0'); + reset <= '1'; + wait until rising_edge(clk); + wait until rising_edge(clk); + reset <= '0'; + + + Log("Test Write Burst", INFO); + AffirmIf(valid_out = '0', "Read output without Read request"); + -- Write entire Memory with random data + for i in 0 to MEMORY_DEPTH-1 loop + valid_in <= '1'; + addr <= std_logic_vector(to_unsigned(i, ADDR_WIDTH)); + tmp := RV.RandSlv(WORD_WIDTH); + test_array(i) := tmp; + data_in <= tmp; + if (ready_in = '0') then + wait until ready_in = '1'; + end if; + wait until rising_edge(clk); + end loop; + valid_in <= '0'; + addr <= (others => '0'); + data_in <= (others => '0'); + wait until rising_edge(clk); + + + Log("Test Single Read", INFO); + -- Read one element from memory + AffirmIf(valid_out = '0', "Read output without Read request"); + valid_in <= '1'; + addr <= std_logic_vector(to_unsigned(0, ADDR_WIDTH)); + read <= '1'; + SB.Push(test_array(0)); + wait until rising_edge(clk); + valid_in <= '0'; + addr <= (others => '0'); + read <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + + + Log("Test Read Burst", INFO); + -- Fill Read Burst + for i in MEMORY_DEPTH-1 downto 0 loop + valid_in <= '1'; + addr <= std_logic_vector(to_unsigned(i, ADDR_WIDTH)); + read <= '1'; + SB.Push(test_array(i)); + if (ready_in = '0') then + wait until ready_in = '1'; + end if; + wait until rising_edge(clk); + end loop; + valid_in <= '0'; + addr <= (others => '0'); + read <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + + + Log("Test Concurrent Request/Read Operation", INFO); + -- Request + valid_in <= '1'; + addr <= std_logic_vector(to_unsigned(0, ADDR_WIDTH)); + read <= '1'; + SB.Push(test_array(0)); + if (ready_in = '0') then + wait until ready_in = '1'; + end if; + wait until rising_edge(clk); + valid_in <= '0'; + addr <= (others => '0'); + read <= '0'; + -- Read and Request + if (valid_out /= '1') then + wait until valid_out = '1'; + end if; + valid_in <= '1'; + addr <= std_logic_vector(to_unsigned(1, ADDR_WIDTH)); + read <= '1'; + SB.Push(test_array(1)); + AlertIf(ready_in /= '1', "Precondition for concurrent operation not met"); + wait until rising_edge(clk); + valid_in <= '0'; + addr <= (others => '0'); + read <= '0'; + -- Read + wait until rising_edge(clk); + wait until rising_edge(clk); + + + Log("Test Operation Order", INFO); + -- Request Address 0 + valid_in <= '1'; + addr <= std_logic_vector(to_unsigned(0, ADDR_WIDTH)); + read <= '1'; + SB.Push(test_array(0)); + if (ready_in = '0') then + wait until ready_in = '1'; + end if; + wait until rising_edge(clk); + -- Write Address 0 + read <= '0'; + data_in <= test_array(MEMORY_DEPTH-1); + if (ready_in = '0') then + wait until ready_in = '1'; + end if; + wait until rising_edge(clk); + -- Request Address 0 + read <= '1'; + SB.Push(test_array(7)); + data_in <= (others => '0'); + if (ready_in = '0') then + wait until ready_in = '1'; + end if; + wait until rising_edge(clk); + valid_in <= '0'; + addr <= (others => '0'); + read <= '0'; + wait until rising_edge(clk); + wait until rising_edge(clk); + + -- Wait until test Completion + if (not SB.empty) then + wait until SB.empty; + end if; + TranscriptOpen(RESULTS_FILE, APPEND_MODE); + SetTranscriptMirror; + ReportAlerts; + TranscriptClose; + std.env.stop; + wait; + end process; + + output_check_prc : process(all) + begin + if falling_edge(clk) then + if (valid_out = '1') then + ready_out <= '1'; + SB.Check(data_out); + else + ready_out <= '0'; + end if; + end if; + end process; + + clock_prc : process + begin + clk <= '0'; + wait for 25 ns; + clk <= '1'; + wait for 25 ns; + end process; + + watchdog : process + begin + wait for 1 ms; + Alert("Test timeout", FAILURE); + std.env.stop; + end process; + +end architecture; \ No newline at end of file diff --git a/src/mem_ctrl.vhd b/src/mem_ctrl.vhd index 190ceba..824afa8 100644 --- a/src/mem_ctrl.vhd +++ b/src/mem_ctrl.vhd @@ -32,10 +32,11 @@ architecture arch of mem_ctrl is -- *SIGNAL DECLARATION* signal mem_read_data : std_logic_vector(DATA_WIDTH-1 downto 0); - signal delay_line : std_logic_vector(READ_LATENCY downto 0) := (others => '0'); + signal delay_line : std_logic_vector(READ_LATENCY-1 downto 0) := (others => '0'); signal fifo_empty : std_logic := '0'; - signal fifo_cnt : natural 0 to MAX_BURST_LENGTH := 0; - signal delay_cnt : natural 0 to READ_LATENCY := 0; + signal fifo_cnt : natural range 0 to MAX_BURST_LENGTH := 0; + signal delay_cnt : natural range 0 to READ_LATENCY := 0; + signal ready_in_sig, valid_out_sig : std_logic := '0'; begin @@ -49,27 +50,43 @@ begin port map ( clk => clk, addr => addr, - wen => not read, - ren => read, + wen => ready_in_sig and valid_in and (not read), + ren => ready_in_sig and valid_in and read, wr_data => data_in, rd_data => mem_read_data ); + + ready_in_sig <= '0' when (fifo_cnt - delay_cnt = 0) else '1'; + ready_in <= ready_in_sig; + valid_out_sig <= not fifo_empty; + valid_out <= valid_out_sig; + delay_line_prc : process(clk) begin if rising_edge(clk) then if (reset = '1') then - delay_line <= (others => '0'); - delay_cnt <= 0; + delay_line <= (others => '0'); + delay_cnt <= 0; else -- Shift Right - delay_line(READ_LATENCY-1 downto 0) <= delay_line(READ_LATENCY downto 1); - delay_line(READ_LATENCY) <= read; - - if (read = '1' and delay_line(1) = '0') then - delay_cnt <= delay_cnt + 1; - elsif (read = '0' and delay_line(1) = '1') then - delay_cnt <= delay_cnt - 1; + if (READ_LATENCY > 1) then + delay_line(READ_LATENCY-2 downto 0) <= delay_line(READ_LATENCY-1 downto 1); + delay_line(READ_LATENCY-1) <= ready_in_sig and valid_in and read; + + if ((ready_in_sig and valid_in and read) = '1' and delay_line(1) = '0') then + delay_cnt <= delay_cnt + 1; + elsif ((ready_in_sig and valid_in and read) = '0' and delay_line(1) = '1') then + delay_cnt <= delay_cnt - 1; + end if; + else + delay_line(0) <= ready_in_sig and valid_in and read; + + if ((ready_in_sig and valid_in and read) = '1' and delay_line(0) = '0') then + delay_cnt <= delay_cnt + 1; + elsif ((ready_in_sig and valid_in and read) = '0' and delay_line(0) = '1') then + delay_cnt <= delay_cnt - 1; + end if; end if; end if; end if; @@ -85,14 +102,10 @@ begin reset => reset, data_in => mem_read_data, write => delay_line(0), - read => ready_out, + read => ready_out and valid_out_sig, data_out => data_out, empty => fifo_empty, full => open, - free => fifo_cnt, + free => fifo_cnt ); - - ready_in <= '0' when (fifo_cnt + delay_cnt = MAX_BURST_LENGTH) else '1'; - valid_out <= not fifo_empty; - end architecture; \ No newline at end of file