kv-be / pretty-vhdl

MIT License
0 stars 0 forks source link

sometimes pretty vhdl gets in eternal loop #21

Closed kv-be closed 5 months ago

kv-be commented 5 months ago

the following code (issue21.vhd) results in an eternal loop


-- Filename: tdi_read_control_tb.vhd

-- Copyright (c) 2014 Deltatec (www.deltatec.be)

-- This file is provided without any express or implied warranties, including, -- but not limited to, the implied warranties of merchantability and fitness -- for a particular purpose. It is not intended for use in life support -- appliances, devices, or systems. Use in such applications is expressly -- prohibited.--

-- Author: Benjamin Delhaye (BD)

-- History: 29/09/2020 (BD) : Creation of this file -- 03/04/2024 (PN) : Adaptation of the file for Hyp4U project

-- -- Description: -- Test bench for the TDI_READ_CONTROL block

-- Notes:



-- LIBRARY --

library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all;

library dt; use dt.dt_types_pkg.all;

use work.random_pkg.all;


-- ENTITY --

entity tdi_read_control_tb is generic ( G_SENSOR : string := "CARDINAL1280" ); end tdi_read_control_tb;


-- ARCHITECTURE --

architecture Behavioral of tdi_read_control_tb is --autoformat_off package tdi_pkg is new work.tdi_pkg generic map(G_SENSOR => G_SENSOR); use tdi_pkg.all;
--autoformat_on


-- TYPE --

type t_test_inputs is record test_title : string(1 to 512); tdi_type : std_logic_vector(1 downto 0); -- TDI type (0: none, 1: TDI6 HR, 2: TDI12, 3: TDI3 FR) dual_readout : std_logic; -- dual readout input register hs_plus_pan_mode : std_logic; -- if the tdi type is doing HS + PAN tdi_spectral_agglom : std_logic_vector(1 downto 0); -- (1: none, 2: SAx2, 3: SAx3) hs_nol : std_logic_vector(11 downto 0); -- Number of lines to emulate in the ANC FIFO HS pan_nol : std_logic_vector(11 downto 0); -- Number of lines to emulate in the ANC FIFO PAN hs_off : boolean; -- Parameter that allow to emulate that no HS frame is generated pan_off : boolean; -- Parameter that allow to emulate that no PAN frame is generated no_accum : integer; -- Number of accumulations to emulate no_accum_pan : integer; -- Number of accumulations to emulate for PAN frames (only used with CMV12K sensor) end record t_test_inputs;

constant C_BYTES_PER_LINE : integer := (C_DDR_PIXEL_SIZE_BIT * C_SENSOR_LINE_SIZE_PIXEL) / 8;

type t_test_cases is array (natural range <>) of t_test_inputs;

-- This type is used to define a table containing the ground truth about the accumulation and shift offset arrays type t_verification_array is array (natural range <>) of t_int_array(3 downto 0);

-- The following series of constants are the meaning of the indexes in the verification array constant C_TDI_12_TDI_11_PAN_IDX : integer := 0; constant C_TDI_12_SA2_IDX : integer := 1; constant C_TDI_12_SA3_IDX : integer := 2; constant C_TDI_3_FR_IDX : integer := 3; constant C_TDI_5_PAN_HR_TDI_6_HR_IDX : integer := 4; constant C_TDI_6_HR_SA2_IDX : integer := 5; constant C_TDI_6_HR_SA3_IDX : integer := 6; constant C_TDI_6_DR_IDX : integer := 7; constant C_TDI_6_DR_SA2_IDX : integer := 8; constant C_TDI_6_DR_SA3_IDX : integer := 9; constant C_PAN_MODE_IDX : integer := 10;

--The following series of constants are the meaning of the indexes at a given entry of the verification array constant C_SHIFT_OFFSET_IDX0 : integer := 0; constant C_SHIFT_OFFSET_IDX1 : integer := 1; constant C_ACCUM_OFFSET_IDX1 : integer := 2; constant C_ACCUM_OFFSET_IDX2 : integer := 3;

--TDI input parameters constant C_TDI_NONE : std_logic_vector(1 downto 0) := "00"; constant C_TDI6_HR : std_logic_vector(1 downto 0) := "01"; constant C_TDI12 : std_logic_vector(1 downto 0) := "10"; constant C_TDI3_FR : std_logic_vector(1 downto 0) := "11"; constant C_SA_NONE : std_logic_vector(1 downto 0) := "01"; constant C_SA2 : std_logic_vector(1 downto 0) := "10"; constant C_SA3 : std_logic_vector(1 downto 0) := "11";

