----------------------------------------------------------------------------------
-- 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: 
--
----------------------------------------------------------------------------------


-- ===================================================================================================
-- See comments in ChlngLFSR_NoNorm.vhd. This one implements the n-Ahead functionality.
-- ===================================================================================================

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

entity ChlngLFSR_nAhead_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);
      set_n_ahead_val: in std_logic; 
      inc_n_ahead: in std_logic; 
      val_to_set: in std_logic_vector(CLFSR_LEN_NB-1 downto 0);
      n_ahead_setting: out 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_nAhead_NoNorm;

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

   signal ready_reg, ready_next: std_logic;

   signal init_seed_reg, init_seed_next: std_logic;
   signal n_ahead_setting_reg, n_ahead_setting_next: unsigned(CLFSR_LEN_NB-1 downto 0);
   signal n_ahead_cnt_reg, n_ahead_cnt_next: unsigned(CLFSR_LEN_NB-1 downto 0);

   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, n bit polynomial
   LFSR12_B: 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;
         init_seed_reg <= '0';
         n_ahead_setting_reg <= (CLFSR_LEN_NB-1 downto 1 =>'0') & (0=>'1');
         n_ahead_cnt_reg <= (others => '0');
         ready_reg <= '1';
      elsif ( Clk'event and Clk = '1' ) then
         state_reg <= state_next;
         init_seed_reg <= init_seed_next;
         n_ahead_setting_reg <= n_ahead_setting_next;
         n_ahead_cnt_reg <= n_ahead_cnt_next;
         ready_reg <= ready_next;
      end if; 
   end process;

-- Combo logic for state machine
   process (state_reg, init_seed, init_seed_reg, next_seq, start, LFSR_out, ready_reg, set_n_ahead_val, inc_n_ahead, 
      val_to_set, n_ahead_setting_reg, n_ahead_cnt_reg, RegionSizeMinus1)
      begin
      state_next <= state_reg;

      ready_next <= ready_reg;

      init_seed_next <= init_seed_reg;

      n_ahead_setting_next <= n_ahead_setting_reg;
      n_ahead_cnt_next <= n_ahead_cnt_reg;

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

      case state_reg is

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

-- One or the other of these can occur but not both simultaneously (controlled by BitGenDriver). THIS ONLY
-- SETS the n_ahead value, it does NOT cause n_head skipping to occur. This happens ONLY when 'init_seed'
-- is set.
            if ( set_n_ahead_val = '1' ) then
               n_ahead_setting_next <= unsigned(val_to_set);
            elsif ( inc_n_ahead = '1' ) then
               n_ahead_setting_next <= n_ahead_setting_reg + 1;
            end if;

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

-- Initialize n_ahead_cnt for use when 'init_seed' is set to '1'.
               n_ahead_cnt_next <= (others => '0');

-- Handles case where we assert 'init_seed' and 'start', and both are released. Need to remember if
-- 'init_seed' was asserted below.
               init_seed_next <= init_seed;

-- Load the seed into the LFSR in this cycle and commence 'n_ahead' skipping in the following state
-- if n_head_setting is not 0. 
               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 AND we've moved 
-- ahead the requested number of numbers (if any). 
         when check_PRN =>

-- Check that the generated number is less than the number of SMCs available. NOTE that RegionSizeMinus1 is always
-- 1 less than a power of two, e.g., is 4095 for an CUBE size of 4096 SMCs.
            if ( unsigned(LFSR_out) <= unsigned(RegionSizeMinus1) ) then

-- If next_seq is set to '1' (init_seed_reg is 0) or if init_seed_reg is 1 but n_ahead_setting is 0, then we
-- are done since we have successfully produced a value.
               if ( init_seed_reg = '0' or n_ahead_setting_reg = 0 ) then
                  ready_next <= '1';
                  state_next <= idle;

-- Handle case where init_seed is 1 AND n_ahead_setting_reg is NOT 0. This combination indicates that we need to move 
-- ahead n_ahead numbers in the sequence as determined by the n_ahead_settings_reg. Keep incrementing until we reach the 
-- required number of n_ahead_cnts, e.g., if n_ahead_setting_reg is 1, then skip one 'valid' number. KEEP THIS INSIDE of 
-- the bounding 'if stmt' b/c the move ahead counter needs to be incremented ONLY on 'valid' numbers in the sequence. 
               else
                  n_ahead_cnt_next <= n_ahead_cnt_reg + 1;
                  if ( n_ahead_cnt_reg = n_ahead_setting_reg ) then
                     ready_next <= '1';
                     state_next <= idle;
                  else
                     gen_bit <= '1';
                  end if;
               end if;

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

   n_ahead_setting <= std_logic_vector(n_ahead_setting_reg); 

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

