--
--  File Name:         ResolutionPkg.vhd
--  Design Unit Name:  ResolutionPkg
--  Revision:          STANDARD VERSION
--
--  Maintainer:        Jim Lewis      email:  jim@SynthWorks.com 
--  Contributor(s):            
--     Jim Lewis      email:  jim@SynthWorks.com   
--
--  Package Defines
--      resolved resolution functions for integer, real, and time
--      types resolved_integer, resolved_real, resolved_time
--    
--  Developed for: 
--        SynthWorks Design Inc. 
--        VHDL Training Classes
--        11898 SW 128th Ave.  Tigard, Or  97223
--        http://www.SynthWorks.com
--
--  Revision History:
--    Date      Version    Description
--    09/2006:  0.1        Initial revision
--                         Numerous revisions for VHDL Testbenches and Verification
--    02/2009:  1.0        VHDL-2008 STANDARD VERSION
--    05/2015   2015.05    Added Alerts
--    --                   Replaced Alerts with asserts as alerts are illegal in pure functions
--    11/2016   2016.11    Removed Asserts as they are not working as intended.
--                         See ResolutionPkg_debug as it uses Alerts to correctly detect errors
--
--
--  Copyright (c) 2005 - 2016 by SynthWorks Design Inc.  All rights reserved.
--
--  Verbatim copies of this source file may be used and 
--  distributed without restriction.   
-- 								 
--  This source file may be modified and distributed under 
--  the terms of the ARTISTIC License as published by 
--  The Perl Foundation; either version 2.0 of the License, 
--  or (at your option) any later version. 						 
-- 								 
--  This source is distributed in the hope that it will be 	 
--  useful, but WITHOUT ANY WARRANTY; without even the implied  
--  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 	 
--  PURPOSE. See the Artistic License for details. 							 
-- 								 
--  You should have received a copy of the license with this source.
--  If not download it from, 
--     http://www.perlfoundation.org/artistic_license_2_0
--

library ieee ; 
use ieee.std_logic_1164.all ; 
use ieee.numeric_std.all ; 

library osvvm ; 
use osvvm.AlertLogPkg.all ; 

package ResolutionPkg is 
  constant MULTIPLE_DRIVER_SEVERITY : severity_level := ERROR ; 

