---------------------------------------------------------------------------------- -- 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 ( GCLK : in std_logic; BTNC: in std_logic; LD0, LD1, LD2, LD3, LD4, LD5, LD6, LD7: out 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) ); 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; -- '9' accounts for the fact that we extend the REBEL row by 8 FFs, so we have 264 and need 9 bits to represent that value constant REBEL_LENGTH_LB: integer := 9; constant REBEL_LENGTH_NB: integer := 2**(REBEL_LENGTH_LB-1) + 8; 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. Range increases to 840 when output clocks are 75 MHz (Not sure about this -- actually -- depends on the VCO frequency, which is tuned depending on the M and D factors for the MMCM). Looked for a while but -- couldn't find the answer. CoreGen does not give this either. The clock division when 75 MHz is CLKOUT1_DIVIDE => 13, -- which suggests that the VCO runs at 975 (-1 parts can run between 600 MHz and 1200 MHz). So 1/(975*65) = 18.3 ps. -- So 15 ns period/18.3 ps = 820 steps. NOPE, this is too large looks closer to 730-740 from simulations. -- See ClkCoreGen/launch_capture_clk.vhd constant PHASE_SHIFT_LEN_NB: integer := 10; -- 100 MHz -- constant PHASE_SHIFT_RANGE: integer := 560; -- 75 MHz constant PHASE_SHIFT_RANGE: integer := 740; 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. The delay chain is 264 elements (worst case) with about -- 1 ns/FF, so with a 10 ns propagation period per clock cycle, we leave 128*10ns = 1.28 us for this to happen (more -- than enough). YOU MUST WAIT FOR THE FLUSH OUT TO OCCUR COMPLETELY b/c we use the flush out value as the PUT_init_val, -- which is used to determine when we achieve success in LCSweep constant MAX_PUT_WAIT_CYCLES_NB: integer := 7; constant MAX_PUT_WAIT_CYCLES: integer := 2**MAX_PUT_WAIT_CYCLES_NB; -- constant MAX_PUF_NUMS_NB: integer := 16; -- constant MAX_SAMS_LB: integer := 3; -- constant MAX_SAMS_NB: integer := 8; constant MAX_SWEEP_TRANSITIONS_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, SI_Capture: std_logic; signal SE_Launch, SE_Capture: std_logic; signal RESET_IN: 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; -- 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_QMOuts: std_logic_vector(REBEL_LENGTH_NB-1 downto 0); signal REBEL_QOuts: std_logic_vector(REBEL_LENGTH_NB-1 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(MAX_SWEEP_TRANSITIONS_NB-1 downto 0); signal REBEL_num_sweep_trans: std_logic_vector(MAX_SWEEP_TRANSITIONS_NB-1 downto 0); signal REBEL_target_FF: std_logic_vector(REBEL_LENGTH_LB-1 downto 0); signal LCT_start, LCT_ready: std_logic; signal DEBUG_LCT_dump_data: std_logic; signal DEBUG_out_ready: std_logic; signal DEBUG_print_all_strobes: std_logic; -- LCT_path_num and LCT_sam_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_sam_num: std_logic_vector(MAX_SAMS_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_num_req_sams_in: std_logic_vector(MAX_SAMS_NB-1 downto 0); -- NOT USED ANY MORE -- signal TOP_REBEL_results: std_logic_vector(REBEL_LENGTH_NB+2 downto 0); -- signal TOP_REBEL_results_Qout: std_logic_vector(REBEL_LENGTH_NB+2 downto 0); signal TOP_PUFNum: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal TOP_PUFNum_valid: std_logic; -- signal TOP_FinalRange: std_logic_vector(PHASE_SHIFT_LEN_NB-1 downto 0); signal TOP_back_or_forward_search: std_logic; signal TOP_enrollment: std_logic; begin -- ========================================================================================================= -- ************************************************* PARAMETERS ******************************************** -- ========================================================================================================= RESET_IN <= BTNC; TOP_back_or_forward_search <= '0'; -- This refers to the REBEL FF to which the transition must propagate, where 0 specifies the insertion point itself. -- THIS NUMBER CAN NOT BE LARGER THAN (REBEL_LENGTH_NB-DESIGN_WIDTH_NB). For example, if REBEL_LENGTH_NB is 16 and -- DESIGN_WIDTH_NB is 8, then the MAX VALUE is 8 because the rightmost PUT output (labeled 0) represents the insertion -- point and then there are 8 FFs to the right of this PUT FF so the index into the REBEL row that the LCTest engine -- looks at is (REBEL_LENGTH_NB - DESIGN_WIDTH_NB) + REBEL_ins_point - target_FF = (16-8)+0-8 = 0 (rightmost FF -- in REBEL row). 9 bits here but only values less than 16 are useful b/c of the clock cycle time constraint (10 ns of -- propagation delay along the delay chain is all that is allowed). REBEL_target_FF <= "000000001"; TOP_enrollment <= '1'; -- Check LCT_ready, and assert this for ONE clk. LCT_start <= '1'; -- DEBUG_LCT_dump_data to be used to get data DEBUG_out_ready <= '1'; DEBUG_print_all_strobes <= '1'; -- Data to look at -- REBEL_num_result_trans; -- REBEL_num_sweep_trans; -- TOP_PUFNum; -- TOP_PUFNum_valid; LD0 <= TOP_PUFNum(0); LD1 <= TOP_PUFNum(1); LD2 <= TOP_PUFNum(2); LD3 <= TOP_PUFNum(3); LD4 <= TOP_PUFNum(4); LD5 <= TOP_PUFNum(5); LD6 <= TOP_PUFNum(6); LD7 <= TOP_PUFNum(7); -- TOP_num_req_sams_in <= std_logic_vector(to_unsigned(1, MAX_SAMS_NB)); -- ========================================================================================================= -- ========================================================================================================= -- 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=>GCLK, 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(0), PUT_init_val=>PUT_init_val, -- DEBUG L_go_out=>L_go_out, C_go_out=>C_go_out); -- ========================================================================================================= -- Can NOT be ALL zeros -- don't have the LFSR with Zero implemented here LC_LFSR_seed <= (LC_LFSR_LEN_NB-1 downto 1 => '0') & '1'; -- 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, SI_Capture=>SI_Capture, SE_Capture=>SE_Capture, ClkEn_Capture=>ClkEn_Capture, REBEL_FDMode=>REBEL_FDMode, REBEL_QMOuts=>REBEL_QMOuts, REBEL_QOuts=>REBEL_QOuts); -- ===================================================================== -- 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, dummy_bit=>'0', insertion_point=>REBEL_ins_point, ready=>REBEL_ready, ScanEn=>SE_Capture, scan_bit=>SI_Capture); -- Whenever the REBEL configuration engine is running, disable clock gating (allow the FFs to respond to the clocks). DisableClkGating_Capture <= SE_Capture; -- Technically, we don't need these scan FFs because we can observe the Q outputs of the REBEL row directly. -- In fact, we don't even need scan FFs -- only a shift register here -- may change that later. The 3 is needed -- because REBEL has 3 state elements in the header -- Connecting REBEL_QOuts to the D inputs only to FORCE place and route to make these signals available for -- post route simulation -- DEBUG ONLY. Usually Q=>TOP_REBEL_results. -- TOP_REBEL_results <= "000" & REBEL_QMOuts; -- ResultsRow: entity work.MUXD_ScanFF_Row(beh) -- generic map (NUM_SFFs=>REBEL_LENGTH_NB+3) -- port map (D=>TOP_REBEL_results, SI=>REBEL_QOuts(0), SE=>SE_Capture, Clk=>Clk_Capture, ClkEn=>ClkEn_Capture, -- RESET=>RESET, SO=>open, Q=>TOP_REBEL_results_Qout); -- ========================================================================================================= -- The LCTest -- sequences LFSR, REBELController, LaunchCaptureEngine and REBEL scan out operations -- Each tick of LCT_start causes one entire sweep (inner-most loop) to be carried out (and one TOP_PUFNum -- to be calculated). The first LCT_start (from a reset) causes the LC_LFSR_seed_in to be installed in the -- LFSR. After n insertion points (outside loop) and m samples (middle loop) from the reset, the -- LC_LFSR_next_seq is pulsed to generate a new pattern. REBEL_target_FF determines the REBEL FF at which -- the sweep terminates -- it is relative from the current insertion point. LCTest: entity work.LCTest_Base(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_INSERTION_POINT=>MAX_INSERTION_POINT, MAX_SWEEP_TRANSITIONS_NB=>MAX_SWEEP_TRANSITIONS_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_start=>REBEL_start, REBEL_Config_ready=>REBEL_ready, REBEL_Config_ins_point_out=>REBEL_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=>LCT_start, ready=>LCT_ready, DEBUG_LCT_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, target_FF=>REBEL_target_FF, TOP_REBEL_results=>REBEL_QMOuts, LC_phaseshift_request=>FPA_requested_phase, TOP_PUFNum=>TOP_PUFNum, TOP_PUFNum_valid=>TOP_PUFNum_valid, TOP_back_or_forward_search=>TOP_back_or_forward_search, TOP_enrollment=>TOP_enrollment); end beh;