----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    
-- Design Name: 
-- Module Name:    ChlngLFSR_NoNorm - Behavioral 
-- Project Name: 
-- Target Devices: 
-- Tool versions: 
-- Description: 
--
-- Dependencies: 
--
-- Revision: 
-- Revision 0.01 - File Created
-- Additional Comments: 
--
----------------------------------------------------------------------------------


-- ===================================================================================================
-- This module controls the random values used to generate a specific challenge. When 'init_seed' is '1', 
-- the seed is placed into the LFSR_reg on the first cycle when 'start' is asserted. If 'init_seed' is '0', 
-- then a second signal, 'next_seq', is examined. If '1', then the LFSR is advanced one clock. 

-- The maximal LFSR generate 2^n values (INCLUDING the all zero case). The number of sense voltages in 
-- our PUF however may not be a power of two. The number is given by 'TOP_NUM_SMCS'. Here, I choose an 
-- LFSR length that meets the requirement that TOP_NUM_SMCS <= 2^n and skip all values that are greater 
-- than TOP_NUM_SMCS. This ensures that all values are visited (eventually). 

-- My initial plan is to use a 12-bit LFSR which can generate upto 4096 numbers. My array will have 4096 SMCs 
-- To generate more than 4095 pairings, I create two instantiations of this module. For the first 4095 number 
-- generations, I set the second copy 1 generation ahead of the first. Assuming no pseudo-randomness, the 
-- numbers generated for a 3-bit LFSR would be 
-- 1 2 3 4 5 6 7: First copy
-- 2 3 4 5 6 7 1: Second copy
-- I would limit this to 2^3-2 = 6 sequences, the 2^n-1 = 7 default minus 1 (the 1-ahead value).
-- Then the next 2-ahead sequence would be
-- 1 2 3 4 5 6 7: First copy (same sequence)
-- 3 4 5 6 7 1 2
-- I would limit this to 2^3-3 = 5 sequences, the 2^n-1 = 7 default minus 2 (the 2-ahead value). This strategy 
-- allows me to use all the original base entropy first before starting to reuse the base entropy. 
-- See PUF_DOCUMENTATION for more details here.
-- ===================================================================================================

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;

entity ChlngLFSR_NoNorm is
   generic(
      CLFSR_LEN_NB: integer := 12);
   port(
      Clk: in std_logic;
      RESET: in std_logic;
      start: in std_logic;
      init_seed: in std_logic;
      next_seq: in std_logic;
      seed_in: in std_logic_vector(CLFSR_LEN_NB-1 downto 0);
      RegionSizeMinus1: in std_logic_vector(CLFSR_LEN_NB-1 downto 0);
      ready: out std_logic;
      PRN: out std_logic_vector(CLFSR_LEN_NB-1 downto 0)
      );
end ChlngLFSR_NoNorm;

ARCHITECTURE beh of ChlngLFSR_NoNorm is
   type state_type is (idle, check_PRN);
   signal state_reg, state_next: state_type;

   signal ready_reg, ready_next: std_logic;

   signal LFSR_out: std_logic_vector(CLFSR_LEN_NB-1 downto 0);

   signal set_seed: std_logic;
   signal gen_bit: std_logic;

   begin

-- LFSR primitive
   LFSR12_A: entity work.LFSR12_wZERO(beh)
      generic map(LFSR_LEN_NB=>CLFSR_LEN_NB)
      port map (Clk=>Clk, RESET=>RESET, set_seed=>set_seed, gen_bit=>gen_bit, seed=>seed_in, LFSR_out=>LFSR_out);

-- State and register logic
   process(Clk, RESET)
      begin
      if ( RESET = '1' ) then
         state_reg <= idle;
         ready_reg <= '1';
      elsif ( Clk'event and Clk = '1' ) then
         state_reg <= state_next;
         ready_reg <= ready_next;
      end if; 
   end process;

-- Combo logic for state machine
   process (state_reg, init_seed, next_seq, start, LFSR_out, ready_reg, RegionSizeMinus1)
      begin
      state_next <= state_reg;

      ready_next <= ready_reg;

      set_seed <= '0';
      gen_bit <= '0';

      case state_reg is

-- =======================
         when idle =>
            ready_next <= '1';

-- Start the LFSR to generate PRN. 
            if ( start = '1' ) then
               ready_next <= '0';

-- Load the seed into the LFSR (which is stored in a register by ManageParams.vhd at startup).
               if ( init_seed = '1' ) then
                  set_seed <= '1';
                  state_next <= check_PRN;

-- Enable the LFSR to generate the next bit. 
               elsif ( next_seq = '1' ) then
                  gen_bit <= '1';
                  state_next <= check_PRN;
               end if;
            end if;

-- =======================
-- We need to run the LFSR until a value less than or equal to the 'RegionSizeMinus1' is produced 
         when check_PRN =>

-- Check that the generated number is less than the number of SMCs - 1 available.
            if ( unsigned(LFSR_out) <= unsigned(RegionSizeMinus1) ) then
               ready_next <= '1';
               state_next <= idle;

-- If LFSR has invalid value, generate next one and check again.
            else
               gen_bit <= '1';
            end if;
      end case;
   end process;

-- Set the PRN to the output of the LFSR
   PRN <= LFSR_out;
   ready <= ready_reg;
end beh;

