---------------------------------------------------------------------------
-- File           : ea_linear_gen.vhd
-- Author(s)      : Nikola Avramovic
-- Created        : March 16th, 2019
---------------------------------------------------------------------------
-- Description    : Incremental generator, it used to increment by 8 
---------------------------------------------------------------------------

---------------------------------------------------------------------------
library ieee; 
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
   use work.p_parameters_and_constants.all;
   use work.p_patt_gen_interface.all;

entity ea_linear_gen is 
   port( clk           : in  std_logic;
         reset         : in  std_logic;
         -- to/from linear generator
         control_patti : in  TYPE_CTRL_PATTERN_TO_LINEAR;
         control_patto : out TYPE_LINEAR_TO_CTRL_PATTERN;
         -- to linear generator
         fifo_avaloni  : in  TYPE_FIFO_AVALON_TO_LINEAR;
         -- to multiplexor
         patt_muxo     : out TYPE_LINEAR_GEN_TO_PATTERN_MUX
   );
end ea_linear_gen;

architecture rtl of ea_linear_gen is  
   
   type TYPE_STATE is (IDLE, SENDING, LAST_BYTE);
   
   type TYPE_REGS is record   
      state            : TYPE_STATE;   
      frame_length     : natural;
      data_length      : natural;
      data_out         : unsigned(C_AVALON_ST_DATA_WIDTH-1 downto 0);
      req              : boolean;
      busy             : boolean;
      last_byte        : boolean;
      first_byte       : boolean;
   end record;
   
   constant CONST_REGS_RESET : TYPE_REGS := (
      state            => IDLE,
      frame_length     => 0,
      data_length      => 0,
      data_out         => X"00", -- default seqence
      req              => false,
      busy             => false,
      last_byte        => false,
      first_byte       => false
   ); 
   
   signal r            : TYPE_REGS := CONST_REGS_RESET;

--TODO: think about error states in this module
begin
   sync: process (reset, clk) 
      variable s                 : TYPE_REGS;

   begin

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

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

         case r.state is
            when IDLE =>
               --s.linear_en       := control_patti.linear_en;
               s.last_byte       := false;

               if control_patti.linear_en and not r.last_byte then
                  s.frame_length := control_patti.frame_length;
                  s.data_out     := to_unsigned(control_patti.start_seqence, C_AVALON_ST_DATA_WIDTH);   
                  s.state        := SENDING;
                  s.data_length  := 0;
                  s.busy         := true;
                  s.req          := true;
                  s.first_byte   := true;

               end if;

            when SENDING =>
               if not 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.data_out     := r.data_out + C_AVALON_ST_DATA_WIDTH; 
                     s.state        := SENDING;
                     s.req          := true;
                     s.first_byte   := false;

                  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 =>
               if not fifo_avaloni.fifo_full then
                  s.data_length     := r.data_length + 1;
                  s.data_out        := r.data_out + C_AVALON_ST_DATA_WIDTH;
                  s.state           := IDLE;
                  s.last_byte       := false;
                  s.req             := false;

               else
                  s.state           := LAST_BYTE;

               end if;
         end case;

         -- Assign the register record -------------------------------------------
         r            <= s;
      end if;  
   end process;

   patt_muxo          <= (req        => r.req,
                          first_byte => r.first_byte,
                          data       => std_logic_vector(r.data_out));

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

end architecture rtl;      