---------------------------------------------------------------------------
-- File           : ea_status_object_gen.vhd
-- Author(s)      : Nikola Avramovic
-- Created        : March 14h, 2019
---------------------------------------------------------------------------
-- Description    : This module should map output status addresses
---------------------------------------------------------------------------

---------------------------------------------------------------------------
library ieee, work;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
   use work.p_parameters_and_constants.all;
   use work.p_functions.all;
   use work.p_interfaces.all;
   use work.p_addresses.all;
   use work.p_generator_interface.all;

entity ea_status_object_gen is
   generic(
      G_NO_OF_PATT_GEN    : natural := 2;
      G_PORT_GEN_NO       : natural := 1
      );
   port  (
      clk                 : in  std_logic;
      reset               : in  std_logic;
      -- to/from input generator
      masteri             : in  TYPE_MASTER_TO_STATUS;
      mastero             : out TYPE_STATUS_TO_MASTER;
      -- to/from pattern generator
      pattern_geni        : in  TYPE_PATTERN_GEN_TO_STATUS_ARRAY(G_NO_OF_PATT_GEN downto 1);
      --pattern_geno        : out TYPE_STATUS_TO_PATTERN_GEN_ARRAY(G_NO_OF_PATT_GEN downto 1);
      -- from port generator
      port_geni           : in  TYPE_PORT_GEN_TO_STATUS 
      --port_geno           : out TYPE_STATUS_TO_PORT_GEN
   );
end entity ea_status_object_gen;

architecture rtl of ea_status_object_gen is

   type TYPE_REGS is record
      pattern_error_count                : integer;
      port_error_count                   : integer;
      master_error_count                 : integer;
      data_out                           : std_logic_vector (C_AVALON_MM_DATA_WIDTH-1 downto 0);
      data_valid                         : boolean;
      wait_req                           : std_logic;
      address                            : integer;
      read_count                         : natural;
      burst_addr                         : integer;
      fatal_err_patt_1                   : std_logic_vector(C_AVALON_MM_DATA_WIDTH-1 downto 0);
      fatal_err_patt_2                   : std_logic_vector(C_AVALON_MM_DATA_WIDTH-1 downto 0);
      fatal_err_port                     : std_logic_vector(C_AVALON_MM_DATA_WIDTH-1 downto 0);
      burst_read                         : boolean;
   end record TYPE_REGS;

   constant CONST_REGS_RESET : TYPE_REGS := (
      pattern_error_count                 => 0,
      port_error_count                    => 0,
      master_error_count                  => 0,
      data_out                            => (others => '1'),
      data_valid                          => false,
      wait_req                            => '0',
      address                             => 0,
      read_count                          => 0,
      burst_addr                          => -1,
      fatal_err_patt_1                    => (others => '0'),
      fatal_err_patt_2                    => (others => '0'),
      fatal_err_port                      => (others => '0'),
      burst_read                          => false
   );

   signal r : TYPE_REGS;

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

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

      elsif rising_edge(clk) then

         s                               := r;
         s.data_valid                    := false;
         s.wait_req                      := '0';

         -- add fatal errors from pattern and port into one vector
         s.fatal_err_patt_1(0)           := boolean_to_stdlogic(pattern_geni(1).lfsr_error);       
         s.fatal_err_patt_1(1)           := boolean_to_stdlogic(pattern_geni(1).linear_error);     
         s.fatal_err_patt_1(2)           := boolean_to_stdlogic(pattern_geni(1).crc_error);        
         s.fatal_err_patt_1(3)           := boolean_to_stdlogic(pattern_geni(1).control_error);    
         s.fatal_err_patt_1(4)           := boolean_to_stdlogic(pattern_geni(1).mux_error);        
         s.fatal_err_patt_1(5)           := boolean_to_stdlogic(pattern_geni(1).fifo_avalon_error);
         s.fatal_err_patt_1(6)           := '0';
         s.fatal_err_patt_1(7)           := '0';

         s.fatal_err_patt_2(0)           := boolean_to_stdlogic(pattern_geni(2).lfsr_error);       
         s.fatal_err_patt_2(1)           := boolean_to_stdlogic(pattern_geni(2).linear_error);     
         s.fatal_err_patt_2(2)           := boolean_to_stdlogic(pattern_geni(2).crc_error);        
         s.fatal_err_patt_2(3)           := boolean_to_stdlogic(pattern_geni(2).control_error);    
         s.fatal_err_patt_2(4)           := boolean_to_stdlogic(pattern_geni(2).mux_error);        
         s.fatal_err_patt_2(5)           := boolean_to_stdlogic(pattern_geni(2).fifo_avalon_error);
         s.fatal_err_patt_2(6)           := '0';
         s.fatal_err_patt_2(7)           := '0';

         s.fatal_err_port(0)             := boolean_to_stdlogic(port_geni.bridge_error);
         s.fatal_err_port(1)             := boolean_to_stdlogic(port_geni.output_error);
         s.fatal_err_port(2)             := '0';
         s.fatal_err_port(3)             := '0';
         s.fatal_err_port(4)             := '0';
         s.fatal_err_port(5)             := '0';
         s.fatal_err_port(6)             := '0';
         s.fatal_err_port(7)             := '0';


         -- read particular (according the address) register
         if masteri.read_req = '1' and masteri.start_reading = '1' then
            s.address                    := (to_integer(unsigned(masteri.address)));
            s.read_count                 := (to_integer(unsigned(masteri.read_count)));
            s.burst_addr                 := s.address;
            s.burst_read                 := true;

         elsif (r.burst_addr <= (r.address + r.read_count - 1)) and r.burst_read then
            s.burst_addr                 := r.burst_addr + 1;
            s.wait_req                   := '1';
            s.burst_read                 := true;

         else
            s.burst_read                 := false;

         end if;

         if r.burst_read then
            -- read status from dadicated burst_addr
            if r.burst_addr = C_FATAL_ERROR_PATT_1 then
               s.data_out                := r.fatal_err_patt_1;
               s.data_valid              := true;

            elsif r.burst_addr = C_FATAL_ERROR_PATT_2 then
               s.data_out                := r.fatal_err_patt_2;
               s.data_valid              := true;

            elsif r.burst_addr = C_FATAL_ERROR_PORT then
               s.data_out                := r.fatal_err_port;
               s.data_valid              := true;

             else
               -- if it is wrong burst_addr, then send all '1' with deassert valid signal
               s.data_out                := (others => '1');
               s.data_valid              := false;

            end if;
         end if;

         r                    <= s; 

      end if;
   end process;

   mastero                   <= (data_valid  => boolean_to_stdlogic(r.data_valid),
                                 read_data   => r.data_out,
                                 wait_req    => r.wait_req);

end architecture rtl;