---------------------------------------------------------------------------
-- File           : ea_scoreboard.vhd
-- Author(s)      : Nikola Avramovic
-- Created        : March 16th, 2019
---------------------------------------------------------------------------
-- Description    : Scoreboard check whether data is correct
---------------------------------------------------------------------------
--
---------------------------------------------------------------------------
library ieee; 
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;
   use work.p_parameters_and_constants.all;
   use work.p_interfaces.all;
   use work.p_functions.all;
   use work.p_monitor_interface.all;
   use work.p_patt_mon_interface.all;

entity ea_scoreboard is 
   port (clk              : in  std_logic;
         reset            : in  std_logic;
         -- to/from control pattern
         control_patti    : in  TYPE_CTRL_PATTERN_TO_SCOREBOARD;
         control_patto    : out TYPE_SCOREBOARD_TO_CTRL_PATTERN;
         -- to/from expacted fifo avalon 
         exp_fifo_avaloni : in  TYPE_AVALON_ST_SOURCE_TO_SINK;
         exp_fifo_avalono : out TYPE_AVALON_ST_SINK_TO_SOURCE;
         -- to/from observed fifo avalon 
         obs_fifo_avaloni : in  TYPE_AVALON_ST_SOURCE_TO_SINK;
         obs_fifo_avalono : out TYPE_AVALON_ST_SINK_TO_SOURCE
   );
end ea_scoreboard;

architecture rtl of ea_scoreboard is  
   
   constant C_DATA_BUFFER    : natural := 5;

   type TYPE_REGS is record   
      busy                   : boolean;
      first_byte             : boolean;
      obs_frame_receiving    : boolean;
      obs_fifo_valid         : boolean;
      obs_fifo_ready         : boolean;
      obs_data_in            : TYPE_AVALON_ST_SOURCE_TO_SINK_ARRAY(C_DATA_BUFFER-1 downto 0);
      exp_frame_receiving    : boolean;
      exp_fifo_valid         : boolean;
      exp_fifo_ready         : boolean;
      exp_data_in            : TYPE_AVALON_ST_SOURCE_TO_SINK_ARRAY(C_DATA_BUFFER-1 downto 0);
      error_frame            : boolean;
      frame_corr             : boolean;
      error_frame_counter    : unsigned(C_BYTE_LENGTH-1 downto 0);
      correct_frame_counter  : unsigned(C_BYTE_LENGTH-1 downto 0);
   end record;
   
   constant CONST_REGS_RESET : TYPE_REGS := (
      busy                   => false,
      first_byte             => false,
      obs_frame_receiving    => false,
      obs_fifo_valid         => false,
      obs_fifo_ready         => true,
      obs_data_in            => (others => C_AVALON_ST_SOURCE_TO_SINK),
      exp_frame_receiving    => false,
      exp_fifo_valid         => false,
      exp_fifo_ready         => false,
      exp_data_in            => (others => C_AVALON_ST_SOURCE_TO_SINK),
      error_frame            => false,
      frame_corr             => false,
      error_frame_counter    => X"00",
      correct_frame_counter  => X"00" 
   ); 
   
   signal r :      TYPE_REGS := CONST_REGS_RESET;
   
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;
         
         if control_patti.scoreboard_en then
            -----------------------------------------------------------------------------
            -- Observed FIFO management
            -----------------------------------------------------------------------------
            -- observed fifo most not be full, otherwise frame will be dropped
            s.obs_fifo_ready             := true;

            -- buffer input data
            s.obs_data_in(0)             := obs_fifo_avaloni;
            s.obs_data_in                := s.obs_data_in(0) & s.obs_data_in(C_DATA_BUFFER-1 downto 1);

            -- start reading from expected fifo
            if (r.obs_data_in(C_DATA_BUFFER-1).valid = '1') then
               s.exp_fifo_ready          := true;               -- set expecting fifo ready 

            end if;

            if r.obs_data_in(0).valid = '1' and r.obs_data_in(0).sop = '1' then
               s.obs_frame_receiving     := true;

            elsif r.obs_data_in(3).valid = '1' and r.obs_data_in(3).eop = '1' then
               s.obs_frame_receiving     := false;
               s.exp_fifo_ready          := false;

            end if;

            -----------------------------------------------------------------------------
            -- Expacted FIFO management has done by observed signals
            -----------------------------------------------------------------------------
            -- buffer input data
            if exp_fifo_avaloni.valid = '1' then
               s.exp_data_in(0)          := exp_fifo_avaloni;
               s.exp_data_in             := s.exp_data_in(0) & s.exp_data_in(C_DATA_BUFFER-1 downto 1);

            end if;

            -----------------------------------------------------------------------------
            -- Comparing data 
            -----------------------------------------------------------------------------
            if r.obs_frame_receiving then

               if r.obs_data_in(0).data /= r.exp_data_in(4).data then
                  s.error_frame          := true;

               else
                  s.frame_corr           := true;

               end if;

               -- check error frame at the end of frame
               if r.error_frame and (r.obs_frame_receiving) and (not s.obs_frame_receiving) then
                  s.error_frame          := false;
                  s.error_frame_counter  := r.error_frame_counter + 1;

               -- check frame at the end of frame
               elsif r.frame_corr and (not r.error_frame) and (r.obs_frame_receiving) and (not s.obs_frame_receiving) then
                  s.frame_corr           := false;
                  s.correct_frame_counter:= r.correct_frame_counter + 1;

               end if;

            end if;

         -- if scoreboard is not set, send all X'0000'
         else
            s.error_frame_counter        := X"00";
            s.correct_frame_counter      := X"00";

         end if;

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

         -- ready signals must have immediate reaction
         exp_fifo_avalono        <= (ready                  => boolean_to_stdlogic(r.exp_fifo_ready));
         obs_fifo_avalono        <= (ready                  => boolean_to_stdlogic(r.obs_fifo_ready));

      end if;  
   end process;

   control_patto                 <= (error_frame_counter    => r.error_frame_counter,
                                     correct_frame_counter  => r.correct_frame_counter);

end architecture rtl;      