---------------------------------------------------------------------------
-- Copyright (c) 2018, Filip Kliment
---------------------------------------------------------------------------
-- File           : report_pck.vhd
-- Author(s)      : Filip Kliment
---------------------------------------------------------------------------

library ieee, std;
   use std.textio.all;
   use ieee.std_logic_1164.all;
   use ieee.numeric_std.all;


-- -----------------------------------------------------------------------------
-- PACKAGE DECLARATION
-- -----------------------------------------------------------------------------
package report_pck is
   constant C_MSG_ID_SIZE : natural := 30;
   constant C_TIME_SIZE   : natural := 20;

   -- Operation
   type tVerbosity is (NONE,   -- NONE
                       INFO,   -- INFO verbosity (normal)
                       DEBUG); -- DEBUG Verbosity 

   type tReportStatistics is protected      
      impure function get_info_count    return natural;
      impure function get_error_count   return natural;
      procedure inc_info_counter;
      procedure inc_error_counter;
   end protected tReportStatistics;
 
   ----------------------------------------------------------------------------
   -- Converts unsigned vector to hexadecimal string
   ----------------------------------------------------------------------------
   function to_hexstr(vec : unsigned) return string;

   ----------------------------------------------------------------------------
   -- Report Info Message 
   ----------------------------------------------------------------------------
   procedure report_info(
      msg_id : in string;                     -- prefix (left column)
      msg    : in string;                     -- message
      msg_verbosity : in tVerbosity := INFO;  -- verbosity level of this message
      bfm_verbosity : in tVerbosity := DEBUG  -- current verbosity level of BFM
   );

   procedure report_error (
      msg_id : in string; -- string to print
      msg    : in string -- string to print
   );

   procedure report_test_end;

end report_pck;

-- -----------------------------------------------------------------------------
-- PACKAGE BODY ----------------------------------------------------------------
-- -----------------------------------------------------------------------------

package body report_pck is

   ----------------------------------------------------------------------------
   -- Report Statistics
   ----------------------------------------------------------------------------
   type tReportStatistics is protected body      
      variable info_count    : natural := 0;
      variable warning_count : natural := 0;
      variable error_count   : natural := 0;
      variable fatal_count   : natural := 0;
      impure function get_info_count    return natural is
      begin
         return info_count;
      end function;
      impure function get_error_count   return natural is
      begin
         return error_count;
      end function;

      procedure inc_info_counter is
      begin
         info_count := info_count+1;
      end procedure;
      procedure inc_error_counter is
      begin
         error_count := error_count+1;
      end procedure;

   end protected body tReportStatistics;

   shared variable statistics : tReportStatistics;
   
   -- conver hexadecimal string to std_logic_vector
   function to_hexstr(vec : unsigned) return string is
      variable ret : string(1 to (vec'length+3)/4) := (others => ' ');
      variable tmp : unsigned(ret'length*4 - 1 downto 0) := (others => '0');
      variable nibble : natural range 0 to 15;
      variable j      : natural range 0 to ret'length - 1;
   begin
      tmp(vec'range) := vec;
      for i in ret'range loop
         j := ret'high - i;
         nibble := to_integer(tmp(j*4+3 downto j*4));
         if nibble < 10 then
            ret(i) := character'val(character'pos('0') + nibble);
         else
            ret(i) := character'val(character'pos('A') - 10 + nibble);
         end if;
      end loop;
      return ret;
   end function;

   ----------------------------------------------------------------------------
   -- Report Info Message 
   ----------------------------------------------------------------------------
   procedure report_info (
      msg_id : in string;                     -- prefix (left column)
      msg    : in string;                     -- message
      msg_verbosity : in tVerbosity := INFO;  -- verbosity level of this message
      bfm_verbosity : in tVerbosity := DEBUG  -- current verbosity level of BFM
   ) is
      variable l : line; -- aux. variable
   begin
      if (bfm_verbosity >= msg_verbosity) then
         statistics.inc_info_counter;
         write(l, "** Note: " & justify(msg_id, field => C_MSG_ID_SIZE, justified => left) & " (" 
                              & justify(to_string(now, ns), field => C_TIME_SIZE, justified => left) 
                              & ") : " & msg);
         writeline(output, l);
      end if;
   end;

   ----------------------------------------------------------------------------
   -- Report Error Message 
   ----------------------------------------------------------------------------
   procedure report_error (
      msg_id : in string; -- string to print
      msg    : in string  -- string to print
   ) is
   begin
      statistics.inc_error_counter;
      report msg_id & " : " & msg
      severity error;
   end;

   procedure report_test_end 
   is
   begin
     report_info("TEST", "---------------------------");
     report_info("TEST", "Test finished successfully!");
     report_info("TEST", "---------------------------");
     report_info("STATISTICS", "Report Statistics: " & LF &
       "INFO Message Count:     " & justify(to_string(statistics.get_info_count),    field => 4) & LF &
       "ERROR Message Count:    " & justify(to_string(statistics.get_error_count),   field => 4));
   end;

end report_pck;
