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

-- ===================================================================================================
-- LFSR -- modeled after the version available in OpenCores except that I have added the all 0 case
-- and changed the shift right to a shift left.  If set_seed is 1, then load seed. If set_seed is 0 
-- and gen_bit is 1, do a 1-bit shift. 

-- NOTE: We could include several 12-bit LFSRs that implement a different primitive. Just note that it is 
-- possible at one or more iterations that the two LFSRs (which now each cycle through the 4095 number space 
-- in a different fashion) that both LFSRs generate the same number, which of course would specify the same 
-- SMC. This would obviously generate an 'invalid' bit during enrollment but otherwise would be harmless.
-- ===================================================================================================

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

entity LFSR12_wZERO is
   generic (LFSR_LEN_NB: integer := 12);
   port (
      Clk: in std_logic;
      RESET: in std_logic;
      set_seed: in std_logic; 
      gen_bit: in std_logic; 
      seed: in std_logic_vector(LFSR_LEN_NB-1 downto 0);
      LFSR_out: out std_logic_vector(LFSR_LEN_NB-1 downto 0)
      );
end LFSR12_wZERO;

architecture beh of LFSR12_wZERO is
   signal LFSR_reg, LFSR_next: std_logic_vector(LFSR_LEN_NB-1 downto 0);
   signal next_bit: std_logic;
   signal nor_bit: std_logic;
   signal request: std_logic_vector(1 downto 0);
   begin

-- state and register logic
   process(Clk, RESET)
      begin
      if ( RESET = '1' ) then
         LFSR_reg <= (LFSR_LEN_NB-1 downto 1 =>'0') & (0=>'1');
      elsif ( Clk'event and Clk = '1' ) then
         LFSR_reg <= LFSR_next;
      end if; 
   end process;

-- Set seed takes priority if both are set
   request <= set_seed & gen_bit;

-- Add the 'all zero' state. Simply the bitwise nor of the lower 11 bits. See
-- LFSR_C_Validation/VHDL_NO_NORM_wZERO.c for a C implementation of this LFSR.
   nor_bit <= not(LFSR_reg(10) or LFSR_reg(9) or LFSR_reg(8) or LFSR_reg(7) or
                  LFSR_reg(6) or LFSR_reg(5) or LFSR_reg(4) or LFSR_reg(3) or
                  LFSR_reg(2) or LFSR_reg(1) or LFSR_reg(0));

-- Confirmed this is a primitive in a C code implementation. NOTE: Implementation in
-- /home/research/research/FPGAs/HELP/VHDL_HELP/contrib/lfsr_randgen/trunk/lfsr_pkg.vhd
-- shifts the new bit on the right, as we do here. This is important -- if reversed,
-- you need to reverse the tap points.
--    xor_out := rand(11) xor rand(5) xor rand(3) xor rand(0);
   next_bit <= LFSR_reg(11) xor LFSR_reg(5) xor LFSR_reg(3) xor LFSR_reg(0) xor nor_bit;

-- Preserve contents or put the seed in or shift the LSFR to generate the new bit. Reversed
-- bit shift on 9/27/2013 to match that in above C file.
   LFSR_next <= LFSR_reg when (request = "00") else
                seed when (request(1) = '1') else
                LFSR_reg(LFSR_LEN_NB-2 downto 0) & next_bit; 

   LFSR_out <= LFSR_reg;

end beh;
