---------------------------------------------------------------------------
-- Copyright (c) 2012, TTTech Computertechnik AG
-- Project        : Pegasus E/S
---------------------------------------------------------------------------
-- File           : p_report_utils.vhd
-- Author(s)      : Petr Kobiersky
-- Created        : March 12nd, 2012
---------------------------------------------------------------------------
-- Description    : Report Utilities
--
-- Package provides standard functions for reporting.
--
---------------------------------------------------------------------------

---------------------------------------------------------------------------

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


-- -----------------------------------------------------------------------------
-- PACKAGE DECLARATION
-- -----------------------------------------------------------------------------
package p_report_utils 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 

   -- BFM ParameterProtected Type (Used for accessing shared variable)
   ----------------------------------------------------------------------------
   -- Report Statistics
   ----------------------------------------------------------------------------
   type tReportStatistics is protected      
      impure function get_info_count    return natural;
      impure function get_error_count   return natural;
      impure function get_warning_count return natural;
      impure function get_fatal_count   return natural;
      procedure inc_info_counter;
      procedure inc_error_counter;
      procedure inc_warning_counter;
      procedure inc_fatal_counter;
   end protected tReportStatistics;
   
   ----------------------------------------------------------------------------
   -- Converts log level specified in string to a pre-defined type
   -- 
   ----------------------------------------------------------------------------   
   function convert_report_level(level: in string) return tVerbosity;

   ----------------------------------------------------------------------------
   -- Report Debug Message 
   ----------------------------------------------------------------------------
   procedure report_debug(
      msg_id        : in string;              -- prefix (left column)
      msg           : in string;              -- message
      bfm_verbosity : in tVerbosity := DEBUG  -- current verbosity level of BFM
   );

   ----------------------------------------------------------------------------
   -- 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
   );

   ----------------------------------------------------------------------------
   -- Report Warning Message 
   ----------------------------------------------------------------------------
   procedure report_warning (
      msg_id : in string; -- string to print
      msg    : in string  -- string to print
   );

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

   ----------------------------------------------------------------------------
   -- Report Fatal Message 
   ----------------------------------------------------------------------------
   procedure report_fatal (
      msg_id : in string; -- string to print
      msg    : in string -- string to print
   );

   ----------------------------------------------------------------------------
   -- End of Test Procedure
   -- It prints End of Test delimiter to the simulation output
   -- stream (transcript). 
   ----------------------------------------------------------------------------
   procedure report_test_end;

   ----------------------------------------------------------------------------
   -- End of Test Procedure (Timeout)
   -- It prints End of Test delimiter caused by timeout to the simulation
   -- output stream (transcript). 
   ----------------------------------------------------------------------------
   procedure report_test_timeout;


end p_report_utils;

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

package body p_report_utils 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;
      impure function get_warning_count return natural is
      begin
         return warning_count;
      end function;
      impure function get_fatal_count   return natural is
      begin
         return fatal_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;
      procedure inc_warning_counter is
      begin
         warning_count := warning_count+1;
      end procedure;
      procedure inc_fatal_counter is
      begin
         fatal_count := fatal_count+1;
      end procedure;
   end protected body tReportStatistics;

   shared variable statistics : tReportStatistics;
   
   
   -- convert a character to lower case
   function to_lower(c: character) return character is
   begin
      if c >= 'A' and c <= 'Z' then
         return character'val(character'pos(c) - character'pos('A') + character'pos('a'));
      else
         return c;
      end if;
   end function;
   
   -- convert a string to lower case
   function to_lower(s: string) return string is
     variable lowercase: string (s'range);
   begin
     for i in s'range loop
        lowercase(i):= to_lower(s(i));
     end loop;
     return lowercase;
   end function;   

   -- convert verbosity level specified as strign to a predefined type
   function convert_report_level(level: in string) return tVerbosity 
   is 
   variable      
      ret      :tVerbosity;
   begin   
      if to_lower(level) = "info" then         
         ret := INFO;
      elsif to_lower(level) = "debug" then
         ret := DEBUG;
      else
         report_warning("log_level", "Unknown string for verbosity level! Using default value = INFO !");
         ret := INFO;
      end if;      
      return ret;
   end function;
   
   ----------------------------------------------------------------------------
   -- Report Debug Message 
   ----------------------------------------------------------------------------
   procedure report_debug (
      msg_id : in string;                     -- prefix (left column)
      msg    : in string;                     -- message
      bfm_verbosity : in tVerbosity := DEBUG  -- current verbosity level of BFM
   ) is
      variable l : line; -- aux. variable
   begin
      if (bfm_verbosity >= DEBUG) 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 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 Warning Message 
   ----------------------------------------------------------------------------
   procedure report_warning (
      msg_id : in string; -- string to print
      msg    : in string  -- string to print
   ) is
   begin
      statistics.inc_warning_counter;
      report msg_id & " : " & msg
      severity warning;
      
   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;

   ----------------------------------------------------------------------------
   -- Report Fatal Message
   ----------------------------------------------------------------------------
   procedure report_fatal (
      msg_id : in string; -- string to print
      msg    : in string  -- string to print
   ) is
   begin
      statistics.inc_fatal_counter;
      report msg_id & " : " & msg
      severity failure;
   end;

   ----------------------------------------------------------------------------
   -- End of Test Procedure
   -- It prints End of Test delimiter to the simulation output
   -- stream (transcript). 
   ----------------------------------------------------------------------------
   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 &
       "WARNINIG Message Count: " & justify(to_string(statistics.get_warning_count), field => 4) & LF &
       "ERROR Message Count:    " & justify(to_string(statistics.get_error_count),   field => 4) & LF &
       "FATAL Message Count:    " & justify(to_string(statistics.get_fatal_count),   field => 4));
   end;

   ----------------------------------------------------------------------------
   -- End of Test Procedure (Timeout)
   -- It prints End of Test delimiter caused by timeout to the simulation
   -- output stream (transcript). 
   ----------------------------------------------------------------------------
   procedure report_test_timeout
   is
   begin
     report_info( "TEST", "-------------------------");
     report_error("TEST", "Test finished on timeout!");
     report_info( "TEST", "-------------------------");
   end;

end p_report_utils;
