Commit 4415494c authored by Ille, Ondrej, Ing.'s avatar Ille, Ondrej, Ing.

Merge branch '9-rx-buffer-unit-test' into 'master'

Resolve "RX buffer unit test"

Closes #9

See merge request illeondr/CAN_FD_IP_Core!103
parents e4cbc488 6e95d74e
Pipeline #1163 passed with stages
in 2 minutes and 2 seconds
......@@ -142,6 +142,9 @@
-- 2. Separated "write_raw_increment" to "write_raw_intent" and
-- "write_raw_OK" which is valid only when there is enough
-- space in the buffer and overrun did not occur before!
-- 7.6.2018 Changed detection of buffer full to equality of
-- "read_pointer" and "write_pointer_raw" and nonzero amount
-- of frames stored.
--------------------------------------------------------------------------------
Library ieee;
......@@ -349,13 +352,13 @@ entity rxBuffer is
-- RX Buffer is empty (no frame is stored in it)
signal rx_empty_int : std_logic;
-- Internal number of free memory words. Updated during the frame after
-- each word is stored!
signal rx_mem_free_raw : natural range 0 to buff_size;
-- Number of free memory words available to SW after frame was committed.
signal rx_mem_free_int : natural range 0 to buff_size;
-- Number of free memory words calculated during frame storing, before
-- commit.
signal rx_mem_free_raw : natural range 0 to buff_size;
-- Indicator of at least one free word in RX FIFO!
signal is_free_word : boolean;
......@@ -386,6 +389,11 @@ entity rxBuffer is
-- if "data_overrun" did not occur during the frame!
signal commit_rx_frame : std_logic;
-- When overrun occurred at any point in the frame and some word was not
-- stored, frame can not be committed, and write_pointer must be moved
-- back to last committed value!
signal commit_overrun_abort : std_logic;
-- Indicates that read occurred, and that it is valid (there is something
-- to read), thus read pointer can be incremented.
signal read_increment : boolean;
......@@ -483,7 +491,8 @@ begin
false;
write_extra_ts <= true when ((rx_fsm = rxb_store_end_ts_low) or
(rx_fsm = rxb_store_end_ts_high))
(rx_fsm = rxb_store_end_ts_high)) and
(data_overrun_int = '0')
else
false;
......@@ -498,13 +507,18 @@ begin
false;
----------------------------------------------------------------------------
-- Store of the memory can be executed only if there is at least one
-- free word in the memory!
-- Store of new word can be executed only if there is space in the buffer.
-- We don't need exact amount of words. We only need to know if there is
-- space! When "read_pointer" and "write_pointer_raw" are equal, then
-- memory is either empty, or full! If there is no frame stored and pointers
-- are equal, then memory is empty! If there is at least one frame and
-- pointers are equal, then memory must be full!
----------------------------------------------------------------------------
is_free_word <= false when (rx_mem_free_raw = 0) else
is_free_word <= false when (read_pointer = write_pointer_raw and
message_count > 0)
else
true;
----------------------------------------------------------------------------
-- Overrun condition. Following conditions must be met:
-- 1. FSM wants to write to memory either to the position of
......@@ -512,12 +526,8 @@ begin
-- words which were already written, thus there is no need to watch
-- for overrun!
-- 2. There is no free word in the memory remaining!
-- 3. There is no read intent from SW. If there is read intent, and no
-- space in the buffer, data can be stored to the position which is
-- just being read!
----------------------------------------------------------------------------
overrun_condition <= true when (write_raw_intent and
(read_increment = false) and
(is_free_word = false))
else
false;
......@@ -614,8 +624,7 @@ begin
timestamp_capture <= (OTHERS => '0');
elsif (rising_edge(clk_sys)) then
timestamp_capture <= timestamp_capture;
if ((drv_rtsopt = RTS_END and rec_message_valid = '1') or
(drv_rtsopt = RTS_BEG and sof_pulse = '1'))
then
......@@ -644,40 +653,41 @@ begin
message_count <= message_count;
read_frame_counter <= read_frame_counter;
-- Start the counter only if there is something to read!
--------------------------------------------------------------------
-- Reading frame by user when there is active read and there is
-- something to read
--------------------------------------------------------------------
if (read_increment) then
----------------------------------------------------------------
-- During the read of FRAME_FORMAT word store the length
-- of the frame to "read_frame_counter", thus we know how much
-- we have to read before decrementing the "message_count".
----------------------------------------------------------------
if (read_frame_counter = 0) then
read_frame_counter <=
to_integer(unsigned(memory(read_pointer)
(RWCNT_H downto RWCNT_L)));
-- The last word is read during decrement from 1 to 0. We can
-- decrease number of frames then, NOT earlier! If decremented
-- earlier, reading of last frame would get stuck, since
-- read_pointer in memory access is incremented only with
-- non-zero message count! If "commit_frame_counter" is '1' we
-- don't decrement since new frame has arrived at the same
-- moment as reading has finished!
elsif (read_frame_counter = 1) then
if (commit_rx_frame = '0') then
message_count <= message_count - 1;
end if;
read_frame_counter <= read_frame_counter - 1;
-- Just count down during the read of all remaining words...
else
if (commit_rx_frame = '1') then
message_count <= message_count + 1;
end if;
read_frame_counter <= read_frame_counter - 1;
read_frame_counter <= read_frame_counter - 1;
end if;
end if;
--------------------------------------------------------------------
-- Manipulation of "message_count". When last word is read from
-- frame (read_frame_counter = 1 and read_increment), "message_count"
-- is decreased, when new frame is committed, message count
-- is increased. If both at the same time, no change since one frame
-- is added, next is removed!
--------------------------------------------------------------------
if (read_increment and (read_frame_counter = 1)) then
if (commit_rx_frame = '0') then
message_count <= message_count - 1;
end if;
elsif (commit_rx_frame = '1') then
message_count <= message_count + 1;
elsif (commit_rx_frame = '1') then
message_count <= message_count + 1;
end if;
end if;
......@@ -746,8 +756,11 @@ begin
-- Store first TIMESTAMP_U_W from beginning of frame.
--------------------------------------------------------------------
when rxb_store_beg_ts_high =>
rx_fsm <= rxb_store_data;
if (rec_abort = '1') then
rx_fsm <= rxb_idle;
else
rx_fsm <= rxb_store_data;
end if;
--------------------------------------------------------------------
-- Store DATA_W. If error ocurrs, abort the storing. If storing is
......@@ -794,16 +807,22 @@ begin
commit_proc : process(res_n, clk_sys)
begin
if (res_n = ACT_RESET) then
commit_rx_frame <= '0';
commit_rx_frame <= '0';
commit_overrun_abort <= '0';
elsif (rising_edge(clk_sys)) then
if (((rec_message_valid = '1' and drv_rtsopt = RTS_BEG) or
(rx_fsm = rxb_store_end_ts_high)) and (data_overrun_int = '0'))
(rx_fsm = rxb_store_end_ts_high)))
then
commit_rx_frame <= '1';
if (data_overrun_int = '0') then
commit_rx_frame <= '1';
else
commit_overrun_abort <= '1';
end if;
else
commit_rx_frame <= '0';
commit_rx_frame <= '0';
commit_overrun_abort <= '0';
end if;
end if;
......@@ -827,8 +846,8 @@ begin
write_pointer_raw <= 0;
write_pointer_extra_ts <= 0;
rx_mem_free_raw <= buff_size;
rx_mem_free_int <= buff_size;
rx_mem_free_raw <= buff_size;
elsif (rising_edge(clk_sys)) then
......@@ -839,25 +858,31 @@ begin
read_pointer <= (read_pointer + 1) mod buff_size;
end if;
--------------------------------------------------------------------
-- Commiting "write_pointer_raw", resetting or incrementing during
-- write...
-- Loading "write_pointer_raw" to "write_pointer" when frame is
-- committed.
--------------------------------------------------------------------
if (commit_rx_frame = '1') then
write_pointer <= write_pointer_raw;
elsif (rec_abort = '1' or overrun_condition) then
write_pointer_raw <= write_pointer;
end if;
elsif (write_raw_OK) then
--------------------------------------------------------------------
-- Updating "write_pointer_raw":
-- 1. Increment when word is written to memory.
-- 2. Reset when "rec_abort" is active (Error frame) or
-- frame finished and overrun occurred meanwhile. Reset to
-- value of last commited write pointer.
--------------------------------------------------------------------
if (write_raw_OK) then
write_pointer_raw <= (write_pointer_raw + 1) mod buff_size;
elsif (rec_abort = '1' or commit_overrun_abort = '1') then
write_pointer_raw <= write_pointer;
else
write_pointer_raw <= write_pointer_raw;
end if;
--------------------------------------------------------------------
-- Setting extra write pointer for write of timestamp from end of
-- frame...
......@@ -877,30 +902,36 @@ begin
--------------------------------------------------------------------
-- Calculating free memory. The same way as write_pointer_raw.
-- Free memory for the user is available only after the commit!
-- However, here we must consider also reads!
-- Calculate free memory internally (raw)
--------------------------------------------------------------------
if (commit_rx_frame = '1') then
if (read_increment) then
rx_mem_free_int <= rx_mem_free_raw + 1;
else
rx_mem_free_int <= rx_mem_free_raw;
end if;
elsif (rec_abort = '1') then
if (read_increment) then
if (read_increment) then
if (rec_abort = '1' or commit_overrun_abort = '1') then
rx_mem_free_raw <= rx_mem_free_int + 1;
else
elsif (not write_raw_OK) then
rx_mem_free_raw <= rx_mem_free_raw + 1;
end if;
else
if (rec_abort = '1' or commit_overrun_abort = '1') then
rx_mem_free_raw <= rx_mem_free_int;
elsif (write_raw_OK) then
rx_mem_free_raw <= rx_mem_free_raw - 1;
end if;
end if;
elsif (write_raw_OK and (not read_increment)) then
rx_mem_free_raw <= rx_mem_free_raw - 1;
elsif read_increment then
rx_mem_free_int <= rx_mem_free_int + 1;
rx_mem_free_raw <= rx_mem_free_raw + 1;
--------------------------------------------------------------------
-- Calculate free memory for user:
-- 1. Increment when user reads the frame.
-- 2. Load RAW value when comitt occurs
--------------------------------------------------------------------
if (read_increment) then
if (commit_rx_frame = '1') then
rx_mem_free_int <= rx_mem_free_raw + 1;
else
rx_mem_free_int <= rx_mem_free_int + 1;
end if;
elsif (commit_rx_frame = '1') then
rx_mem_free_int <= rx_mem_free_raw;
end if;
end if;
......@@ -977,7 +1008,7 @@ begin
-- Assertions
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----------------------------------------------------------------------------
-- RX Buffer size can be only powers of 2. Since modulo arithmetics is used
......@@ -1090,4 +1121,27 @@ begin
-- pragma translate_on
end process;
----------------------------------------------------------------------------
-- Checking consistency of "mem_free" calculation.
-- If buffer is idle (no storing is in progress), and message_count is 0,
-- then the buffer should be completely empty, thus, mem_free should be
-- equal to size of buffer.
----------------------------------------------------------------------------
--mem_free_calc_process : process(clk_sys)
--begin
-- pragma translate_off
-- if (rising_edge(clk_sys) and now /= 0 fs) then
-- if (rx_fsm = rxb_idle and message_count = 0 and rx_mem_free_int /=
-- buff_size and commit_rx_frame = '0')
-- then
-- report "Buffer should be empty, but 'rx_mem_free_raw' is " &
-- "not equal to 'buff_size'" severity error;
-- end if;
--
-- end if;
-- pragma translate_on
-- end process;
end architecture;
......@@ -2105,6 +2105,7 @@ package body CANtestLib is
-- Generate random data
-- Unused bytes of data can be set to 0
frame.data := (OTHERS => (OTHERS => '0'));
if (frame.data_length > 0) then
for i in 0 to frame.data_length - 1 loop
rand_logic_vect_v(rand_ctr, data_byte, 0.5);
......
......@@ -115,10 +115,11 @@ architecture rx_buf_unit_test of CAN_test is
signal rx_read_buff : std_logic_vector(31 downto 0);
-- Driving bus aliases
signal drv_rtsopt : std_logic := RTS_BEG;
signal drv_rtsopt : std_logic := RTS_END;
signal drv_read_start : std_logic := '0';
signal drv_clr_ovr : std_logic := '0';
----------------------------------------------------------------------------
-- Test specific signals
----------------------------------------------------------------------------
......@@ -138,6 +139,9 @@ architecture rx_buf_unit_test of CAN_test is
signal exit_imm_d_2 : boolean := false;
signal exit_imm_d_3 : boolean := false;
-- Additional random counter
signal rand_ctr_3 : natural range 0 to RAND_POOL_SIZE := 0;
----------------------------------------------------------------------------
-- Memory declarations for memories where data are read out
----------------------------------------------------------------------------
......@@ -216,7 +220,7 @@ architecture rx_buf_unit_test of CAN_test is
wait for 0 ns;
end loop;
end if;
-- At the end we need to move one more time
-- in_pointer <= in_pointer+1;
wait for 0 ns;
......@@ -283,6 +287,9 @@ architecture rx_buf_unit_test of CAN_test is
signal rec_abort :out std_logic;
signal rec_message_valid :out std_logic;
signal drv_rtsopt :in std_logic;
signal drv_clr_ovr :inout std_logic;
signal memory :inout eval_mem_test;
signal in_pointer :inout natural;
signal timestamp :in std_logic_vector(63 downto 0);
......@@ -291,14 +298,34 @@ architecture rx_buf_unit_test of CAN_test is
variable CAN_frame : SW_CAN_frame_type;
variable stored_ts : std_logic_vector(63 downto 0);
variable rand_val : natural;
variable abort_present : boolean;
variable abort_present : boolean := false;
variable id_out : std_logic_vector(28 downto 0);
begin
CAN_generate_frame(rand_ctr, CAN_frame);
stored_ts := (OTHERS => '0');
------------------------------------------------------------------------
-- Initiate frame storing by clearing possible overrun from before.
-- It might have happened that Overrun was generated at the same time
-- as there was intent abort. In that case, the frame was aborted,
-- overrun was not cleared and stayed till next frame. Storing of
-- next frame then evaluated overrun as present and did not store the
-- frame to input memory!
------------------------------------------------------------------------
drv_clr_ovr <= '1';
wait until rising_edge(clk_sys);
drv_clr_ovr <= '0';
wait for 1 ns;
-- Check that overrun was cleared
if (rx_data_overrun = '1') then
log("Overrun not cleared!", error_l, log_level);
end if;
------------------------------------------------------------------------
-- Initiate Frame by SOF pulse and store timestamp!
------------------------------------------------------------------------
sof_pulse <= '1';
if (drv_rtsopt = RTS_BEG) then
stored_ts := std_logic_vector(to_unsigned(
......@@ -308,16 +335,20 @@ architecture rx_buf_unit_test of CAN_test is
sof_pulse <= '0';
wait until rising_edge(clk_sys);
------------------------------------------------------------------------
-- Wait Random time (to emulate CAN ID). No real need to emulate real
-- length of Identifier! Emulate random error also during this time,
-- error frame may come also before any storing started and can not FUCK
-- UP the buffer.
------------------------------------------------------------------------
wait_rand_cycles(rand_ctr, clk_sys, 10, 50);
generate_random_abort(rand_ctr, rec_abort, clk_sys, abort_present, 0.1,
log_level);
if (abort_present) then
wait until rising_edge(clk_sys);
wait until rising_edge(clk_sys);
return;
end if;
......@@ -332,6 +363,7 @@ architecture rx_buf_unit_test of CAN_test is
rec_brs <= CAN_frame.brs;
rec_esi <= CAN_frame.esi;
rec_rtr <= CAN_frame.rtr;
log("Storing metadata", info_l, log_level);
wait until rising_edge(clk_sys);
......@@ -341,13 +373,15 @@ architecture rx_buf_unit_test of CAN_test is
store_metadata <= '0';
wait until rising_edge(clk_sys);
------------------------------------------------------------------------
-- Store data words
------------------------------------------------------------------------
if (CAN_frame.data_length > 0) then
for i in 0 to ((CAN_frame.data_length - 1) / 4) loop
-- Wait random time between store of individual data bytes!
wait_rand_cycles(rand_ctr, clk_sys, 10, 50);
-- Send signal to store data
store_data_word <= CAN_frame.data((i * 4) + 3) &
CAN_frame.data((i * 4) + 2) &
......@@ -363,6 +397,8 @@ architecture rx_buf_unit_test of CAN_test is
generate_random_abort(rand_ctr, rec_abort, clk_sys, abort_present,
0.05, log_level);
if (abort_present) then
wait until rising_edge(clk_sys);
wait until rising_edge(clk_sys);
return;
end if;
end loop;
......@@ -370,24 +406,42 @@ architecture rx_buf_unit_test of CAN_test is
wait_rand_cycles(rand_ctr, clk_sys, 30, 100);
------------------------------------------------------------------------
-- If we got here, no abort was generated, thus frame was stored OK!
-- We commit frame to the buffer and store it to test memories!
------------------------------------------------------------------------
rec_message_valid <= '1';
log("Frame valid!", info_l, log_level);
wait until rising_edge(clk_sys);
------------------------------------------------------------------------
-- Timestamp must be marked, if we are interested in END OF Frame
-- Timestamp!
------------------------------------------------------------------------
if (drv_rtsopt = RTS_END) then
CAN_frame.timestamp := timestamp;
else
CAN_frame.timestamp := stored_ts;
end if;
rec_message_valid <= '0';
------------------------------------------------------------------------
-- Check that during whole storing of this frame data overrun did not
-- occur!
------------------------------------------------------------------------
if (rx_data_overrun = '1') then
log("Data overrun appeared!", info_l, log_level);
------------------------------------------------------------------------
-- If overrun did not happend, insert frame to input test memory!
------------------------------------------------------------------------
else
insert_frame_test_mem(CAN_frame, memory, in_pointer);
end if;
wait until rising_edge(clk_sys);
rec_message_valid <= '0';
wait until rising_edge(clk_sys);
insert_frame_test_mem(CAN_frame, memory, in_pointer);
wait until rising_edge(clk_sys);
end procedure;
......@@ -401,6 +455,7 @@ architecture rx_buf_unit_test of CAN_test is
signal drv_read_start :inout std_logic;
signal clk_sys :in std_logic;
signal out_mem :out eval_mem_test;
signal in_mem :in eval_mem_test;
signal out_pointer :inout natural
)is
variable rwcnt : natural;
......@@ -414,6 +469,14 @@ architecture rx_buf_unit_test of CAN_test is
for i in 0 to rwcnt loop
drv_read_start <= '1';
out_mem(out_pointer) <= buff_out;
-- Check that word is exactly matching the word in in_mem at the
-- same position
if (buff_out /= in_mem(out_pointer)) then
log("Buffer FUCKED UP, inex: " & integer'image(out_pointer),
error_l, log_level);
end if;
out_pointer <= out_pointer + 1;
wait until rising_edge(clk_sys);
drv_read_start <= '0';
......@@ -421,7 +484,8 @@ architecture rx_buf_unit_test of CAN_test is
end loop;
end procedure;
----------------------------------------------------------------------------
-- Compare contents of input and output memory, if data stored to the buffer
-- are equal to data read from the buffer!
......@@ -505,8 +569,10 @@ begin
false;
drv_bus(DRV_READ_START_INDEX) <= drv_read_start;
drv_bus(DRV_RTSOPT_INDEX) <= drv_rtsopt;
drv_bus(DRV_RTSOPT_INDEX) <= drv_rtsopt;
drv_bus(DRV_CLR_OVR_INDEX) <= drv_clr_ovr;
----------------------------------------------------------------------------
-- Stimuli generator - Main test process
----------------------------------------------------------------------------
......@@ -521,11 +587,6 @@ begin
reset_test(res_n, status, run, stim_errs);
log("Restarted RX Bufrer test", info_l, log_level);
print_test_info(iterations, log_level, error_beh, error_tol);
log("Consider adding RX Buffer model into this testbench!", warning_l,
log_level);
log("Note that RX buffer content is NOT initialized on purpose!" &
"If initialized during reset, it is impossible to do" &
"synthesis into RAM!", warning_l, log_level);
------------------------------------------------------------------------
-- Main loop of the test
......@@ -534,24 +595,34 @@ begin
while (loop_ctr < iterations or exit_imm)
loop
--------------------------------------------------------------------
-- Change setting for timestamp options (store timestamp
-- at beginning or end of frame)
--------------------------------------------------------------------
if (drv_rtsopt = RTS_BEG) then
drv_rtsopt <= RTS_END;
else
drv_rtsopt <= RTS_BEG;
end if;
--------------------------------------------------------------------
-- Start generating the frames on Input as long as there is enough
-- space available in the common memory
-- space available in the common memory.
--------------------------------------------------------------------
while (in_mem_full = false) loop
--while (rx_message_count = "00000000000") loop
-- Now buffer has for sure space. Frame is inserted into the
-- RX Buffer, Model and stored also into common memory
insert_frame_to_RX_Buffer(rand_ctr, clk_sys, rec_ident_in,
rec_dlc_in, rec_frame_type_in, rec_ident_type_in, rec_brs, rec_esi,
rec_is_rtr, sof_pulse, store_metadata, store_data, store_data_word,
rec_abort, rec_message_valid, in_mem, in_pointer, timestamp,
log_level);
rec_dlc_in, rec_frame_type_in, rec_ident_type_in, rec_brs,
rec_esi, rec_is_rtr, sof_pulse, store_metadata, store_data,
store_data_word, rec_abort, rec_message_valid, drv_rtsopt,
drv_clr_ovr, in_mem, in_pointer, timestamp, log_level);
end loop;
-- Now input memory is full
-- We need to wait for Data reader to read all frames into common
-- memory from rx buffer and its model. Then it checks data
-- memory from rx buffer. Then it checks data
-- consistency and next iteration can start
wait until iterati