--
-- Note that not all simulators support resolution functions of the form:
--    subtype  std_logic_vector_max is (resolved_max) std_ulogic_vector ;
--
-- Hence, types of the form are offered as a temporary workaround until they do: 
--    std_logic_vector_max_c is array (natural range <>) of std_logic_max ; -- for non VHDL-2008
--

  -- resolved_max
  --   return maximum value.  
  --   No initializations required on ports, default of type'left is ok
  function resolved_max ( s : std_ulogic_vector) return std_ulogic ; 
  subtype  std_logic_max is resolved_max std_ulogic ; 
  subtype  std_logic_vector_max is (resolved_max) std_ulogic_vector ;
  type     std_logic_vector_max_c is array (natural range <>) of std_logic_max ; -- for non VHDL-2008  

  subtype  unsigned_max is (resolved_max) unresolved_unsigned ; 
  type     unsigned_max_c is array (natural range <>) of std_logic_max ; -- for non VHDL-2008  
  subtype  signed_max   is (resolved_max) unresolved_signed ;
  type     signed_max_c is array (natural range <>) of std_logic_max ; -- for non VHDL-2008  

  function resolved_max ( s : bit_vector) return bit ;               
  subtype  bit_max is resolved_max bit ; 
  subtype  bit_vector_max is (resolved_max) bit_vector ; 
  type     bit_vector_max_c is array (natural range <>) of bit_max ; -- for non VHDL-2008  

  function resolved_max ( s : integer_vector ) return integer ;      
  subtype  integer_max is resolved_max integer ; 
  subtype  integer_vector_max is (resolved_max) integer_vector ; 
  type     integer_vector_max_c is array (natural range <>) of integer_max ; -- for non VHDL-2008  

  function resolved_max ( s : time_vector ) return time ;            
  subtype  time_max is resolved_max time ; 
  subtype  time_vector_max is (resolved_max) time_vector ; 
  type     time_vector_max_c is array (natural range <>) of time_max ; -- for non VHDL-2008  

  function resolved_max ( s : real_vector ) return real ;            
  subtype  real_max is resolved_max real ; 
  subtype  real_vector_max is (resolved_max) real_vector ; 
  type     real_vector_max_c is array (natural range <>) of real_max ; -- for non VHDL-2008  

  function resolved_max ( s : string) return character ;             
  subtype  character_max is resolved_max character ; 
  subtype  string_max is (resolved_max) string ; 
  type     string_max_c is array (positive range <>) of character_max ; -- for non VHDL-2008  

  function resolved_max ( s : boolean_vector) return boolean ;       
  subtype  boolean_max is resolved_max boolean ; 
  subtype  boolean_vector_max is (resolved_max) boolean_vector ; 
  type     boolean_vector_max_c is array (natural range <>) of boolean_max ; -- for non VHDL-2008  

  
  -- return sum of values that /= type'left
  -- No initializations required on ports, default of type'left is ok
  function resolved_sum ( s : integer_vector ) return integer ;      
  subtype  integer_sum is resolved_sum integer ; 
  subtype  integer_vector_sum is (resolved_sum) integer_vector ; 
  type     integer_vector_sum_c is array (natural range <>) of integer_sum ; -- for non VHDL-2008  

  function resolved_sum ( s : time_vector ) return time ;            
  subtype  time_sum is resolved_sum time ; 
  subtype  time_vector_sum is (resolved_sum) time_vector ; 
  type     time_vector_sum_c is array (natural range <>) of time_sum ; -- for non VHDL-2008  

  function resolved_sum ( s : real_vector ) return real ;            
  subtype  real_sum is resolved_sum real ; 
  subtype  real_vector_sum is (resolved_sum) real_vector ; 
  type     real_vector_sum_c is array (natural range <>) of real_sum ; -- for non VHDL-2008  

  
  -- resolved_weak
  -- Special just for std_ulogic
  -- No initializations required on ports, default of type'left is ok
  function resolved_weak (s : std_ulogic_vector) return std_ulogic ;  -- no init, type'left
  subtype  std_logic_weak is resolved_weak std_ulogic ; 
  subtype  std_logic_vector_weak is (resolved_weak) std_ulogic_vector ;  


  -- legacy stuff
  -- requires ports to be initialized to 0 in the appropriate type.  
  function resolved ( s : integer_vector ) return integer ;     
  subtype  resolved_integer is resolved integer ;

  function resolved ( s : time_vector ) return time ; 
  subtype  resolved_time is resolved time ;

  function resolved ( s : real_vector ) return real ; 
  subtype  resolved_real is resolved real ;
  
  function resolved (s : string) return character ;      -- same as resolved_max
  subtype  resolved_character is resolved character ;
  -- subtype  resolved_string is (resolved) string ;  -- subtype will replace type later 
  type resolved_string is array (positive range <>) of resolved_character;  -- will change to subtype -- assert but no init

  function resolved ( s : boolean_vector) return boolean ;  --same as resolved_max  
  subtype  resolved_boolean is resolved boolean ;

