----------------------------------------------------------------------------------
-- Company: 
-- Engineer: 
-- 
-- Create Date:    
-- Design Name: 
-- Module Name:    ChlngLFSR_NormGrp - 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. 

-- This is a special module that handles subsets of SMCs as is required if normalization is carried out. 
-- REGION_SIZE is the size of the region (in SMCs, currently 4x4 or 16) and the NUM_GROUPS or the # of regions
-- (currently 16x16 or 256 for a cube of SMCs of size 64x64 or 4096 total SMCs). Note that the maximal LFSR 
-- sequence is 2^n - 1 values normally, which excludes the all zero case, but in this module, we need to
-- include the 'all zero' case.

-- Note that there are fewer comparisons we can make with regions. Without regions, the total number of 
-- comparisons are 4095*4094/2 = 8,382,465 comparisons (4096 - 1 since 0 is NOT included in the sequence
-- of numbers produced by the LFSR.) With regions, this reduces to 16*15/2 = 120 per region * 256 regions = 
-- 30,720 (SMC (0,0) is NOW VALID). Even all-linear is smaller at 15*256 = 3,840 instead of 4,095. 

-- Idea is to use two 4-bit LFSRs to generate all 15 linear pairing and 120 all combination pairings within a 
-- region, e.g., when 1-Ahead is used, we get 0-1, 1-2, 2-3, 3-4, 4-5, 5-6, 6-7, 7-8, 8-9, 9-10, 10-11, 11-12, 
-- 12-13, 13-14, 14-15 (which is all linear). NOTE: We need to add 0 to the LFSR sequence. 

-- We use the n-Ahead in the same fashion as the case without normalization (ChlngLFSR_nAhead_NoNorm.vhd) except the 
-- n-Ahead can only be advanced 15 times. We get 15 pairing with 1-Ahead, 14 pairings with 2-Ahead, etc. So 
-- each region generates (15+14+13+12...+2+1) = 120. With 256 regions, we get 120*256 = 30,720 under all combinations. 

-- n-Ahead needs to be advanced when CLFSR_num_bits_reg = (REGION_SIZE - CLFSR_n_ahead_setting)*NUM_GROUPS - 1
-- (see BitGenDriver.vhd). The original expression (without normalization) is TOP_NUM_SMCS - CLFSR_n_ahead_setting - 1
-- so I'll need to craft this more generic method into BitGenDriver.vhd.

-- We would combine this with one 8-bit LFSR to cycle through each of the regions randomly. It would get advanced
-- every time a cycle of 15 of the 4-bit LFSR was reached. This would randomize the traversal within each region 
-- (assuming we don't reseed) since we would begin with the 16th value for the next region. We would be forced to go
-- through all SMCs within each region before moving to the next region unless we fire the 8-bit LFSR each time.

-- ===================================================================================================

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

entity ChlngLFSR_NormGrp is
   generic(
      CLFSR_LEN_NB: integer := 8);
   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);
      advance_grp: in std_logic;
      ready: out std_logic;
      PRN: out std_logic_vector(CLFSR_LEN_NB-1 downto 0)
      );
end ChlngLFSR_NormGrp;

ARCHITECTURE beh of ChlngLFSR_NormGrp 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
   LFSR8: entity work.LFSR8_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, advance_grp)
      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' and advance_grp = '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 available. Don't think this check
-- is needed in the 4-bit case.
            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;

