---------------------------------------------------------------------------------- -- Company: -- Engineer: -- -- Create Date: 3/27/2014 -- Design Name: -- Module Name: Top - 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; entity Top is generic ( constant CTRL_REG_WIDTH_NB: integer := 32; constant DATA_REG_WIDTH_NB: integer := 32 ); port ( CLK_IN: in std_logic; RESET_IN_NOT: in std_logic; CtrlRegA: in std_logic_vector(CTRL_REG_WIDTH_NB-1 downto 0); DataRegA: out std_logic_vector(DATA_REG_WIDTH_NB-1 downto 0); DataRegB: out std_logic_vector(DATA_REG_WIDTH_NB-1 downto 0); DataRegC: out std_logic_vector(DATA_REG_WIDTH_NB-1 downto 0) ); end Top; architecture beh of Top is -- ========================================================================================================= -- ========================================================================================================= constant DESIGN_WIDTH_LB: integer := 8; constant DESIGN_WIDTH_NB: integer := 2**DESIGN_WIDTH_LB; constant MAX_INSERTION_POINT: integer := DESIGN_WIDTH_NB - 1; -- This constant determines HOW MANY FFs in the REBEL row are inspected for MULTIPLE transitions (from the inspection point). -- Setting to 16 causes xor to be carried out on 16 pairs of FFs, using a total of 17 FFs. _NB is the number of bits needed -- to count up to 16 constant XOR_INSPECTION_NUM_FFS_NB: integer := 5; constant XOR_INSPECTION_NUM_FFS: integer := 16; -- '9' accounts for the fact that we extend the REBEL row by 'XOR_INSPECTION_NUM_FFS' FFs beyond the 255 constant REBEL_LENGTH_LB: integer := 9; constant REBEL_LENGTH_NB: integer := 2**(REBEL_LENGTH_LB-1) + XOR_INSPECTION_NUM_FFS; -- A 32-bit LFSR constant LC_LFSR_LEN_LB: integer := 5; constant LC_LFSR_LEN_NB: integer := 2**LC_LFSR_LEN_LB; constant LC_LFSR_SCAN_CYCLES_LB: integer := DESIGN_WIDTH_LB + 1; -- For two rows, implementing launch-on-capture constant LC_LFSR_SCAN_CYCLES_NB: integer := 2**LC_LFSR_SCAN_CYCLES_LB; -- Phase shift values range from 0 to 560 when input clock is 100 MHz and output clocks (Clk_launch and Clk_capture) are -- 100 MHz, so we need 10 bits here. -- At 75 MHz, range increases to 740, computed from ClkCoreGen/launch_capture_clk.vhd as follows: -- 100MHz (input_clock) / 4 (DIVCLK_DIVIDE) * 39 (CLKFBOUT_MULT_F) / 13 (CLKOUT0_DIVIDE_F) = 75 MHz. Which means the -- fVCO is 100 / 4 * 39 = 975 MHz. (-1 parts can run between 600 MHz and 1200 MHz). -- The increment per FPA is then 1/(fVCO * 56) = 18.3 ps. So the number of FPAs is 15 ns/18.3 ps = 820 -- but in reality -- (from the simulations) it appears to be about 740, so I'm not sure what I doing wrong in my calc. -- At 50 MHz, 100MHz / 1 * 10 / 20 = 50 MHz. So fVCO is 1GHz which means the increment is 17.86 ps and number is -- 20 ns/17.86 = 1120 but this seems too high. constant PHASE_SHIFT_LEN_NB: integer := 11; -- 100 MHz -- constant PHASE_SHIFT_RANGE: integer := 560; -- 75 MHz -- constant PHASE_SHIFT_RANGE: integer := 740; -- 50 MHz (NOTE: NEED 11 bits for PHASE_SHIFT_LEN_NB for 1120). constant PHASE_SHIFT_RANGE: integer := 1120; constant PHASE_SHIFT_ZEROPHASE: integer := 0; -- These are the wait cycles after flush delay mode is enabled in LaunchCaptureEngine to allow for the initial -- value to propagate out the end of the delay chain. Note that I now chuck out a portion of the delay chain for -- analysis so our wait time is much smaller (and constant now). The number of FFs is given by XOR_INSPECTION_NUM_FFS -- above, which is currently set to 16 (so there are 17 master latches to propagate through once flush delay is -- enabled). With worst case delay through each master at 1 ns, we need to wait 17 ns. Flush delay is only enabled -- for half of the clock period, so at 50 MHz, clock persion is 20 ns, so 10ns is available. Therefore, we only need -- to wait two clock cycles for the PUT_init_val to flush out to the 0 element in the segment. Making it 3 just to -- be safe. According to the tool, the ModePrev/ModeNext path is 128ns worst case -- making this 6 for 140 ns constant MAX_PUT_WAIT_CYCLES_NB: integer := 3; constant MAX_PUT_WAIT_CYCLES: integer := 2**MAX_PUT_WAIT_CYCLES_NB - 2; -- constant MAX_PUF_NUMS_NB: integer := 16; -- Allows upto 128 samples to be averaged (10000000) constant MAX_NUM_SAMS_NB: integer := 8; constant MAX_TESTS_NB: integer := 8; -- GENERAL signal Clk_Launch: std_logic; signal Clk_Capture: std_logic; attribute clock_signal : string; attribute clock_signal of Clk_Launch : signal is "yes"; attribute clock_signal of Clk_Capture : signal is "yes"; signal ClkEn_Launch, ClkEn_Capture: std_logic; signal SI_Launch: std_logic; signal SE_Launch: std_logic; signal RESET_IN: std_logic; signal RESET_IN_SOFT: std_logic; signal RESET: std_logic; -- ClkGenCtrl signal Clk_Capture_Select: std_logic; -- LaunchCaptureEngine signal LC_start: std_logic; signal LC_ready: std_logic; signal FPA_requested_phase: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal DisableClkGating_Launch, DisableClkGating_Capture: std_logic; signal REBEL_FDMode: std_logic; signal FPA_PhaseAdjEn, FPA_IncDecCtrl, FPA_PhaseAdjDone: std_logic; signal PUT_init_val: std_logic; signal TOP_phase_shift_inc_dec: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); -- DEBUG signal L_go_out: std_logic; signal C_go_out: std_logic; -- LC_LFSR_Controller signal LC_LFSR_start, LC_LFSR_ready: std_logic; signal LC_LFSR_seed: std_logic_vector(LC_LFSR_LEN_NB-1 downto 0); signal LC_LFSR_init_seed, LC_LFSR_next_seq: std_logic; -- REBELController signal REBEL_start, REBEL_ready: std_logic; signal REBEL_load: std_logic; -- Include the 3 header bits here signal REBEL_ConfigIns: std_logic_vector(REBEL_LENGTH_NB+2 downto 0); signal REBEL_QMOuts: std_logic_vector(REBEL_LENGTH_NB-1 downto 0); signal REBEL_QMOuts_Seg: std_logic_vector(XOR_INSPECTION_NUM_FFS downto 0); -- LCTest -- Technically, the range of the insertion points are determined by DESIGN_WIDTH-1 downto 0. -- However, we need to compare this with registers with larger bit widths, and use this -- value in arithmetic ops with larger bit widths (see LCTest and REBELController). signal REBEL_ins_point: std_logic_vector(REBEL_LENGTH_LB-1 downto 0); signal REBEL_num_result_trans: std_logic_vector(XOR_INSPECTION_NUM_FFS_NB-1 downto 0); signal REBEL_target_FF: std_logic_vector(XOR_INSPECTION_NUM_FFS_NB-1 downto 0); signal TOP_test_num: std_logic_vector(MAX_TESTS_NB-1 downto 0); signal LCTD_start, LCTD_ready: std_logic; signal LCTB_start, LCTB_ready: std_logic; signal DEBUG_print_snapshots: std_logic; signal DEBUG_snapshot_ready: std_logic; signal DEBUG_print_PNs: std_logic; signal DEBUG_PN_ready: std_logic; signal DEBUG_processor_done_reading: std_logic; signal DEBUG_num_result_trans: std_logic_vector(3 downto 0); -- LCT_path_num are set in LCTest and used to construct the PN_RAM address -- signal LCT_path_num: std_logic_vector(MAX_PUF_NUMS_NB-1 downto 0); -- signal LCT_actual_path_num: std_logic_vector(ACTUAL_PATH_NUM_WIDTH_NB-1 downto 0); -- signal LCT_paths_pf_addr: std_logic_vector(PATH_RAM_ADDR_WIDTH_NB-1 downto 0); signal TOP_log_n_num_sams: std_logic_vector(MAX_NUM_SAMS_NB-1 downto 0); signal TOP_num_sams: std_logic_vector(MAX_NUM_SAMS_NB-1 downto 0); signal TOP_sam_num: std_logic_vector(MAX_NUM_SAMS_NB-1 downto 0); signal TOP_PUFNum: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal TOP_PUFNum_valid: std_logic; signal TOP_PUFNum_range_threshold: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal TOP_PUFNum_range: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal TOP_back_or_forward_search: std_logic; signal TOP_skip_path: std_logic; signal TOP_enrollment: std_logic; signal TOP_regeneration: std_logic; signal TOP_authentication: std_logic; begin -- ========================================================================================================= -- ************************************************* PARAMETERS ******************************************** -- ========================================================================================================= ProcessInputs: entity work.ProcessInputParams(beh) generic map(CTRL_REG_WIDTH_NB=>CTRL_REG_WIDTH_NB, XOR_INSPECTION_NUM_FFS_NB=>XOR_INSPECTION_NUM_FFS_NB, MAX_NUM_SAMS_NB=>MAX_NUM_SAMS_NB, LC_LFSR_LEN_NB=>LC_LFSR_LEN_NB, PHASE_SHIFT_LEN_NB=>PHASE_SHIFT_LEN_NB) port map (Clk=>Clk_Launch, RESET=>RESET, CtrlRegA=>CtrlRegA, RESET_IN_SOFT=>RESET_IN_SOFT, TOP_start_engine=>LCTD_start, REBEL_target_FF=>REBEL_target_FF, DEBUG_print_snapshots=>DEBUG_print_snapshots, DEBUG_print_PNs=>DEBUG_print_PNs, DEBUG_processor_done_reading=>DEBUG_processor_done_reading, TOP_log_n_num_sams=>TOP_log_n_num_sams, TOP_back_or_forward_search=>TOP_back_or_forward_search, LC_LFSR_seed=>LC_LFSR_seed, TOP_PUFNum_range_threshold=>TOP_PUFNum_range_threshold, TOP_phase_shift_inc_dec=>TOP_phase_shift_inc_dec, TOP_skip_path=>TOP_skip_path, TOP_enrollment=>TOP_enrollment, TOP_regeneration=>TOP_regeneration, TOP_authentication=>TOP_authentication); -- RESET_IN <= not RESET_IN_NOT; RESET_IN <= RESET_IN_SOFT; -- TOP_num_sams MUST be a power of 2, and obviously related to TOP_log_n_num_sams. User specifies TOP_log_n_num_sams -- and TOP_num_sams is computed from it. TOP_num_sams <= std_logic_vector(to_unsigned(1, MAX_NUM_SAMS_NB) sll to_integer(unsigned(TOP_log_n_num_sams))); DEBUG_num_result_trans <= REBEL_num_result_trans(3 downto 0) when unsigned(REBEL_num_result_trans) <= to_unsigned(15, 4) else "1111"; -- This statement creates 17 256-to-1 muxes that selects REBEL_QMOuts_Seg <= REBEL_QMOuts((to_integer(unsigned(REBEL_ins_point)) + XOR_INSPECTION_NUM_FFS) downto to_integer(unsigned(REBEL_ins_point))); -- ************** REBEL_LENGTH_NB DEPENDENCY ****************** -- DEBUG printing. Print out 17 bits of the snapshot (which properly accounts for the 16 FFs that are added to the row) -- So when REBEL_ins_point is 0, we print REBEL_QMOuts(16 downto 0) which is 17 bits. DataRegA <= REBEL_QMOuts_Seg -- DataRegA(31 downto 15) & "00000000000" -- DataRegA(14 downto 3) & PUT_init_val -- DataRegA(3) & DEBUG_PN_ready -- DataRegA(2) & DEBUG_snapshot_ready -- DataRegA(1) & LCTD_ready; -- DataRegA(0) DataRegB <= TOP_test_num -- DataRegB(31 downto 24) & REBEL_ins_point(7 downto 0) -- DataRegB(23 downto 16) & DEBUG_num_result_trans -- DataRegB(15 downto 12) & TOP_PUFNum_valid -- DataRegB(11) & TOP_PUFNum; -- DataRegB(10 downto 0) DataRegC <= "00" -- DataRegC(31 downto 30) & TOP_sam_num -- DataRegC(29 downto 22) & TOP_PUFNum_range -- DataRegC(21 downto 11) & FPA_requested_phase; -- DataRegC(10 downto 0) -- ========================================================================================================= -- ========================================================================================================= -- Zed has 100 MHz single ended clk. Generates two clks -- the unshifted version called Clk_Launch and a fine -- phase shifted version called Clk_Capture. Phase shifts are in increments of 17.86 ps. Clk_Capture_Select -- when '0' selects Clk_Launch to drive the REBEL row, otherwise Clk_Capture is selected. Clk_Capture_PhaseAdjEn -- enables phase adjustment. When asserted, setting Clk_Capture_IncDecCtrl at '0' decrements and at '1' increments -- phase. RESET output is synchronous with Clk -- it asserts when external world RESET is asserted, but is delayed -- in being deasserted -- waits for the DCMs to lock. NOTE: ALL LOGIC uses Clk_Launch (0 phase shifted version) -- except for REBEL row below. ClkGenCtrlMod: entity work.ClkGenCtrl(beh) port map (CLK_IN1=>CLK_IN, RESET_IN_DCM=>RESET_IN, psen=>FPA_PhaseAdjEn, psincdec=>FPA_IncDecCtrl, psdone=>FPA_PhaseAdjDone, Clk_Launch=>Clk_Launch, Clk_Capture_Select=>Clk_Capture_Select, Clk_Capture=>Clk_Capture, RESET=>RESET); -- The LC engine is responsible for coordinating the launch capture event AFTER the scan chains have been configured -- properly. FPA_requested_phase is the requested value of the fine phase shift of the Capture clock, and becomes -- the raw PUF number LCEngineMod: entity work.LaunchCaptureEngine(beh) generic map(PHASE_SHIFT_LEN_NB=>PHASE_SHIFT_LEN_NB, PHASE_SHIFT_RANGE=>PHASE_SHIFT_RANGE, PHASE_SHIFT_ZEROPHASE=>PHASE_SHIFT_ZEROPHASE, MAX_PUT_WAIT_CYCLES_NB=>MAX_PUT_WAIT_CYCLES_NB, MAX_PUT_WAIT_CYCLES=>MAX_PUT_WAIT_CYCLES) port map (Clk_Launch=>Clk_Launch, Clk_Capture=>Clk_Capture, RESET=>RESET, LC_start=>LC_start, requested_phase=>FPA_requested_phase, DisableClkGating_Launch=>DisableClkGating_Launch, DisableClkGating_Capture=>DisableClkGating_Capture, Clk_Capture_Sel=>Clk_Capture_Select, ready=>LC_ready, REBEL_FDMode=>REBEL_FDMode, FPA_PhaseAdjEn=>FPA_PhaseAdjEn, FPA_IncDecCtrl=>FPA_IncDecCtrl, FPA_PhaseAdjDone=>FPA_PhaseAdjDone, ClkEn_Launch=>ClkEn_Launch, ClkEn_Capture=>ClkEn_Capture, REBEL_QMOutRow=>REBEL_QMOuts_Seg(0), PUT_init_val=>PUT_init_val, -- DEBUG L_go_out=>L_go_out, C_go_out=>C_go_out); -- ========================================================================================================= -- LC_LFSRController is responsible for generating a random sequence for the launch FFs. It is controlled using -- LC_LFSR_init_seed (causes LC_LFSR_seed_in to be loaded into LFSR), next_seq (causes existing LFSR value to be -- saved and reloaded) and start. The engine that asserts start should check 'LC_LFSR_ready' first. LC_LFSRController: entity work.LC_LFSRController(beh) generic map(LFSR_LEN_LB=>LC_LFSR_LEN_LB, LFSR_LEN_NB=>LC_LFSR_LEN_NB, LFSR_SCAN_CYCLES_LB=>LC_LFSR_SCAN_CYCLES_LB, LFSR_SCAN_CYCLES_NB=>LC_LFSR_SCAN_CYCLES_NB) port map (Clk=>Clk_Launch, RESET=>RESET, start=>LC_LFSR_start, init_seed=>LC_LFSR_init_seed, next_seq=>LC_LFSR_next_seq, seed_in=>LC_LFSR_seed, ready=>LC_LFSR_ready, ScanEn=>SE_Launch, scan_bit=>SI_Launch); -- Whenever the LFSR engine is running, disable clock gating (allow the FFs to respond to the clocks). DisableClkGating_Launch <= SE_Launch; -- ===================================================================== -- DESIGN UNDER TEST with launch FFs and REBEL FFs AES: entity work.AES_3PipeStages(rtl) generic map (DESIGN_WIDTH_NB=>DESIGN_WIDTH_NB, REBEL_LENGTH_NB=>REBEL_LENGTH_NB) port map (Clk_Launch=>Clk_Launch, Clk_Capture=>Clk_Capture, RESET=>RESET, SI_Launch=>SI_Launch, SE_Launch=>SE_Launch, ClkEn_Launch=>ClkEn_Launch, REBEL_load=>REBEL_load, REBEL_ConfigIns=>REBEL_ConfigIns, ClkEn_Capture=>ClkEn_Capture, REBEL_FDMode=>REBEL_FDMode, REBEL_QMOuts=>REBEL_QMOuts); -- ===================================================================== -- REBEL controller: scans REBEL with configuration bits given by the 'insertion point'. 'insertion_point' is ZERO-based -- and from left to right, high order to low order. For example, choosing 0 for insertion point selects right-most REBEL FF REBELController: entity work.REBELController(beh) generic map (DESIGN_WIDTH_LB=>DESIGN_WIDTH_LB, DESIGN_WIDTH_NB=>DESIGN_WIDTH_NB, REBEL_LENGTH_LB=>REBEL_LENGTH_LB, REBEL_LENGTH_NB=>REBEL_LENGTH_NB) port map (Clk=>Clk_Capture, RESET=>RESET, do_config=>REBEL_start, insertion_point=>REBEL_ins_point, ready=>REBEL_ready, REBEL_load=>REBEL_load, REBEL_ConfigIns=>REBEL_ConfigIns); -- Whenever the REBEL configuration engine is running, disable clock gating (allow the FFs to respond to the clocks). DisableClkGating_Capture <= REBEL_load; -- ========================================================================================================= -- The LCTest_Driver -- handles LFSR operations LCTest_DriverMod: entity work.LCTest_Driver(beh) generic map (REBEL_LENGTH_LB=>REBEL_LENGTH_LB, REBEL_LENGTH_NB=>REBEL_LENGTH_NB, MAX_INSERTION_POINT=>MAX_INSERTION_POINT, MAX_TESTS_NB=>MAX_TESTS_NB) port map (Clk=>Clk_Launch, RESET=>RESET, LFSR_start=>LC_LFSR_start, LFSR_ready=>LC_LFSR_ready, LFSR_init_seed=>LC_LFSR_init_seed, LFSR_next_seq=>LC_LFSR_next_seq, REBEL_Config_ins_point=>REBEL_ins_point, TOP_test_num=>TOP_test_num, LCTB_start=>LCTB_start, LCTB_ready=>LCTB_ready, start=>LCTD_start, ready=>LCTD_ready, TOP_skip_path=>TOP_skip_path); -- LCTest_Base handles LaunchCaptureEngine and REBEL scan operations. Each tick of LCTB_start causes one entire sweep (inner-most loop) -- to be carried out (and one TOP_PUFNum -- to be calculated). After n samples (outter loop), an average PUFNum is computed. REBEL_target_FF -- determines the REBEL FF at which the sweep terminates -- it is relative from the current insertion point. LCTest_BaseMod: entity work.LCTest_Base(beh) generic map (PHASE_SHIFT_LEN_NB=>PHASE_SHIFT_LEN_NB, PHASE_SHIFT_RANGE=>PHASE_SHIFT_RANGE, PHASE_SHIFT_ZEROPHASE=>PHASE_SHIFT_ZEROPHASE, MAX_NUM_SAMS_NB=>MAX_NUM_SAMS_NB, XOR_INSPECTION_NUM_FFS=>XOR_INSPECTION_NUM_FFS, XOR_INSPECTION_NUM_FFS_NB=>XOR_INSPECTION_NUM_FFS_NB) port map (Clk=>Clk_Launch, RESET=>RESET, LFSR_ready=>LC_LFSR_ready, log_n_num_sams=>TOP_log_n_num_sams, num_sams=>TOP_num_sams, sam_num=>TOP_sam_num, REBEL_Config_start=>REBEL_start, REBEL_Config_ready=>REBEL_ready, REBEL_num_result_trans=>REBEL_num_result_trans, LC_start=>LC_start, LC_ready=>LC_ready, start=>LCTB_start, ready=>LCTB_ready, DEBUG_print_snapshots=>DEBUG_print_snapshots, DEBUG_snapshot_ready=>DEBUG_snapshot_ready, DEBUG_processor_done_reading=>DEBUG_processor_done_reading, DEBUG_print_PNs=>DEBUG_print_PNs, DEBUG_PN_ready=>DEBUG_PN_ready, PUT_init_val=>PUT_init_val, target_FF=>REBEL_target_FF, REBEL_QMOuts_Seg=>REBEL_QMOuts_Seg, LC_phaseshift_request=>FPA_requested_phase, TOP_PUFNum=>TOP_PUFNum, TOP_PUFNum_valid=>TOP_PUFNum_valid, TOP_PUFNum_range_threshold=>TOP_PUFNum_range_threshold, TOP_PUFNum_range=>TOP_PUFNum_range, TOP_back_or_forward_search=>TOP_back_or_forward_search, TOP_phase_shift_inc_dec=>TOP_phase_shift_inc_dec, TOP_authentication=>TOP_authentication, TOP_enrollment=>TOP_enrollment); end beh;