-- This function initializes the verification array and returns a table function init_verification_array return t_verification_array is variable v_verification_array : t_verification_array(10 downto 0); begin -- v_verification_array(i)(0) = shift_offset(0), v_verification_array(i)(1) = shift_offset(1), v_verification_array(i)(2) = accum_offset(1), v_verification_array(i)(3) = accum_offset(2) -- v_verification_array(i)(4) = number of accumulation

  -- first all the entries of the verification array are filled with the number of bytes per line, then multiplications are made where there must be done
  for i in 0 to v_verification_array'length - 1 loop
     v_verification_array(i)(C_SHIFT_OFFSET_IDX0) := C_BYTES_PER_LINE;
     v_verification_array(i)(C_ACCUM_OFFSET_IDX1) := C_BYTES_PER_LINE;
     v_verification_array(i)(C_ACCUM_OFFSET_IDX2) := C_BYTES_PER_LINE;
  end loop;

  --C_TDI_12_TDI_11_PAN_IDX
  v_verification_array(C_TDI_12_TDI_11_PAN_IDX)(C_SHIFT_OFFSET_IDX0)     := 12 * v_verification_array(C_TDI_12_TDI_11_PAN_IDX)(C_SHIFT_OFFSET_IDX0);
  v_verification_array(C_TDI_12_TDI_11_PAN_IDX)(C_ACCUM_OFFSET_IDX2)     := 2 * v_verification_array(C_TDI_12_TDI_11_PAN_IDX)(C_ACCUM_OFFSET_IDX2);

  --C_TDI_12_SA2_IDX
  v_verification_array(C_TDI_12_SA2_IDX)(C_SHIFT_OFFSET_IDX0)            := 24 * v_verification_array(C_TDI_12_SA2_IDX)(C_SHIFT_OFFSET_IDX0);
  v_verification_array(C_TDI_12_SA2_IDX)(C_ACCUM_OFFSET_IDX2)            := 2 * v_verification_array(C_TDI_12_SA2_IDX)(C_ACCUM_OFFSET_IDX2);

  --C_TDI_12_SA3_IDX
  v_verification_array(C_TDI_12_SA3_IDX)(C_SHIFT_OFFSET_IDX0)            := 36 * v_verification_array(C_TDI_12_SA3_IDX)(C_SHIFT_OFFSET_IDX0);
  v_verification_array(C_TDI_12_SA3_IDX)(C_ACCUM_OFFSET_IDX2)            := 2 * v_verification_array(C_TDI_12_SA3_IDX)(C_ACCUM_OFFSET_IDX2);

  --C_TDI_3_FR_IDX
  v_verification_array(C_TDI_3_FR_IDX)(C_SHIFT_OFFSET_IDX0)              := 3 * v_verification_array(C_TDI_3_FR_IDX)(C_SHIFT_OFFSET_IDX0);
  v_verification_array(C_TDI_3_FR_IDX)(C_ACCUM_OFFSET_IDX2)              := 2 * v_verification_array(C_TDI_3_FR_IDX)(C_ACCUM_OFFSET_IDX2);

  --C_TDI_5_PAN_HR_TDI_6_HR_IDX
  v_verification_array(C_TDI_5_PAN_HR_TDI_6_HR_IDX)(C_ACCUM_OFFSET_IDX1) := 2 * v_verification_array(C_TDI_5_PAN_HR_TDI_6_HR_IDX)(C_ACCUM_OFFSET_IDX1);
  v_verification_array(C_TDI_5_PAN_HR_TDI_6_HR_IDX)(C_ACCUM_OFFSET_IDX2) := 2 * v_verification_array(C_TDI_5_PAN_HR_TDI_6_HR_IDX)(C_ACCUM_OFFSET_IDX1);

  --C_TDI_6_HR_SA2_IDX
  v_verification_array(C_TDI_6_HR_SA2_IDX)(C_ACCUM_OFFSET_IDX1)          := 2 * v_verification_array(C_TDI_6_HR_SA2_IDX)(C_ACCUM_OFFSET_IDX1);
  v_verification_array(C_TDI_6_HR_SA2_IDX)(C_ACCUM_OFFSET_IDX2)          := 2 * v_verification_array(C_TDI_6_HR_SA2_IDX)(C_ACCUM_OFFSET_IDX1);

  --C_TDI_6_HR_SA3_IDX
  v_verification_array(C_TDI_6_HR_SA3_IDX)(C_ACCUM_OFFSET_IDX1)          := 2 * v_verification_array(C_TDI_6_HR_SA3_IDX)(C_ACCUM_OFFSET_IDX1);
  v_verification_array(C_TDI_6_HR_SA3_IDX)(C_ACCUM_OFFSET_IDX2)          := 2 * v_verification_array(C_TDI_6_HR_SA3_IDX)(C_ACCUM_OFFSET_IDX1);

  --C_TDI_6_DR_IDX
  v_verification_array(C_TDI_6_DR_IDX)(C_ACCUM_OFFSET_IDX1)              := 0;

  --C_TDI_6_DR_SA2_IDX
  v_verification_array(C_TDI_6_DR_SA2_IDX)(C_ACCUM_OFFSET_IDX1)          := 0;

  --C_TDI_6_DR_SA3_IDX
  v_verification_array(C_TDI_6_DR_SA3_IDX)(C_ACCUM_OFFSET_IDX1)          := 0;

  --C_PAN_MODE_IDX
  v_verification_array(C_PAN_MODE_IDX)(C_ACCUM_OFFSET_IDX1)              := 0;
  v_verification_array(C_PAN_MODE_IDX)(C_ACCUM_OFFSET_IDX2)              := 0;
  return v_verification_array;

end function;

constant C_VERIFICATION_ARRAY : t_verification_array := init_verification_array;

-- This function provides the index to look at in the verification array given the shift offset array output by the DUT. -- It corresponds to the factor that multiplies the number of bytes per line at index 1 of the shift offset index. function get_verification_index (dual_readout : std_logic; shift_offset_array : t_slv_25b_array(1 downto 0)) return integer is variable v_factor : integer := 0; begin v_factor := to_integer(unsigned(shift_offset_array(1))) / C_BYTES_PER_LINE; case v_factor is when 12 => return C_TDI_12_TDI_11_PAN_IDX; when 24 => return C_TDI_12_SA2_IDX; when 36 => return C_TDI_12_SA3_IDX; when 3 => return C_TDI_3_FR_IDX; when 5 => return C_TDI_5_PAN_HR_TDI_6_HR_IDX; when 11 => if dual_readout = '1' then return C_TDI_6_DR_IDX; end if; return C_TDI_6_HR_SA2_IDX; when 17 => return C_TDI_6_HR_SA3_IDX; when 23 => return C_TDI_6_DR_SA2_IDX; when 35 => return C_TDI_6_DR_SA3_IDX; when 1 => return C_PAN_MODE_IDX; when others => assert False report "Failed to retrieve the index of the verification array, it seems that something went wront with the shift_offset_array!" severity failure; end case; end function;

