---------------------------------------------------------------------------
-- File           : ea_status_object_mon.vhd
-- Author(s)      : Nikola Avramovic
-- Created        : March 14h, 2019
---------------------------------------------------------------------------
-- Description    : Status object mapped monitor status registers
---------------------------------------------------------------------------

---------------------------------------------------------------------------
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_monitor_interface.all;

entity ea_status_object_mon is
   generic(
      G_NO_OF_PATT_MON    : natural := 2;
      G_PORT_MON_NO       : natural := 1
      );
   port  (
      clk                 : in  std_logic;
      reset               : in  std_logic;
      -- to/from input monitor
      masteri             : in  TYPE_MASTER_TO_STATUS;
      mastero             : out TYPE_STATUS_TO_MASTER;
      -- to/from pattern monitor
      pattern_moni        : in  TYPE_PATTERN_MON_TO_STATUS_ARRAY(G_NO_OF_PATT_MON downto 1);
      --pattern_mono        : out TYPE_STATUS_TO_PATTERN_MON_ARRAY(G_NO_OF_PATT_MON downto 1);
      -- from port monitor
      port_moni           : in  TYPE_PORT_MON_TO_STATUS;
      port_mono           : out TYPE_STATUS_TO_PORT_MON
   );
end entity ea_status_object_mon;

architecture rtl of ea_status_object_mon 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_errors                       : std_logic_vector(C_AVALON_MM_DATA_WIDTH-1 downto 0);
      corr_crc_pck_read                  : boolean;
      fatal_read                         : boolean;
      smd_i_read                         : boolean;
      smd_c_read                         : boolean;
      crc_packet_read                    : boolean;
      frag_no_read                       : boolean;
      preamble_length_read               : boolean;
      error_frame_read                   : boolean;
      correct_frame_read                 : boolean;
      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_errors                        => (others => '0'),
      corr_crc_pck_read                   => false,
      fatal_read                          => false,
      smd_i_read                          => false,
      smd_c_read                          => false,
      crc_packet_read                     => false,
      frag_no_read                        => false,
      preamble_length_read                => false,
      error_frame_read                    => false,
      correct_frame_read                  => false,
      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_errors(0)               := boolean_to_stdlogic(pattern_moni(1).one_frame_err);
         s.fatal_errors(1)               := boolean_to_stdlogic(pattern_moni(2).one_frame_err);
         s.fatal_errors(2)               := boolean_to_stdlogic(port_moni.cam_error);
         s.fatal_errors(3)               := boolean_to_stdlogic(port_moni.patt_not_ready);
         s.fatal_errors(4)               := boolean_to_stdlogic(port_moni.sfd_error);
         s.fatal_errors(5)               := boolean_to_stdlogic(port_moni.preamble_error);
         s.fatal_errors(6)               := boolean_to_stdlogic(port_moni.idle_error);
         s.fatal_errors(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;

            s.corr_crc_pck_read          := false;   
            s.smd_i_read                 := false;          
            s.smd_c_read                 := false;          
            s.crc_packet_read            := false;     
            s.frag_no_read               := false;        
            s.preamble_length_read       := false;

         end if;

         if r.burst_read then
            -- read status from dadicated burst_addr
            if r.burst_addr = C_FATAL_ERROR then
               s.data_out                := r.fatal_errors;
               s.data_valid              := true;
               s.fatal_read              := true;

            elsif r.burst_addr = C_CORRECT_CRC_PCK_COUNTER then
               s.data_out                := std_logic_vector(port_moni.correct_crc_pck_counter);
               s.data_valid              := true;
               s.corr_crc_pck_read       := true;

            elsif r.burst_addr = C_SMD_I_ERR_COUNT then
               s.data_out                := std_logic_vector(port_moni.smd_i_err_count);
               s.data_valid              := true;
               s.smd_i_read              := true;

            elsif r.burst_addr = C_SMD_C_ERR_COUNT then
               s.data_out                := std_logic_vector(port_moni.smd_c_err_count);
               s.data_valid              := true;
               s.smd_c_read              := true;

            elsif r.burst_addr = C_CRC_PACKET_ERR_COUNTER then
               s.data_out                := std_logic_vector(port_moni.crc_packet_err_count);
               s.data_valid              := true;
               s.crc_packet_read         := true;

            elsif r.burst_addr = C_FRAG_NO_ERR_COUNTER then
               s.data_out                := std_logic_vector(port_moni.frag_no_err_count);
               s.data_valid              := true;
               s.frag_no_read            := true;

            elsif r.burst_addr = C_PREAMBLE_LEN_ERR_COUNTER then
               s.data_out                := std_logic_vector(port_moni.preamble_length_err_count);
               s.data_valid              := true;
               s.preamble_length_read    := true;


            elsif r.burst_addr = C_ERROR_FRAME_COUNTER_1 then
               s.data_out                := std_logic_vector(pattern_moni(1).error_frame_counter);
               s.data_valid              := true;
               s.error_frame_read        := true;


            elsif r.burst_addr = C_CORRECT_FRAME_COUNTER_1 then
               s.data_out                := std_logic_vector(pattern_moni(1).correct_frame_counter);
               s.data_valid              := true;
               s.correct_frame_read      := true;


            elsif r.burst_addr = C_ERROR_FRAME_COUNTER_2 then
               s.data_out                := std_logic_vector(pattern_moni(2).error_frame_counter);
               s.data_valid              := true;
               s.error_frame_read        := true;


            elsif r.burst_addr = C_CORRECT_FRAME_COUNTER_2 then
               s.data_out                := std_logic_vector(pattern_moni(2).correct_frame_counter);
               s.data_valid              := true;
               s.correct_frame_read      := 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);

   port_mono                 <= (corr_crc_pck_read      =>r.corr_crc_pck_read,
                                 smd_i_read             =>r.smd_i_read,
                                 smd_c_read             =>r.smd_c_read,
                                 crc_packet_read        =>r.crc_packet_read,
                                 frag_no_read           =>r.frag_no_read,
                                 preamble_length_read   =>r.preamble_length_read);

end architecture rtl;