----------------------------------------------------------------------------
---- Create Date:    13:06:08 07/28/2010                                ----     
---- Design Name: lfsr                                                  ----           
---- Project Name: lfsr_randgen                                         ----  
---- Description:                                                       ----  
----  A random number generator based on linear feedback shift          ----
----  register(LFSR).A LFSR is a shift register whose input bit is a    ----
----  linear function of its previous state.The detailed documentation  ----  
----  is available in the file named manual.pdf.                        ----  
----                                                                    ----  
----------------------------------------------------------------------------
----                                                                    ----
---- This file is a part of the lfsr_randgen project at                 ----
---- http://www.opencores.org/                                          ----
----                                                                    ----
---- Author(s):                                                         ----
----   Vipin Lal, lalnitt@gmail.com                                     ----
----                                                                    ----
----------------------------------------------------------------------------
----                                                                    ----
---- Copyright (C) 2010 Authors and OPENCORES.ORG                       ----
----                                                                    ----
---- This source file may be used and distributed without               ----
---- restriction provided that this copyright statement is not          ----
---- removed from the file and that any derivative work contains        ----
---- the original copyright notice and the associated disclaimer.       ----
----                                                                    ----
---- This source file is free software; you can redistribute it         ----
---- and/or modify it under the terms of the GNU Lesser General         ----
---- Public License as published by the Free Software Foundation;       ----
---- either version 2.1 of the License, or (at your option) any         ----
---- later version.                                                     ----
----                                                                    ----
---- This source is distributed in the hope that it will be             ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied         ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR            ----
---- PURPOSE. See the GNU Lesser General Public License for more        ----
---- details.                                                           ----
----                                                                    ----
---- You should have received a copy of the GNU Lesser General          ----
---- Public License along with this source; if not, download it         ----
---- from http://www.opencores.org/lgpl.shtml                           ----
----                                                                    ----
----    set_seedi     : in boolean;                                     ----
----    seedi         : in std_logic_vector(width-1 downto 0);          ----
----    rand_datao    : out std_logic_vector(width-1 downto 0)          ----
----                                                                    ----
----------------------------------------------------------------------------

library ieee;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
   use work.p_lfsr.all;
   use work.p_patt_mon_interface.all;
   use work.p_parameters_and_constants.all;

entity ea_lfsr_mon is
   port (
      clk              : in std_logic;
      reset            : in std_logic;
      -- to/from linear feedback shift register
      control_patti    : in  TYPE_CTRL_PATTERN_TO_LFSR;
      control_patto    : out TYPE_LFSR_TO_CTRL_PATTERN;
      -- from fifo avalon stream
      exp_fifo_avaloni : in  TYPE_EXP_FIFO_AVALON_TO_LFSR;
      -- to multiplexor
      patt_muxo        : out TYPE_LFSR_MON_TO_PATTERN_MUX
   );
end ea_lfsr_mon;

architecture Behavioral of ea_lfsr_mon is
   
   type TYPE_STATE is (IDLE, SENDING, LAST_BYTE);
   
   type TYPE_REGS is record   
      state            : TYPE_STATE;   
      frame_length     : natural;
      data_length      : natural;
      busy             : boolean;
      req              : boolean;
      first_byte       : boolean;
      last_byte        : boolean;
      temp             : std_logic;
      rand_temp        : std_logic_vector (C_AVALON_ST_DATA_WIDTH-1 downto 0);
   end record;
   
   constant CONST_REGS_RESET : TYPE_REGS := (
      state            => IDLE,
      frame_length     => 0,
      data_length      => 0,
      busy             => false,
      req              => false,
      first_byte       => false,
      last_byte        => false,
      temp             => '1',
      rand_temp        => (others => '0')
   ); 
   
   signal r            : TYPE_REGS := CONST_REGS_RESET;

begin
   
   synch: process(reset, clk)
      variable s                 : TYPE_REGS;

   begin

      if reset = '1' then
         r                          <= CONST_REGS_RESET;

         -- init random data, according IEEE random pattern
         --IEEE random pattern
         --(32 => '1',26 => '1',23 => '1',22 => '1',16 => '1',12 => '1',11 => '1',10 => '1',8 => '1',7 => '1',5 => '1',4 => '1',2 => '1',1 => '1',0 => '1',others => '0');    --IEEE pattern for crc32
         r.rand_temp(7)             <= '1';
         r.rand_temp(5)             <= '1';
         r.rand_temp(4)             <= '1';
         r.rand_temp(2)             <= '1';
         r.rand_temp(1)             <= '1';
         r.rand_temp(0)             <= '1';

      elsif (rising_edge(clk)) then
         -- initialize the variables ------------------------------------------
         s                          := r;

         case r.state is
            when IDLE =>
               -- reset registers during the idle state
               s                    := CONST_REGS_RESET;
               s.last_byte          := false;

               if control_patti.lfsr_en then
                  s.frame_length    := control_patti.frame_length;
                  s.state           := SENDING;
                  s.data_length     := 0;
                  s.busy            := true;
                  s.req             := true;
                  s.first_byte      := true;

               end if;

            when SENDING =>
               if not exp_fifo_avaloni.fifo_full then
                  if r.data_length < (r.frame_length - C_AVALON_ST_DATA_WIDTH) then
                     s.data_length   := r.data_length + 1;
                     s.state         := SENDING;
                     s.req           := true;
                     s.first_byte    := false;

                     if control_patti.seed_en then
                        s.rand_temp  := std_logic_vector(to_unsigned(control_patti.seed, C_AVALON_ST_DATA_WIDTH));

                     end if;

                     s.temp          := xor_gates(s.rand_temp);
                     s.rand_temp(C_AVALON_ST_DATA_WIDTH-1 downto 1) := r.rand_temp(C_AVALON_ST_DATA_WIDTH-2 downto 0);
                     s.rand_temp(0)  := r.temp;

                  else 
                     s.state         := LAST_BYTE;
                     s.req           := true;
                     s.last_byte     := true;
                     s.busy          := false;

                  end if;
               else
                  s.state            := SENDING;

               end if;

            when LAST_BYTE =>
               -- wait for a space in the fifo
               if not exp_fifo_avaloni.fifo_full then
                  s.data_length      := r.data_length + 1;
                  s.state            := IDLE;
                  s.last_byte        := false;
                  s.req              := false;

                  -- generte last random data
                  s.temp             := xor_gates(s.rand_temp);
                  s.rand_temp(C_AVALON_ST_DATA_WIDTH-1 downto 1) := r.rand_temp(C_AVALON_ST_DATA_WIDTH-2 downto 0);
                  s.rand_temp(0)     := r.temp;
               else
                  s.state            := LAST_BYTE;

               end if;

            when others =>
               NULL;

         end case;
         
         -- Assign the register record -------------------------------------------
         r            <= s;

      end if;
   end process;

   patt_muxo     <= (req        => r.req,
                     first_byte => r.first_byte,
                     rand_data  => r.rand_temp);

   control_patto <= (busy       => r.busy,
                     first_byte => r.first_byte,
                     last_byte  => r.last_byte);
      
end Behavioral;