end package ResolutionPkg ;
package body ResolutionPkg is 

  -- resolved_max
  -- return maximum value.  Assert FAILURE if more than 1 /= type'left
  -- No initializations required on ports, default of type'left is ok

  -- Optimized version is just the following:  
  --  ------------------------------------------------------------
  --  function resolved_max ( s : <array_type> ) return <element_type> is 
  --  ------------------------------------------------------------
  --  begin
  --    return maximum(s) ;  
  --  end function resolved_max ; 

  ------------------------------------------------------------
  function resolved_max (s : std_ulogic_vector) return std_ulogic is 
  ------------------------------------------------------------ 
  begin
    return maximum(s) ; 
  end function resolved_max ; 

  ------------------------------------------------------------
  function resolved_max ( s : bit_vector ) return bit is 
  ------------------------------------------------------------ 
  begin
    return maximum(s) ; 
  end function resolved_max ; 

  ------------------------------------------------------------
  function resolved_max ( s : integer_vector ) return integer is 
  ------------------------------------------------------------ 
  begin
    return maximum(s) ; 
  end function resolved_max ; 
  
  ------------------------------------------------------------
  function resolved_max ( s : time_vector ) return time is 
  ------------------------------------------------------------
  begin
    return maximum(s) ; 
  end function resolved_max ; 

  ------------------------------------------------------------
  function resolved_max ( s : real_vector ) return real is 
  ------------------------------------------------------------
  begin
    return maximum(s) ; 
  end function resolved_max ; 
  
  ------------------------------------------------------------
  function resolved_max ( s : string ) return character is 
  ------------------------------------------------------------
  begin
    return maximum(s) ; 
  end function resolved_max ; 

  ------------------------------------------------------------
  function resolved_max ( s : boolean_vector) return boolean is
  ------------------------------------------------------------
  begin
    return maximum(s) ; 
  end function resolved_max ; 

  
  -- resolved_sum - appropriate for numeric types
  -- return sum of values that /= type'left
  -- No initializations required on ports, default of type'left is ok
  ------------------------------------------------------------
  function resolved_sum ( s : integer_vector ) return integer is 
  ------------------------------------------------------------
    variable result : integer := 0 ; 
  begin
    for i in s'RANGE loop
      if s(i) /= integer'left then 
        result := s(i) + result;
      end if ;
    end loop ;
    return result ; 
  end function resolved_sum ; 
  
  ------------------------------------------------------------
  function resolved_sum ( s : time_vector ) return time is 
  ------------------------------------------------------------
    variable result : time := 0 sec ; 
  begin
    for i in s'RANGE loop
      if s(i) /= time'left then 
        result := s(i) + result;
      end if ;
    end loop ;
    return result ; 
  end function resolved_sum ; 

  ------------------------------------------------------------
  function resolved_sum ( s : real_vector ) return real is 
  ------------------------------------------------------------
    variable result : real := 0.0 ; 
  begin
    for i in s'RANGE loop
      if s(i) /= real'left then 
        result := s(i) + result;
      end if ;
    end loop ;
    return result ; 
  end function resolved_sum ; 
  
  
  -- resolved_weak
  -- Special just for std_ulogic
  -- No initializations required on ports, default of type'left is ok
  type stdlogic_table is array(STD_ULOGIC, STD_ULOGIC) of STD_ULOGIC;

  constant weak_resolution_table : stdlogic_table := (
    --  Resolution order:  Z < U < W < X < - < L < H < 0 < 1
    --      ---------------------------------------------------------
    --      |  U    X    0    1    Z    W    L    H    -        |   |  
    --      ---------------------------------------------------------
             ('U', 'X', '0', '1', 'U', 'W', 'L', 'H', '-'),  -- | U |
             ('X', 'X', '0', '1', 'X', 'X', 'L', 'H', '-'),  -- | X |
             ('0', '0', '0', '1', '0', '0', '0', '0', '0'),  -- | 0 |
             ('1', '1', '1', '1', '1', '1', '1', '1', '1'),  -- | 1 |
             ('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', '-'),  -- | Z |
             ('W', 'X', '0', '1', 'W', 'W', 'L', 'H', '-'),  -- | W |
             ('L', 'L', '0', '1', 'L', 'L', 'L', 'H', 'L'),  -- | L |
             ('H', 'H', '0', '1', 'H', 'H', 'W', 'H', 'H'),  -- | H |
             ('-', '-', '0', '1', '-', '-', 'L', 'H', '-')   -- | - |
             );
             
  ------------------------------------------------------------
  function resolved_weak (s : std_ulogic_vector) return std_ulogic is
  ------------------------------------------------------------
    variable result : std_ulogic := 'Z' ; 
  begin
    for i in s'RANGE loop
      result := weak_resolution_table(result, s(i)) ; 
    end loop ;
    return result ; 
  end function resolved_weak ; 

  
  -- legacy stuff.
  -- requires ports to be initialized to 0 in the appropriate type.  
  
  ------------------------------------------------------------
  function resolved ( s : integer_vector ) return integer is 
  -- requires interface to be initialized to 0
  ------------------------------------------------------------
    variable result : integer := 0 ; 
    variable failed : boolean := FALSE ; 
  begin
    for i in s'RANGE loop
      if s(i) /= 0 then 
        failed := failed or (result /= 0) ;
        result := maximum(s(i),result);
      end if ;
    end loop ;
    assert not failed report "ResolutionPkg.resolved: multiple drivers on integer" severity MULTIPLE_DRIVER_SEVERITY ; 
    -- AlertIf(OSVVM_ALERTLOG_ID, failed, "ResolutionPkg.resolved: multiple drivers on integer") ; 
    return result ; 
  end function resolved ; 

  ------------------------------------------------------------
  function resolved ( s : time_vector ) return time is 
  -- requires interface to be initialized to 0 ns
  ------------------------------------------------------------
    variable result : time := 0 ns ; 
    variable failed : boolean := FALSE ; 
  begin
    for i in s'RANGE loop
      if s(i) > 0 ns then 
        failed := failed or (result /= 0 ns) ;
        result := maximum(s(i),result);
      end if ;
    end loop ;
    assert not failed report "ResolutionPkg.resolved: multiple drivers on time" severity MULTIPLE_DRIVER_SEVERITY ; 
    -- AlertIf(OSVVM_ALERTLOG_ID, failed, "ResolutionPkg.resolved: multiple drivers on time") ; 
    return result ; 
  end function resolved ; 

  ------------------------------------------------------------
  function resolved ( s : real_vector ) return real is 
  -- requires interface to be initialized to 0.0
  ------------------------------------------------------------
    variable result : real := 0.0 ; 
    variable failed : boolean := FALSE ; 
  begin
    for i in s'RANGE loop
      if s(i) /= 0.0 then 
        failed := failed or (result /= 0.0) ;
        result := maximum(s(i),result);
      end if ;
    end loop ;
    assert not failed report "ResolutionPkg.resolved: multiple drivers on real" severity MULTIPLE_DRIVER_SEVERITY ; 
    -- AlertIf(OSVVM_ALERTLOG_ID, failed, "ResolutionPkg.resolved: multiple drivers on real") ; 
    return result ; 
  end function resolved ; 

  ------------------------------------------------------------
  function resolved (s : string) return character is  
  -- same as resolved_max
  ------------------------------------------------------------
    variable result : character := NUL ; 
    variable failed : boolean := FALSE ; 
  begin
    for i in s'RANGE loop
      if s(i) /= NUL then 
        failed := failed or (result /= NUL) ;
        result := maximum(result, s(i)) ; 
      end if ; 
    end loop ;
    assert not failed report "ResolutionPkg.resolved: multiple drivers on character" severity MULTIPLE_DRIVER_SEVERITY ; 
    -- AlertIf(OSVVM_ALERTLOG_ID, failed, "ResolutionPkg.resolved: multiple drivers on character") ; 
    return result ; 
  end function resolved ; 

  ------------------------------------------------------------
  function resolved ( s : boolean_vector) return boolean is
  -- same as resolved_max
  ------------------------------------------------------------
    variable result : boolean := FALSE ; 
    variable failed : boolean := FALSE ; 
  begin
    for i in s'RANGE loop
      if s(i) then 
        failed := failed or result ; 
        result := TRUE ;
      end if ; 
    end loop ;
    assert not failed report "ResolutionPkg.resolved: multiple drivers on boolean" severity MULTIPLE_DRIVER_SEVERITY ; 
    -- AlertIf(OSVVM_ALERTLOG_ID, failed, "ResolutionPkg.resolved: multiple drivers on boolean") ; 
    return result ; 
  end function resolved ; 

end package body ResolutionPkg ;
