---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: -- Design Name: -- Module Name: LCTest_Driver - Behavioral -- Project Name: -- Target Devices: -- Tool versions: -- Description: -- -- Dependencies: -- -- Revision: -- Revision 0.01 - File Created -- Additional Comments: -- ---------------------------------------------------------------------------------- -- =================================================================================================== -- =================================================================================================== library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.all; -- This module is responsible for controlling a sequence of tests as dictated by the parameters. It uses -- LCTest_Base to do the work. entity LCTest_Driver is Generic( REBEL_LENGTH_LB: integer := 9; REBEL_LENGTH_NB: integer := 272; MAX_INSERTION_POINT: integer := 255; MAX_TESTS_NB: integer := 8); Port ( Clk : in std_logic; RESET: in std_logic; LFSR_start: out std_logic; LFSR_ready: in std_logic; LFSR_init_seed: out std_logic; LFSR_next_seq: out std_logic; REBEL_Config_ins_point: out std_logic_vector(REBEL_LENGTH_LB-1 downto 0); TOP_test_num: out std_logic_vector(MAX_TESTS_NB-1 downto 0); LCTB_start: out std_logic; LCTB_ready: in std_logic; start: in std_logic; ready: out std_logic; TOP_skip_path: in std_logic); end LCTest_Driver; architecture beh of LCTest_Driver is type state_type is (idle, wait_LFSR, wait_LCT_Base); signal state_reg, state_next: state_type; signal ready_reg, ready_next: std_logic; signal LFSR_init_seed_reg, LFSR_init_seed_next: std_logic; signal REBEL_Config_ins_point_reg, REBEL_Config_ins_point_next: unsigned(REBEL_LENGTH_LB-1 downto 0); signal test_num_reg, test_num_next: unsigned(MAX_TESTS_NB-1 downto 0); begin -- State and register logic process(Clk, RESET) begin if (RESET = '1' ) then state_reg <= idle; ready_reg <= '1'; LFSR_init_seed_reg <= '1'; REBEL_Config_ins_point_reg <= to_unsigned(MAX_INSERTION_POINT, REBEL_LENGTH_LB); test_num_reg <= (others => '0'); elsif (Clk'event and Clk = '1') then state_reg <= state_next; ready_reg <= ready_next; LFSR_init_seed_reg <= LFSR_init_seed_next; REBEL_Config_ins_point_reg <= REBEL_Config_ins_point_next; test_num_reg <= test_num_next; end if; end process; process (state_reg, ready_reg, start, LFSR_init_seed_reg, REBEL_Config_ins_point_reg, LCTB_ready, LFSR_ready, TOP_skip_path, test_num_reg) begin state_next <= state_reg; ready_next <= ready_reg; LFSR_init_seed_next <= LFSR_init_seed_reg; REBEL_Config_ins_point_next <= REBEL_Config_ins_point_reg; test_num_next <= test_num_reg; LFSR_start <= '0'; LFSR_next_seq <= '0'; LCTB_start <= '0'; case state_reg is -- ===================== when idle => -- For each pulse of the start signal, carry out a LC test (with multiple samples if specified) if ( start = '1' ) then ready_next <= '0'; -- Load up the user-specified seed and configure the launch rows after a reset or anytime 'init_seed' is set. Note that -- we only need to do the LFSR scan once per test sequence. This is a recent change where I do NOT destroy the launch -- register values any longer, so we can do LOTS of tests with one LFSR scan op. Note the LFSR runs for 512 cycles -- while the REBEL scan op is only 272 cycles so we save quite a few cycles by reconfiguring the lauch rows only once per -- test sequence. if ( LFSR_init_seed_reg = '1' ) then LFSR_start <= '1'; REBEL_Config_ins_point_next <= to_unsigned(MAX_INSERTION_POINT, REBEL_LENGTH_LB); test_num_next <= (others => '0'); -- If all insertion points are processed, store current LFSR value (which is last one in last sequence) as the 'seed' -- value and load the launch rows with a new random sequence. elsif ( REBEL_Config_ins_point_reg = 0 ) then LFSR_start <= '1'; LFSR_next_seq <= '1'; REBEL_Config_ins_point_next <= to_unsigned(MAX_INSERTION_POINT, REBEL_LENGTH_LB); test_num_next <= test_num_reg + 1; -- Otherwise, keep using the same LFSR pattern and just decrement the insertion point. else REBEL_Config_ins_point_next <= REBEL_Config_ins_point_reg - 1; end if; -- During enrollment or authenication, we ALWAYS generate a PUFNum. However, during regeneration, the public data decides -- whether we test this path or not. Note that LCT_Base FSM MUST be ready so no need to check this. if ( TOP_skip_path = '0' ) then LCTB_start <= '1'; state_next <= wait_LCT_Base; -- Skip testing this path -- wait for the LFSR to finish if necessary. else state_next <= wait_LFSR; end if; end if; -- ===================== -- Skip this path. In some cases, the LFSR needs to be run to re-load the launch row vectors. Wait for it to finish. when wait_LFSR => LFSR_init_seed_next <= '0'; if ( LFSR_ready = '1' ) then ready_next <= '1'; state_next <= idle; end if; -- ===================== -- Wait for the test to be carried out and the PUFNum generated. NOTE: We start the LFSR here but it completes in LCTest_Base. when wait_LCT_Base => LFSR_init_seed_next <= '0'; if ( LCTB_ready = '1' ) then ready_next <= '1'; state_next <= idle; end if; end case; end process; -- WARNING: If LFSR_start and LFSR_init_seed are asserted at the same time, then you MUST use the _next in order for -- this to work to both start the LFSR and initialize it with the seed. LFSR_init_seed <= LFSR_init_seed_next; -- The insertion point must be available immediately when 'start' is asserted because LCTest_Base latches it into target -- on the first cycle. REBEL_Config_ins_point <= std_logic_vector(REBEL_Config_ins_point_next); ready <= ready_reg; TOP_test_num <= std_logic_vector(test_num_reg); end beh;