-- This function checks that the shift offset array output by the DUT has the expected value at a given index of the verification array -- the index is retrieved from the function get_verification_index. -- The function returns False in case of error, True otherwise. function check_shift_array(shift_offset_array : t_slv_25b_array(1 downto 0); index : integer) return boolean is begin if unsigned(shift_offset_array(0)) /= to_unsigned(C_VERIFICATION_ARRAY(index)(C_SHIFT_OFFSET_IDX0), shift_offset_array(0)'length) then return False; else return True; end if; end function;

-- The function verifies that the accumulation offset array output by the DUT has the expected value. given the retrieved of the verification array. -- The function returns False in case of error, True otherwise. function check_accum_array(accum_offset_array : t_slv_25b_array(35 downto 0); index : integer; dual_readout : std_logic) return boolean is variable v_idx2 : integer := C_VERIFICATION_ARRAY(index)(C_ACCUM_OFFSET_IDX2); variable v_idx1 : integer := C_VERIFICATION_ARRAY(index)(C_ACCUM_OFFSET_IDX1); begin

  --The smallest index of the accumulation offset array is always 0
  if unsigned(accum_offset_array(0)) /= to_unsigned(0, accum_offset_array(0)'length) then
     return False;
  end if;

  if dual_readout = '1' then
     --If there is dual readout, the index 1 must also be 0
     if unsigned(accum_offset_array(1)) /= to_unsigned(0, accum_offset_array(1)'length) then
        return False;
     end if;
     --Then the entries of the accumulation offset array must be equal per pair
     for i in 2 to accum_offset_array'length - 2 loop
        if (i mod 2) = 0 then
           if unsigned(accum_offset_array(i)) /= to_unsigned(i * v_idx2/2, accum_offset_array(i)'length) then
              return False;
           end if;
           if unsigned(accum_offset_array(i + 1)) /= unsigned(accum_offset_array(i)) then
              return False;
           end if;
        end if;
     end loop;
     else
     for i in 1 to accum_offset_array'length - 1 loop
        if unsigned(accum_offset_array(i)) /= to_unsigned(i * v_idx1, accum_offset_array(i)'length) then
           return False;
        end if;
     end loop;
  end if;
  return True;

end function;


-- CONSTANT --

-- Test Constants constant C_CLK_PERIOD : time := 5 ns; -- 200MHz

-- These offsets are added to a frame counter to expect specific values in the frame start addresses present in the ANC FIFO data constant C_HS_ADDRESS_OFFSETS : unsigned(11 downto 0) := X"F00"; constant C_PAN_ADDRESS_OFFSETS : unsigned(11 downto 0) := X"E00";


-- FUNCTIONS --

--Returns a variable containing all the test inputs in a custom structure function get_test_title(test_inputs : t_test_inputs; test_id : integer) return string is variable test_title : string(test_inputs.test_title'range) := (others => NUL); constant C_TITLE : string := "" & CR & LF & "****" & CR & "Test " & integer'image(test_id) & CR & " tdi_type = " & integer'image(to_integer(unsigned(test_inputs.tdi_type))) & CR & " dual_readout = " & std_logic'image(test_inputs.dual_readout) & CR & " hs_plus_pan_mode = " & std_logic'image(test_inputs.hs_plus_pan_mode) & CR & " tdi_spectral_agglom = " & integer'image(to_integer(unsigned(test_inputs.tdi_spectral_agglom))) & CR & " hs_nol = " & integer'image(to_integer(unsigned(test_inputs.hs_nol))) & CR & " pan_nol = " & integer'image(to_integer(unsigned(test_inputs.pan_nol))) & CR & " no_accum = " & integer'image(test_inputs.no_accum) & CR & " no_accum_pan = " & integer'image(test_inputs.no_accum_pan) & CR & " hs_off = " & boolean'image(test_inputs.hs_off) & CR & " pan_off = " & boolean'image(test_inputs.pan_off) & CR & "****" & CR & LF; begin test_title(C_TITLE'range) := C_TITLE; return test_title; end function;

-- Returns a variable containing all the test inputs in a custom structure procedure init_test_inputs(test_id : inout integer; test_inputs : inout t_test_inputs; tdi_type, tdi_spectral_agglom : in std_logic_vector(1 downto 0); dual_readout, hs_plus_pan_mode : in std_logic; hs_nol, pan_nol : in std_logic_vector(11 downto 0); no_accum, no_accum_pan : in integer; hs_off, pan_off : in boolean) is begin test_inputs.tdi_type := tdi_type; test_inputs.dual_readout := dual_readout; test_inputs.hs_plus_pan_mode := hs_plus_pan_mode; test_inputs.tdi_spectral_agglom := tdi_spectral_agglom; test_inputs.hs_nol := hs_nol; test_inputs.pan_nol := pan_nol; test_inputs.hs_off := hs_off; test_inputs.pan_off := pan_off; test_inputs.no_accum := no_accum; test_inputs.no_accum_pan := no_accum_pan; test_inputs.test_title := get_test_title(test_inputs, test_id); test_id := test_id + 1; end procedure;

--Returns the nominal number of tests given the sensor type. function init_number_of_tests return integer is begin if G_SENSOR = "CARDINAL1280" then return 5; end if; if G_SENSOR = "CMV12K" then return 12; end if; end function;

-- Constants that are used to generate random TDI mode to test in the test cases. constant C_NO_TDI_MODES : integer := 13; constant C_TDI_MODES : t_slv_6b_array(C_NO_TDI_MODES - 1 downto 0) := (C_TDI_12, C_TDI_11_PAN, C_TDI_12_SA2, C_TDI_12_SA3, C_TDI_3_FR, C_TDI_5_PAN_HR, C_TDI_6_HR, C_TDI_6_HR_SA2, C_TDI_6_HR_SA3, C_TDI_6_DR, C_TDI_6_DR_SA2, C_TDI_6_DR_SA3, C_PAN_MODE );

-- Meaning of the fields in the tdi_mode signal constant C_TDI_TYPE : std_logic_vector(5 downto 4) := (others => '0'); constant C_HS_PLUS_PAN : std_logic_vector(3 downto 3) := "0"; constant C_TDI_SPECTRAL_AGGLOM : std_logic_vector(2 downto 1) := (others => '0'); constant C_DUAL_READOUT : std_logic_vector(0 downto 0) := "0";

-- Return a structure containing all the inputs of every test cases impure function init_test_cases return t_test_cases is constant C_NO_TESTS : integer := init_number_of_tests; constant C_NO_RANDOM_TESTS : integer := 10; variable test_cases : t_test_cases(C_NO_TESTS + C_NO_RANDOM_TESTS downto 0); variable i, j, v_nol, v_random_tdi : integer := 0; variable v_hs_off : boolean; variable v_pan_off : boolean; variable v_tdi_mode : std_logic_vector(5 downto 0); variable v_no_accum_pan : integer; variable v_no_accum : integer; begin --tdi_type, tdi_spectral_agglom, dual_readout, hs_plus_pan_mode, hs_nol, pan_nol, no_accum, no_accum_pan, hs_off, pan_off, init_test_inputs(i, test_cases(i), C_TDI_NONE, "01", '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI12 init_test_inputs(i, test_cases(i), C_TDI12, C_SA_NONE, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 2, 0, False, true); --TDI12_SA2 init_test_inputs(i, test_cases(i), C_TDI12, C_SA2, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI12_SA3 init_test_inputs(i, test_cases(i), C_TDI12, C_SA3, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true);

if G_SENSOR = "CARDINAL1280" then --TDI3_FR init_test_inputs(i, test_cases(i), C_TDI3_FR, C_SA_NONE, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --PAN init_test_inputs(i, test_cases(i), C_TDI_NONE, C_SA_NONE, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, true, False); end if;

if G_SENSOR = "CMV12K" then --PAN init_test_inputs(i, test_cases(i), C_TDI_NONE, C_SA_NONE, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 0, 50, true, False); --TDI11_PAN init_test_inputs(i, test_cases(i), C_TDI12, C_SA_NONE, '0', '1', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 5, False, False); --TDI6_HR init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA_NONE, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI5_PAN_HR init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA_NONE, '0', '1', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 10, False, False); --TDI6_HR_SA2 init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA2, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI6_HR_SA3 init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA3, '0', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI6_DR init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA_NONE, '1', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI6_DR_SA2 init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA2, '1', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); --TDI6_DR_SA3 init_test_inputs(i, test_cases(i), C_TDI6_HR, C_SA3, '1', '0', std_logic_vector(to_unsigned(100, 12)), std_logic_vector(to_unsigned(200, 12)), 50, 0, False, true); end if;

--Random for j in 0 to C_NO_RANDOM_TESTS - 1 loop v_hs_off := False; v_pan_off := True; v_random_tdi := randint(0, C_NO_TDI_MODES - 1); v_tdi_mode := C_TDI_MODES(v_random_tdi); v_no_accum_pan := 0;

  if G_SENSOR = "CARDINAL1280" then
     while v_tdi_mode(C_HS_PLUS_PAN'low) = '1' or v_tdi_mode(C_DUAL_READOUT'low) = '1' or v_tdi_mode(C_TDI_TYPE'range) = C_TDI6_HR loop
        v_random_tdi := randint(0, C_NO_TDI_MODES - 1);
        v_tdi_mode   := C_TDI_MODES(v_random_tdi);
     end loop;
  end if;

  v_no_accum := randint(20, 1000);

  if v_tdi_mode = C_TDI_11_PAN or v_tdi_mode = C_TDI_5_PAN_HR then
     v_pan_off := False;
     if v_tdi_mode = C_TDI_11_PAN then
        v_no_accum_pan := v_no_accum / 10;
        else
        v_no_accum_pan := v_no_accum / 5;
     end if;
  end if;

  if v_tdi_mode = C_PAN_MODE then
     v_hs_off  := True;
     v_pan_off := False;
     if G_SENSOR = "CMV12K" then
        v_no_accum_pan := v_no_accum;
        v_no_accum     := 0;
     end if;
  end if;

  init_test_inputs(i, test_cases(i), v_tdi_mode(C_TDI_TYPE'range), v_tdi_mode(C_TDI_SPECTRAL_AGGLOM'range), v_tdi_mode(C_DUAL_READOUT'low), v_tdi_mode(C_HS_PLUS_PAN'low),
  --                HS NOL                             PAN NOL                                              NO ACCUM
  std_logic_vector(to_unsigned(randint(1, 2048), 12)), std_logic_vector(to_unsigned(randint(1, 2048), 12)), v_no_accum, v_no_accum_pan, v_hs_off, v_pan_off);

end loop;

return test_cases(test_cases'length - 1 downto 1); -- required to implement index autoincrementation end function;


-- SIGNAL --

signal start_tests_d : std_logic; signal tdi_read_running_pan : std_logic; signal tdi_read_running : std_logic; signal anc_fifo_count : integer; signal verification_idx : integer; signal clk : std_logic := '0'; signal rst : std_logic := '1'; signal acquisition_running : std_logic; signal tdi_write_running : std_logic; signal anc_fifo_hs_dout : std_logic_vector(29 downto 0); signal anc_fifo_hs_re : std_logic; signal anc_fifo_hs_empty : std_logic; signal anc_fifo_pan_dout : std_logic_vector(29 downto 0); signal anc_fifo_pan_re : std_logic; signal anc_fifo_pan_empty : std_logic; signal tdi_type : std_logic_vector(1 downto 0); signal hs_plus_pan_mode : std_logic; signal tdi_spectral_agglom : std_logic_vector(1 downto 0); signal dual_readout : std_logic; signal tdi_accu_start : std_logic; signal tdi_accu_ready : std_logic; signal fb_first_frame_addr : t_slv_12b_array(35 downto 0); signal fb_frame_anc : std_logic_vector(17 downto 0); signal accum_offsets : t_slv_25b_array(35 downto 0); signal shift_offsets : t_slv_25b_array(1 downto 0); signal acc_frame_anc_id_ready : std_logic; signal acc_frame_anc_id : std_logic_vector(5 downto 0); signal fsm_error : std_logic; signal tdi_accu_start_pan : std_logic; signal tdi_accu_ready_pan : std_logic; signal fb_first_frame_addr_pan : t_slv_12b_array(35 downto 0); signal fb_frame_anc_pan : std_logic_vector(17 downto 0); signal accum_offsets_pan : t_slv_25b_array(35 downto 0); signal shift_offsets_pan : t_slv_25b_array(1 downto 0); signal acc_frame_anc_id_ready_pan : std_logic; signal acc_frame_anc_id_pan : std_logic_vector(5 downto 0); signal fsm_error_pan : std_logic; -- Testbench Signals signal clk_cntr : integer := 0; signal start_tests : std_logic := '0'; signal start_test_cond : boolean := False; signal stop_test_cond : boolean := False; signal tests_done : boolean := False; signal tests_cntr : integer := 0; signal test_inputs : t_test_inputs; signal tests_cases : t_test_cases(init_test_cases'length - 1 downto 0) := init_test_cases;

-- Configuration Registers Emulator

signal anc_fifo_hs_cntr : unsigned(11 downto 0) := (others => '0'); signal anc_fifo_hs_empty_d : std_logic; -- ANC FIFO PAN Emulator signal anc_fifo_pan_cntr : unsigned(11 downto 0) := (others => '0'); signal anc_fifo_pan_empty_d : std_logic;

-- TDI Accumulator Emulator signal tdi_accu_start_d : std_logic; signal tdi_accu_timer : integer := 0; signal tdi_accu_timer_delay : integer := randint(1, 2000); signal tdi_accu_start_cntr : integer := 0;

-- TDI Accumulator PAN Emulator signal tdi_accu_pan_start_d : std_logic; signal tdi_accu_pan_timer : integer := 0; signal tdi_accu_pan_timer_delay : integer := randint(1, 2000); signal tdi_accu_pan_start_cntr : integer := 0;

-- Output Parameters Check signal fb_ffa : t_slv_12b_array(35 downto 0); signal out_hs_cntr : integer := 0; signal out_pan_cntr : integer := 0;

signal tdi_accu : integer;


-- ATTRIBUTE --


-- BEGIN --

begin


-- Clock & Reset --

tests_done <= tests_cntr = tests_cases'length + 1; rst <= '0' after 5 * C_CLK_PERIOD;

process begin if not(tests_done) then clk <= '0'; wait for C_CLK_PERIOD/2; clk <= '1'; wait for C_CLK_PERIOD/2; else report "Simulation Success!"; wait; end if; end process;


-- Devices Under Test --

g_dut : if G_SENSOR = "CARDINAL1280" generate i_dut : entity work.tdi_read_control generic map( G_SENSOR => G_SENSOR ) port map( CLK => clk, -- Main Clock RST => rst, -- Main Reset ACQUISITION_RUNNING => acquisition_running, -- '1' enables TDI processing, '0' stops processing at the end of the frame being processed TDI_WRITE_RUNNING => tdi_write_running, -- High until the last frame of the acquisition is written in the DDR frame buffer TDI_READ_RUNNING => tdi_read_running, -- High until the TDI processing is done ANC_FIFO_HS_DOUT => anc_fifo_hs_dout, -- TDI ANC to add in the FIFO ANC_FIFO_HS_RE => anc_fifo_hs_re, -- FIFO TDI read enable ANC_FIFO_HS_EMPTY => anc_fifo_hs_empty, -- FIFO TDI empty flag ANC_FIFO_PAN_DOUT => anc_fifo_pan_dout, -- PAN ANC to add in the FIFO ANC_FIFO_PAN_RE => anc_fifo_pan_re, -- FIFO PAN read enable ANC_FIFO_PAN_EMPTY => anc_fifo_pan_empty, -- FIFO PAN empty flag TDI_TYPE => test_inputs.tdi_type, -- TDI Type (0: none, 1: TDI6 half rate, 2: TDI12, 3: TDI6 full rate) HS_PLUS_PAN_MODE => test_inputs.hs_plus_pan_mode, -- HS + PAN mode (only in vnir) TDI_SPECTRAL_AGGLOM => test_inputs.tdi_spectral_agglom, --"01": no SA, "10": SAx2 "11": SAx3 DUAL_READOUT => test_inputs.dual_readout, -- Two consecutive sensor images are added pixel by pixel before the TDI6 HR algo is applied TDI_ACCU_START => tdi_accu_start, -- Pulse '1' start the TDI Accumulation process TDI_ACCU_READY => tdi_accu_ready, -- '1' indicates that the TDI Accumulation process is ready for a new accumulation FB_FIRST_FRAME_ADDR => fb_first_frame_addr, -- Addresses in FB of the first frames line that need to be processed FB_FRAME_ANC => fb_frame_anc, -- Vector containing the ANC of the frames that need to be processed ACCUM_OFFSETS => accum_offsets, -- Array containing FB address offsets needed between each processed accumulation, PAN or TDI SHIFT_OFFSETS => shift_offsets, -- Array containing FB address offsets needed between each processed line (shift), PAN or TDI ACC_FRAME_ANC_ID_READY => acc_frame_anc_id_ready, -- Pulse indicating that the ANC ID is ready ACC_FRAME_ANC_ID => acc_frame_anc_id, -- Vector containing the ANC ID of the processed frame FSM_ERROR => fsm_error -- Asserted when FSM in undefined state ); elsif G_SENSOR = "CMV12K" generate i_dut_hs : entity work.tdi_read_control generic map( G_SENSOR => G_SENSOR ) port map( CLK => clk, -- Main Clock RST => rst, -- Main Reset ACQUISITION_RUNNING => acquisition_running, -- '1' enables TDI processing, '0' stops processing at the end of the frame being processed TDI_WRITE_RUNNING => tdi_write_running, -- High until the last frame of the acquisition is written in the DDR frame buffer TDI_READ_RUNNING => tdi_read_running, -- High until the TDI processing is done ANC_FIFO_HS_DOUT => anc_fifo_hs_dout, -- TDI ANC to add in the FIFO ANC_FIFO_HS_RE => anc_fifo_hs_re, -- FIFO TDI read enable ANC_FIFO_HS_EMPTY => anc_fifo_hs_empty, -- FIFO TDI empty flag ANC_FIFO_PAN_DOUT => (others => '0'), -- PAN ANC to add in the FIFO ANC_FIFO_PAN_RE => open, -- FIFO PAN read enable ANC_FIFO_PAN_EMPTY => '1', -- FIFO PAN empty flag TDI_TYPE => test_inputs.tdi_type, -- TDI Type (0: none, 1: TDI6 half rate, 2: TDI12, 3: TDI6 full rate) HS_PLUS_PAN_MODE => test_inputs.hs_plus_pan_mode, -- HS + PAN mode (only in vnir) TDI_SPECTRAL_AGGLOM => test_inputs.tdi_spectral_agglom, --"01": no SA, "10": SAx2 "11": SAx3 DUAL_READOUT => test_inputs.dual_readout, -- Two consecutive sensor images are added pixel by pixel before the TDI6 HR algo is applied TDI_ACCU_START => tdi_accu_start, -- Pulse '1' start the TDI Accumulation process TDI_ACCU_READY => tdi_accu_ready, -- '1' indicates that the TDI Accumulation process is ready for a new accumulation FB_FIRST_FRAME_ADDR => fb_first_frame_addr, -- Addresses in FB of the first frames line that need to be processed FB_FRAME_ANC => fb_frame_anc, -- Vector containing the ANC of the frames that need to be processed ACCUM_OFFSETS => accum_offsets, -- Array containing FB address offsets needed between each processed accumulation, PAN or TDI SHIFT_OFFSETS => shift_offsets, -- Array containing FB address offsets needed between each processed line (shift), PAN or TDI ACC_FRAME_ANC_ID_READY => acc_frame_anc_id_ready, -- Pulse indicating that the ANC ID is ready ACC_FRAME_ANC_ID => acc_frame_anc_id, -- Vector containing the ANC ID of the processed frame FSM_ERROR => fsm_error -- Asserted when FSM in undefined state );

  i_dut_pan : entity work.tdi_read_control
     generic map(
        G_SENSOR               => G_SENSOR
     )
     port map(
        CLK                    => clk,                        -- Main Clock
        RST                    => rst,                        -- Main Reset
        ACQUISITION_RUNNING    => acquisition_running,        -- '1' enables TDI processing, '0' stops processing at the end of the frame being processed
        TDI_WRITE_RUNNING      => tdi_write_running,          -- High until the last frame of the acquisition is written in the DDR frame buffer
        TDI_READ_RUNNING       => tdi_read_running_pan,       -- High until the TDI processing is done
        ANC_FIFO_HS_DOUT       => (others => '0'),            -- TDI ANC to add in the FIFO
        ANC_FIFO_HS_RE         => open,                       -- FIFO TDI read enable
        ANC_FIFO_HS_EMPTY      => '1',                        -- FIFO TDI empty flag
        ANC_FIFO_PAN_DOUT      => anc_fifo_pan_dout,          -- PAN ANC to add in the FIFO
        ANC_FIFO_PAN_RE        => anc_fifo_pan_re,            -- FIFO PAN read enable
        ANC_FIFO_PAN_EMPTY     => anc_fifo_pan_empty,         -- FIFO PAN empty flag
        TDI_TYPE               => C_TDI_NONE,                 -- TDI Type (0: none, 1: TDI6 half rate, 2: TDI12, 3: TDI6 full rate)
        HS_PLUS_PAN_MODE       => '0',                        -- HS + PAN mode (only in vnir)
        TDI_SPECTRAL_AGGLOM    => C_SA_NONE,                  --"01": no SA, "10": SAx2 "11": SAx3
        DUAL_READOUT           => '0',                        -- Two consecutive sensor images are added pixel by pixel before the TDI6 HR algo is applied
        TDI_ACCU_START         => tdi_accu_start_pan,         -- Pulse '1' start the TDI Accumulation process
        TDI_ACCU_READY         => tdi_accu_ready_pan,         -- '1' indicates that the TDI Accumulation process is ready for a new accumulation
        FB_FIRST_FRAME_ADDR    => fb_first_frame_addr_pan,    -- Addresses in FB of the first frames line that need to be processed 
        FB_FRAME_ANC           => fb_frame_anc_pan,           -- Vector containing the ANC of the frames that need to be processed 
        ACCUM_OFFSETS          => accum_offsets_pan,          -- Array containing FB address offsets needed between each processed accumulation, PAN or TDI
        SHIFT_OFFSETS          => shift_offsets_pan,          -- Array containing FB address offsets needed between each processed line (shift), PAN or TDI
        ACC_FRAME_ANC_ID_READY => acc_frame_anc_id_ready_pan, -- Pulse indicating that the ANC ID is ready
        ACC_FRAME_ANC_ID       => acc_frame_anc_id_pan,       -- Vector containing the ANC ID of the processed frame
        FSM_ERROR              => fsm_error_pan               -- Asserted when FSM in undefined state
     );

end generate g_dut;


-- Tests Sequencing --

-- Test restarted every 100 clock cycles start_test_cond <= true when clk_cntr = 2000 and tdi_accu_ready = '1' else False;

-- Test finished when no_accum have been performed --autoformat_off g_stop_test : if G_SENSOR = "CARDINAL1280" generate stop_test_cond <= true when (tdi_accu_start_cntr = test_inputs.no_accum) else False;
elsif G_SENSOR = "CMV12K" generate stop_test_cond <= true when (tdi_accu_start_cntr = test_inputs.no_accum) and (tdi_accu_pan_start_cntr = test_inputs.no_accum_pan) else False; end generate g_stop_test; --autoformat_on

process (clk) begin if rising_edge(clk) then if rst = '1' then start_tests <= '0'; test_inputs <= tests_cases(0); else clk_cntr <= clk_cntr + 1; start_tests_d <= start_tests;

        if stop_test_cond then
           start_tests <= '0';
           clk_cntr    <= 0;
        end if;

        if start_test_cond then
           tests_cntr <= tests_cntr + 1;
           if tests_cntr < tests_cases'length then

              start_tests <= '1';
              test_inputs <= tests_cases(tests_cntr);
              report tests_cases(tests_cntr).test_title;
           end if;
        end if;
     end if;
  end if;

end process;


-- CONFIGURATION REGISTERS EMULATOR --

-- Configure all the input register of the DUT process (clk) begin if rising_edge(clk) then if start_tests = '1' then tdi_type <= test_inputs.tdi_type; dual_readout <= test_inputs.dual_readout; hs_plus_pan_mode <= test_inputs.hs_plus_pan_mode; tdi_spectral_agglom <= test_inputs.tdi_spectral_agglom; end if; end if; end process;

-- Acquisition running p_acquisition_running : process (CLK) begin if rising_edge(CLK) then if rst = '1' then acquisition_running <= '0'; else if start_tests = '1' and start_tests_d = '0' then acquisition_running <= '1'; end if; if G_SENSOR = "CMV12K" then if (tdi_accu_start_cntr = test_inputs.no_accum) and (tdi_accu_pan_start_cntr = test_inputs.no_accum_pan) then acquisition_running <= '0'; end if; end if;

        if G_SENSOR = "CARDINAL1280" then
           if (tdi_accu_start_cntr = test_inputs.no_accum) then
              acquisition_running <= '0';
           end if;
        end if;
     end if;
  end if;

end process;

-- TDI Write running p_tdi_write_running : process (CLK) variable v_tdi_write_running_delay : integer; begin if rising_edge(CLK) then if rst = '1' then v_tdi_write_running_delay := randint(50, 125); tdi_write_running <= '0'; else if acquisition_running = '1' then tdi_write_running <= '1'; end if;

        if acquisition_running = '0' then
           v_tdi_write_running_delay := v_tdi_write_running_delay - 1;
           if v_tdi_write_running_delay = 0 then
              tdi_write_running <= '0';
              v_tdi_write_running_delay := randint(50, 125);
           end if;
        end if;
     end if;
  end if;

end process;


-- ANC FIFO HS EMULATOR --


anc_fifo_hs_empty <= '1' when (test_inputs.hs_off or (clk_cntr mod 256) = 0 or tdi_read_running = '0' or (tdi_accu_start_cntr = test_inputs.no_accum)) else '0';

process (clk) begin if rising_edge(clk) then

     if anc_fifo_hs_re = '1' then
        anc_fifo_hs_cntr                                <= anc_fifo_hs_cntr + 1;
        anc_fifo_hs_dout(C_ANC_FRAME_ADDRESS_POS'range) <= std_logic_vector(C_HS_ADDRESS_OFFSETS + anc_fifo_hs_cntr);
        anc_fifo_hs_dout(C_ANC_NBR_OF_LINES_POS'range)  <= test_inputs.hs_nol;
        anc_fifo_hs_dout(C_ANC_ANC_ID_POS'range)        <= std_logic_vector(anc_fifo_hs_cntr(5 downto 0));
     end if;

     anc_fifo_hs_empty_d <= anc_fifo_hs_empty;

     if acquisition_running = '0' then
        anc_fifo_hs_cntr <= (others => '0');
     end if;
  end if;

end process;


-- ANC FIFO PAN EMULATOR --

--autoformat_off g_pan_empty : if G_SENSOR = "CARDINAL1280" generate anc_fifo_pan_empty <= '1' when (test_inputs.pan_off or (clk_cntr mod 64) = 0 or tdi_read_running = '0' or (tdi_accu_start_cntr = test_inputs.no_accum)) else '0'; elsif G_SENSOR = "CMV12K" generate anc_fifo_pan_empty <= '1' when (test_inputs.pan_off or (clk_cntr mod 64) = 0 or tdi_read_running = '0' or (tdi_accu_pan_start_cntr = test_inputs.no_accum_pan)) else '0'; end generate g_pan_empty; --autoformat_on process (clk) begin if rising_edge(clk) then if anc_fifo_pan_re = '1' then anc_fifo_pan_cntr <= anc_fifo_pan_cntr + 1; anc_fifo_pan_dout(C_ANC_FRAME_ADDRESS_POS'range) <= std_logic_vector(C_PAN_ADDRESS_OFFSETS + anc_fifo_pan_cntr); anc_fifo_pan_dout(C_ANC_NBR_OF_LINES_POS'range) <= test_inputs.pan_nol; anc_fifo_pan_dout(C_ANC_ANC_ID_POS'range) <= std_logic_vector(anc_fifo_pan_cntr(5 downto 0)); end if;

     anc_fifo_pan_empty_d <= anc_fifo_pan_empty;

     if acquisition_running = '0' then
        anc_fifo_pan_cntr <= (others => '0');
     end if;
  end if;

end process;


-- TDI ACCUMULATOR EMULATOR --

p_accum : process (clk) begin if rising_edge(clk) then if rst = '1' then tdi_accu_ready <= '1'; end if; tdi_accu_timer <= tdi_accu_timer + 1; tdi_accu_start_d <= tdi_accu_start;

     if tdi_accu_start = '1' then
        tdi_accu_ready      <= '0';
        tdi_accu_timer      <= 0;
        tdi_accu_start_cntr <= tdi_accu_start_cntr + 1;

        elsif tdi_accu_timer = tdi_accu_timer_delay then
        tdi_accu_ready       <= '1';
        tdi_accu_timer       <= tdi_accu_timer; -- wait for the tdi_accu_start to be raised
        tdi_accu_timer_delay <= randint(1, 2000);
     end if;

     if tdi_read_running = '0' then
        tdi_accu_timer      <= 0;
        tdi_accu_start_cntr <= 0;
     end if;
  end if;

end process;


-- TDI ACCUMULATOR EMULATOR PAN --

g_accum_pan : if G_SENSOR = "CMV12K" generate process (clk) begin if rising_edge(clk) then tdi_accu_pan_timer <= tdi_accu_pan_timer + 1; tdi_accu_pan_start_d <= tdi_accu_start_pan;

        if tdi_accu_start_pan = '1' then
           tdi_accu_ready_pan      <= '0';
           tdi_accu_pan_timer      <= 0;
           tdi_accu_pan_start_cntr <= tdi_accu_pan_start_cntr + 1;

           elsif tdi_accu_pan_timer = tdi_accu_pan_timer_delay then
           tdi_accu_ready_pan       <= '1';
           tdi_accu_pan_timer       <= tdi_accu_pan_timer; -- wait for the tdi_accu_pan_start to be raised
           tdi_accu_pan_timer_delay <= randint(1, 2000);
        end if;

        if tdi_read_running_pan = '0' then
           tdi_accu_pan_timer      <= 0;
           tdi_accu_pan_start_cntr <= 0;
        end if;
     end if;
  end process;

end generate g_accum_pan;


-- ASSERTS --

g_assert_process : if G_SENSOR = "CARDINAL1280" generate

  process (CLK)
     variable v_anc_fifo_count   : integer;
     variable v_tdi_accu         : integer;
     variable v_verification_idx : integer;
     variable v_tdi_mode         : std_logic_vector(5 downto 0);
  begin
     v_anc_fifo_count := to_integer(anc_fifo_hs_cntr) - out_hs_cntr;

     if rising_edge(CLK) and RST = '0' then
        if acquisition_running = '0' then
           out_hs_cntr  <= 0;
           out_pan_cntr <= 0;
        end if;

        if acquisition_running = '1' then
           v_tdi_mode := tests_cases(tests_cntr - 1).tdi_type & tests_cases(tests_cntr - 1).hs_plus_pan_mode & tests_cases(tests_cntr - 1).tdi_spectral_agglom & tests_cases(tests_cntr - 1).dual_readout;
           v_tdi_accu := get_accum_factor(v_tdi_mode);
           tdi_accu <= v_tdi_accu;
        end if;

        -- FIFO Checks
        assert not(anc_fifo_hs_empty_d = '1' and anc_fifo_hs_re = '1') report "Trying to read FIFO while EMPTY" severity failure;
        assert not(anc_fifo_pan_empty_d = '1' and anc_fifo_pan_re = '1') report "Trying to read FIFO while EMPTY" severity failure;
        assert not(v_anc_fifo_count = v_tdi_accu and anc_fifo_hs_re = '1') report "Trying to read FIFO despite enough entry have been read" severity failure;
        -- Acumulator
        assert not(tdi_accu_ready = '0' and tdi_accu_start = '1') report "Trying to start ACCU when not ready" severity failure;
        assert not(tdi_accu_ready = '1' and tdi_accu_start_d = '1') report "AccuReady not pulled down after an AccuStart" severity failure;
        assert tdi_accu_start = acc_frame_anc_id_ready report "acc_frame_anc_id_ready must follow tdi_accu_start" severity failure;
        -- Status check 
        assert not(tdi_read_running = '0' and ((anc_fifo_hs_empty = '0' and tdi_write_running = '1'))) report "TDI_READ_RUNNING is high while it must not." severity failure;
        -- Outputs checks
        if tdi_accu_start = '1' then

           v_verification_idx := get_verification_index(test_inputs.dual_readout, shift_offsets);
           verification_idx <= v_verification_idx;

           -- if a multiple of Q TDI frames have been read, a TDI Accumulation must be started (highest priority)
           if (v_anc_fifo_count mod v_tdi_accu) = 0 and anc_fifo_hs_cntr /= 0 then
              out_hs_cntr <= out_hs_cntr + 1;

              assert unsigned(fb_frame_anc(C_FRAME_ANC_NOL'range)) = unsigned(test_inputs.hs_nol) report "TDI ANC nol not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_TDI_TYPE'range) = test_inputs.tdi_type report "TDI ANC tdi_type not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_TDI_SPECTRAL_AGGLOM'range) = test_inputs.tdi_spectral_agglom report "TDI ANC spectral agglomeration not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_DUAL_READOUT'low) = test_inputs.dual_readout report "TDI ANC dual readout not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_HS_PLUS_PAN_MODE'low) = test_inputs.hs_plus_pan_mode report "TDI ANC HS+PAN mode not correct" severity failure;

              assert acc_frame_anc_id = std_logic_vector(anc_fifo_hs_cntr(5 downto 0) - v_tdi_accu) report "ANC Id not as expected" severity failure;

              for i in 0 to v_tdi_accu - 1 loop
                 assert unsigned(fb_first_frame_addr(i)) = C_HS_ADDRESS_OFFSETS + out_hs_cntr + i report "Error in TDI FB FFA" severity failure;
              end loop;

              assert check_shift_array(shift_offsets, get_verification_index(test_inputs.dual_readout, shift_offsets)) report "Error in shift_offsets" severity failure;
              assert check_accum_array(accum_offsets, get_verification_index(test_inputs.dual_readout, shift_offsets), test_inputs.dual_readout) report "Error in accum_offsets" severity failure;
              else -- Raw case otherwises
              out_pan_cntr <= out_pan_cntr + 1;

              assert unsigned(fb_frame_anc(C_FRAME_ANC_NOL'range)) = unsigned(test_inputs.pan_nol) report "PAN ANC nol not correct" severity failure;
              assert unsigned(fb_frame_anc(C_FRAME_ANC_TDI_TYPE'range)) = 0 report "PAN ANC tdi_type not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_TDI_SPECTRAL_AGGLOM'range) = test_inputs.tdi_spectral_agglom report "PAN ANC spectral agglomeration not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_DUAL_READOUT'low) = test_inputs.dual_readout report "PAN ANC dual readout not correct" severity failure;
              assert fb_frame_anc(C_FRAME_ANC_HS_PLUS_PAN_MODE'low) = test_inputs.hs_plus_pan_mode report "PAN ANC HS+PAN mode not correct" severity failure;

              assert acc_frame_anc_id = std_logic_vector(anc_fifo_pan_cntr(5 downto 0) - 1) report "ANC Id not as expected" severity failure;

              assert unsigned(fb_first_frame_addr(0)) = C_PAN_ADDRESS_OFFSETS + out_pan_cntr report "Error in RAW FB FFA" severity failure;

              assert check_shift_array(shift_offsets, get_verification_index(test_inputs.dual_readout, shift_offsets)) report "Error in shift_offsets" severity failure;
              assert check_accum_array(accum_offsets, get_verification_index(test_inputs.dual_readout, shift_offsets), test_inputs.dual_readout) report "Error in accum_offsets" severity failure;
           end if;
        end if;
     end if;
  end process;

  elsif G_SENSOR = "CMV12K" generate
     process (CLK)
        variable v_anc_fifo_count   : integer;
        variable v_tdi_accu         : integer;
        variable v_verification_idx : integer;
        variable v_tdi_mode         : std_logic_vector(5 downto 0);
     begin
        v_anc_fifo_count := to_integer(anc_fifo_hs_cntr) - out_hs_cntr;

        if rising_edge(CLK) and RST = '0' then
           if acquisition_running = '0' then
              out_hs_cntr  <= 0;
              out_pan_cntr <= 0;
           end if;

           if acquisition_running = '1' then
              v_tdi_mode := tests_cases(tests_cntr - 1).tdi_type & tests_cases(tests_cntr - 1).hs_plus_pan_mode & tests_cases(tests_cntr - 1).tdi_spectral_agglom & tests_cases(tests_cntr - 1).dual_readout;
              v_tdi_accu := get_accum_factor(v_tdi_mode);
              tdi_accu <= v_tdi_accu;
           end if;

           -- FIFO Checks
           assert not(anc_fifo_hs_empty_d = '1' and anc_fifo_hs_re = '1') report "Trying to read FIFO while EMPTY" severity failure;
           assert not(anc_fifo_pan_empty_d = '1' and anc_fifo_pan_re = '1') report "Trying to read FIFO while EMPTY" severity failure;
           assert not(v_anc_fifo_count = v_tdi_accu and anc_fifo_hs_re = '1') report "Trying to read FIFO despite enough entry have been read" severity failure;
           -- Acumulator
           assert not(tdi_accu_ready = '0' and tdi_accu_start = '1') report "Trying to start ACCU when not ready" severity failure;
           assert not(tdi_accu_ready = '1' and tdi_accu_start_d = '1') report "AccuReady not pulled down after an AccuStart" severity failure;
           assert tdi_accu_start = acc_frame_anc_id_ready report "acc_frame_anc_id_ready must follow tdi_accu_start" severity failure;
           --Status check
           assert not(tdi_read_running = '0' and (anc_fifo_hs_empty = '0' and tdi_write_running = '1')) report "TDI_READ_RUNNING is high while it must not." severity failure;
           assert not(tdi_read_running_pan = '0' and (anc_fifo_pan_empty = '0' and tdi_write_running = '1')) report "TDI_READ_RUNNING is high while it must not." severity failure;
           -- Outputs checks
           if tdi_accu_start = '1' then

              v_verification_idx := get_verification_index(test_inputs.dual_readout, shift_offsets);
              verification_idx <= v_verification_idx;

              -- if a multiple of Q TDI frames have been read, a TDI Accumulation must be started (highest priority)
              if (v_anc_fifo_count mod v_tdi_accu) = 0 and anc_fifo_hs_cntr /= 0 then
                 out_hs_cntr <= out_hs_cntr + 1;

                 assert unsigned(fb_frame_anc(C_FRAME_ANC_NOL'range)) = unsigned(test_inputs.hs_nol) report "TDI ANC nol not correct" severity failure;
                 assert fb_frame_anc(C_FRAME_ANC_TDI_TYPE'range) = test_inputs.tdi_type report "TDI ANC tdi_type not correct" severity failure;
                 assert fb_frame_anc(C_FRAME_ANC_TDI_SPECTRAL_AGGLOM'range) = test_inputs.tdi_spectral_agglom report "TDI ANC spectral agglomeration not correct" severity failure;
                 assert fb_frame_anc(C_FRAME_ANC_DUAL_READOUT'low) = test_inputs.dual_readout report "TDI ANC dual readout not correct" severity failure;
                 assert fb_frame_anc(C_FRAME_ANC_HS_PLUS_PAN_MODE'low) = test_inputs.hs_plus_pan_mode report "TDI ANC HS+PAN mode not correct" severity failure;

                 assert acc_frame_anc_id = std_logic_vector(anc_fifo_hs_cntr(5 downto 0) - v_tdi_accu) report "ANC Id not as expected" severity failure;

                 for i in 0 to v_tdi_accu - 1 loop
                    assert unsigned(fb_first_frame_addr(i)) = C_HS_ADDRESS_OFFSETS + out_hs_cntr + i report "Error in TDI FB FFA" severity failure;
                 end loop;

                 assert check_shift_array(shift_offsets, get_verification_index(test_inputs.dual_readout, shift_offsets)) report "Error in shift_offsets" severity failure;
                 assert check_accum_array(accum_offsets, get_verification_index(test_inputs.dual_readout, shift_offsets), test_inputs.dual_readout) report "Error in accum_offsets" severity failure;
                 else -- Raw case otherwises
                 out_pan_cntr <= out_pan_cntr + 1;

                 assert unsigned(fb_frame_anc_pan(C_FRAME_ANC_NOL'range)) = unsigned(test_inputs.pan_nol) report "PAN ANC nol not correct" severity failure;
                 assert unsigned(fb_frame_anc_pan(C_FRAME_ANC_TDI_TYPE'range)) = 0 report "PAN ANC tdi_type not correct" severity failure;
                 assert fb_frame_anc_pan(C_FRAME_ANC_TDI_SPECTRAL_AGGLOM'range) = test_inputs.tdi_spectral_agglom report "PAN ANC spectral agglomeration not correct" severity failure;
                 assert fb_frame_anc_pan(C_FRAME_ANC_DUAL_READOUT'low) = test_inputs.dual_readout report "PAN ANC dual readout not correct" severity failure;
                 assert fb_frame_anc_pan(C_FRAME_ANC_HS_PLUS_PAN_MODE'low) = test_inputs.hs_plus_pan_mode report "PAN ANC HS+PAN mode not correct" severity failure;

                 assert acc_frame_anc_id_pan = std_logic_vector(anc_fifo_pan_cntr(5 downto 0) - 1) report "ANC Id not as expected" severity failure;

                 assert unsigned(fb_first_frame_addr_pan(0)) = C_PAN_ADDRESS_OFFSETS + out_pan_cntr report "Error in RAW FB FFA" severity failure;

                 assert check_shift_array(shift_offsets, get_verification_index('0', shift_offsets_pan)) report "Error in shift_offsets" severity failure;
                 assert check_accum_array(accum_offsets, get_verification_index('0', shift_offsets_pan), '0') report "Error in accum_offsets" severity failure;
              end if;
           end if;
        end if;
     end process;
  end generate g_assert_process;

  ---------
  -- END --
  ---------

end Behavioral;

kv-be commented 5 months ago

solved