---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: -- Design Name: -- Module Name: LCTest_Base - 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 carrying out a single path and sample test. It keeps track of the -- current path (LFSR + insertion point) and sample number and is invoked by the DataCollectionEngine. -- Each time it is invoked, it proceeds to the next path and/or sample number. Each time it is invoked, -- it invokes the LCSweep engine, which configures the launch and REBEL rows and carries out a sequence -- of launch/capture tests each with the fine phase shift adjusted until the edge propagates to a target -- FF. LCSweep records the LC interval at which this happens, which represents the number of fine phase -- shifts it takes. entity LCTest_Base is Generic( DESIGN_WIDTH_LB: integer := 8; DESIGN_WIDTH_NB: integer := 256; PHASE_SHIFT_LEN_NB: integer := 10; PHASE_SHIFT_RANGE: integer := 560; PHASE_SHIFT_ZEROPHASE: integer := 0; REBEL_LENGTH_LB: integer := 9; REBEL_LENGTH_NB: integer := 264; MAX_INSERTION_POINT: integer := 255; MAX_SWEEP_TRANSITIONS_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_start: out std_logic; REBEL_Config_ready: in std_logic; REBEL_Config_ins_point_out: out std_logic_vector(REBEL_LENGTH_LB-1 downto 0); REBEL_num_result_trans: out std_logic_vector(MAX_SWEEP_TRANSITIONS_NB-1 downto 0); REBEL_num_sweep_trans: out std_logic_vector(MAX_SWEEP_TRANSITIONS_NB-1 downto 0); LC_start: out std_logic; LC_ready: in std_logic; start: in std_logic; ready: out std_logic; DEBUG_LCT_dump_data : out std_logic; DEBUG_out_ready: in std_logic; DEBUG_print_all_strobes: in std_logic; PUT_init_val: in std_logic; target_FF: in std_logic_vector(REBEL_LENGTH_LB-1 downto 0); TOP_REBEL_results: in std_logic_vector(REBEL_LENGTH_NB-1 downto 0); LC_phaseshift_request: inout std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); TOP_PUFNum: inout std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); TOP_PUFNum_valid: out std_logic; TOP_back_or_forward_search: in std_logic; TOP_enrollment: in std_logic); end LCTest_Base; architecture beh of LCTest_Base is type state_type is (idle, compute_target, go_LFSR_REBEL, wait_LFSR_REBEL, sweep_start, sweep_wait, check_valid); signal state_reg, state_next: state_type; signal LC_sweep_start, LC_sweep_ready: std_logic; signal ready_reg, ready_next: std_logic; signal LFSR_init_seed_reg, LFSR_init_seed_next: std_logic; signal LFSR_next_seq_reg, LFSR_next_seq_next: std_logic; signal REBEL_Config_ins_point_reg, REBEL_Config_ins_point_next: unsigned(REBEL_LENGTH_LB-1 downto 0); signal REBEL_Config_ins_point: std_logic_vector(REBEL_LENGTH_LB-1 downto 0); signal target_index_reg, target_index_next: unsigned(REBEL_LENGTH_LB-1 downto 0); signal PUFNum_reg, PUFNum_next: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal PUFNum_valid_reg, PUFNum_valid_next: std_logic; signal success_flag: std_logic; begin -- This module is responsible for sweeping across all LC intervals until an edge propagates to the target FF. LCSweep: entity work.LCSweep(beh) generic map (DESIGN_WIDTH_LB=>DESIGN_WIDTH_LB, DESIGN_WIDTH_NB=>DESIGN_WIDTH_NB, PHASE_SHIFT_LEN_NB=>PHASE_SHIFT_LEN_NB, PHASE_SHIFT_RANGE=>PHASE_SHIFT_RANGE, PHASE_SHIFT_ZEROPHASE=>PHASE_SHIFT_ZEROPHASE, REBEL_LENGTH_LB=>REBEL_LENGTH_LB, REBEL_LENGTH_NB=>REBEL_LENGTH_NB, MAX_SWEEP_TRANSITIONS_NB=>MAX_SWEEP_TRANSITIONS_NB) port map (Clk=>Clk, RESET=>RESET, REBEL_Config_ins_point=>REBEL_Config_ins_point, REBEL_num_result_trans=>REBEL_num_result_trans, REBEL_num_sweep_trans=>REBEL_num_sweep_trans, LC_start=>LC_start, LC_ready=>LC_ready, start=>LC_sweep_start, ready=>LC_sweep_ready, DEBUG_dump_data=>DEBUG_LCT_dump_data, DEBUG_out_ready=>DEBUG_out_ready, DEBUG_print_all_strobes=>DEBUG_print_all_strobes, PUT_init_val=>PUT_init_val, TOP_REBEL_results=>TOP_REBEL_results, target_index=>std_logic_vector(target_index_reg), back_or_forward_search=>TOP_back_or_forward_search, LC_phaseshift_request=>LC_phaseshift_request, success_flag=>success_flag, TOP_enrollment=>TOP_enrollment); -- State and register logic process(Clk, RESET) begin if (RESET = '1' ) then state_reg <= idle; ready_reg <= '1'; LFSR_init_seed_reg <= '1'; LFSR_next_seq_reg <= '0'; REBEL_Config_ins_point_reg <= to_unsigned(MAX_INSERTION_POINT, REBEL_LENGTH_LB); target_index_reg <= (others => '0'); PUFNum_reg <= (others => '0'); PUFNum_valid_reg <= '0'; elsif (Clk'event and Clk = '1') then state_reg <= state_next; ready_reg <= ready_next; LFSR_init_seed_reg <= LFSR_init_seed_next; LFSR_next_seq_reg <= LFSR_next_seq_next; REBEL_Config_ins_point_reg <= REBEL_Config_ins_point_next; target_index_reg <= target_index_next; PUFNum_reg <= PUFNum_next; PUFNum_valid_reg <= PUFNum_valid_next; end if; end process; process (state_reg, ready_reg, start, LFSR_init_seed_reg, LFSR_next_seq_reg, REBEL_Config_ins_point_reg, LC_sweep_ready, LFSR_ready, REBEL_Config_ready, target_FF, target_index_reg, LC_phaseshift_request, PUFNum_reg, PUFNum_valid_reg, success_flag, TOP_enrollment) begin state_next <= state_reg; ready_next <= ready_reg; LC_sweep_start <= '0'; LFSR_start <= '0'; REBEL_Config_start <= '0'; LFSR_init_seed_next <= LFSR_init_seed_reg; LFSR_next_seq_next <= LFSR_next_seq_reg; REBEL_Config_ins_point_next <= REBEL_Config_ins_point_reg; target_index_next <= target_index_reg; PUFNum_next <= PUFNum_reg; PUFNum_valid_next <= PUFNum_valid_reg; case state_reg is -- ===================== when idle => ready_next <= '1'; -- For each pulse of the start signal, carry out a LC test (LaunchCaptureEngine) if ( start = '1' ) then ready_next <= '0'; -- Load up the user-specified seed after a reset or anytime 'init_seed' is set. if ( LFSR_init_seed_reg = '1' ) then LFSR_start <= '1'; LFSR_next_seq_next <= '0'; REBEL_Config_ins_point_next <= to_unsigned(MAX_INSERTION_POINT, REBEL_LENGTH_LB); -- If all insertion points are processed, store current LFSR value (which is last one in last sequence) as the 'seed' value. -- 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 267 cycles so we save quite a few cycles by reconfiguring the lauch rows only once per -- test sequence. elsif ( REBEL_Config_ins_point_reg = 0 ) then LFSR_start <= '1'; LFSR_next_seq_next <= '1'; REBEL_Config_ins_point_next <= to_unsigned(MAX_INSERTION_POINT, REBEL_LENGTH_LB); -- Otherwise, keep using the same LFSR pattern. else REBEL_Config_ins_point_next <= REBEL_Config_ins_point_reg - 1; end if; state_next <= compute_target; end if; -- ===================== when compute_target => -- Note that we have NOT carried out a scan operation even in cases where one of these is set. The scan is done below. LFSR_init_seed_next <= '0'; LFSR_next_seq_next <= '0'; -- Compute the relative target FF index in REBEL row based on the current insertion point. This is used in LCSweep to decide -- when we've met the edge propagation requirement. REBEL_Config_ins_point counts from n-1 downto 0 from left to right in the -- REBEL row. We need to add (REBEL_LENGTH_NB-DESIGN_WIDTH_NB) to the REBEL_Config_ins_point and subtract the target_FF (which -- is to be interpreted as a relative reference from the insertion point). So if the REBEL row length is 264, the design width -- is 255 and the insertion point is 255 (leftmost FF in REBEL row), and target is 6 then add (264-256) = 8 to 255 = 263 and -- subtract 6 = FF 257. To target the insertion point itself, set target_FF to 0. target_index_next <= (REBEL_LENGTH_NB - DESIGN_WIDTH_NB) + unsigned(REBEL_Config_ins_point_reg) - unsigned(target_FF); state_next <= go_LFSR_REBEL; -- ===================== -- Start up the REBEL config scan engine. The REBEL scan op needs to be run once per insertion point. when go_LFSR_REBEL => if ( REBEL_Config_ready = '1' ) then REBEL_Config_start <= '1'; state_next <= wait_LFSR_REBEL; end if; -- ===================== -- Wait for the ready signals to both be re-asserted. when wait_LFSR_REBEL => if ( LFSR_ready = '1' and REBEL_Config_ready = '1' ) then state_next <= sweep_start; end if; -- ===================== -- Start the LCSweep state machine and wait for it to finish. when sweep_start => if ( LC_sweep_ready = '1' ) then LC_sweep_start <= '1'; state_next <= sweep_wait; end if; -- ===================== -- Wait for the sweep to finish when sweep_wait => if ( LC_sweep_ready = '1' ) then PUFNum_next <= LC_phaseshift_request; state_next <= check_valid; end if; -- ===================== -- For backward search, we start with long LC tests (which allows the edge to enter the scan chain easily) and work -- backwards, pushing the edge backwards toward the target FF -- stop when the edge is pushed JUST before the target FF. -- For the forward/backward search, we exit the first phase (forward search) when the edge just appears in the target FF -- (assuming there is only one transition). Here we allow LC tests to count NO transitions (for long paths) or a single -- transition. If more than 1 occurs during any LC test, we set the success_flag to false and return immediately. when check_valid => if ( success_flag = '1' ) then PUFNum_valid_next <= '1'; else PUFNum_valid_next <= '0'; end if; ready_next <= '1'; state_next <= idle; end case; end process; LFSR_init_seed <= LFSR_init_seed_reg; LFSR_next_seq <= LFSR_next_seq_reg; REBEL_Config_ins_point <= std_logic_vector(REBEL_Config_ins_point_reg); REBEL_Config_ins_point_out <= std_logic_vector(REBEL_Config_ins_point_reg); ready <= ready_reg; TOP_PUFNum <= PUFNum_reg; TOP_PUFNum_valid <= PUFNum_valid_reg; end beh;