---------------------------------------------------------------------
-- 
-- Package fix_std
-- Fixed point arithmetic based on numeric_std
-- 
---------------------------------------------------------------------
-- 
-- This document describes a VHDL package of definitions and subprograms 
-- intended to support the use of fixed-point arithmetic in test benches 
-- and synthesisable designs.  This document and the package it describes 
-- are made freely available to the HDL design community without warranty 
-- of any kind.  You are welcome to make use of this information for your 
-- own private study and in your own designs.  If you make use of the 
-- package, you accept sole responsibility for its fitness for purpose 
-- and its suitability in your application.  You are free to modify the 
-- package in any way, and to record your contribution to it, but this 
-- notice must appear in a prominent place in any modified or derived 
-- version of the package or its supporting documentation.
-- 
-- The author wishes to thank his employer Doulos Ltd for making 
-- available the facilities used to develop, test and distribute this 
-- package.  However, Doulos Ltd accepts no responsibility for the 
-- package's contents and cannot support it in any way.
-- 
---------------------------------------------------------------------
-- Revision information:
-- 
-- Version 0.1  06-May-2003
--   Alpha version, for review
--   No division operators are provided, pending detailed
--   consultation on their functionality.
--   Some subprogram implementations are unnecessarily inefficient.
-- Version 0.2 11-Jun-2003
--   Fixes aiming to make the package portable across all synthesis tools:
--   * Removed deferred constants, made them package constants
--   * Removed all variable initialisations in procedures, made them
--     procedural initialisations in the code
---------------------------------------------------------------------

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

package fix_std is

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

  -- Integer subtype specifying legal values for a bit index.
  -- At present it's restricted to 'natural' to conform with
  -- the behaviour of mainstream synthesis tools.  For simulation,
  -- or in the future when synthesis tools are able to cope, it
  -- would be possible to change this subtype to be the full
  -- integer range, thus allowing negative subscripts for
  -- fraction bits.
  --
  subtype Fix_Subscr is natural;
  
  -- Fixed-point offset, the bit number (subscript) used for
  -- the bit in a UFix or SFix vector having binary weight 2^0
  -- (the units bit).
  --
  constant FixP: Fix_Subscr := 100;

  -- Type declarations for the basic unsigned and signed fixed point
  -- data types:
  --
  type UFix is array (Fix_Subscr range <>) of std_logic;
  type SFix is array (Fix_Subscr range <>) of std_logic;

  -- Type declarations for control of rounding and overflow modes:
  --
  type Fix_Rounding_Mode is (
    clip_LS,      -- Throw away unwanted least significant bits
    towards_zero, -- Round towards zero - same as clip_LS for UFix
    to_nearest    -- Round to nearest.  Exact halves round up.
  );
  type Fix_Overflow_Mode is (
    clip_MS,      -- Throw away unwanted most significant bits
    saturate      -- Saturate overflow to nearest representable value
  );

  -- Defaults for these modes:
  --
  constant Fix_Default_Rounding : Fix_Rounding_Mode := clip_LS;
  constant Fix_Default_Overflow : Fix_Overflow_Mode := clip_MS;

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

  ---------------------------
  -- E.  Extraction functions
  ---------------------------

  -- E.1.  Return the integral part of a UFix value
  function Int(U: UFix) return UFix;

  -- E.2.  Return the fractional part of a UFix value
  function Frac(U: UFix) return UFix;

  -- E.3.  Return the integral part of a SFix value
  function Int(S: SFix) return SFix;

  -- E.4.  Return the fractional part of a SFix value
  function Frac(S: SFix) return UFix;

  -- E.5.  Widen a SFix value if necessary so that
  --       its range adjoins or spans the binary point
  function Span(S: SFix) return SFix;

  -- E.6.  Widen a UFix value if necessary so that
  --       its range adjoins or spans the binary point
  function Span(U: UFix) return UFix;
  
  ---------------------------
  -- T.  Conversion functions
  ---------------------------

  -- T.1 to T.8: Unsigned conversions
  --
  -- T.1.  Resizing an existing UFix.  Provide number of 
  --       integer bits and number of fraction bits.
  --
  function to_UFix(
    N         : UFix;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return UFix;

  -- T.2.  Resizing an existing SFix.  Provide number of 
  --       integer bits and number of fraction bits.
  --
  function to_UFix(
    N         : SFix;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return UFix;

  -- T.3.  Conversion from integer to UFix.  Provide number of 
  --       integer bits and number of fraction bits.  Note that 
  --       negative input is tolerated!
  --
  function to_UFix(
    N         : integer;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return UFix;

  -- T.4.  Conversion from unsigned to UFix.  Provide subscripts of 
  --       MS and (optionally) LS bit of the resulting UFix.
  --
  function to_UFix(
    N         : unsigned;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return UFix;

  -- T.5.  Conversion from  unsigned to UFix.  Automatically set the
  --       range of the resulting UFix to match the unsigned value,
  --       as an integral UFix value with no fraction bits.
  --
  function to_UFix( N : unsigned ) return UFix;

  -- T.6.  Conversion from UFix to unsigned.  All integer bits are
  --       preserved (including adding LS scale bits if necessary).
  --
  function to_unsigned(
    N        : UFix;
    rounding : Fix_Rounding_Mode   := Fix_Default_Rounding
  ) return unsigned;

  -- T.7.  Conversion from UFix to unsigned.  Caller specifies
  --       required number of bits in unsigned result.
  --
  function to_unsigned(
    N        : UFix;
    bits     : positive;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return unsigned;

  -- T.8.  Conversion from UFix to integer. Up to 31 integer bits are
  --       preserved (including adding LS scale bits if necessary).
  --
  function to_integer(
    N        : UFix;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return integer;


  -- T.9 to T.16: Signed conversions
  --
  -- T.9.  Resizing an existing UFix.  Provide number of 
  --       integer bits and number of fraction bits.
  --
  function to_SFix(
    N         : UFix;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return SFix;

  -- T.10. Resizing an existing SFix.  Provide number of 
  --       integer bits and number of fraction bits.
  --
  function to_SFix(
    N         : SFix;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return SFix;

  -- T.11. Conversion from integer to SFix.  Provide number of 
  --       integer bits and number of fraction bits.
  --
  function to_SFix(
    N         : integer;
    MSB_index : Fix_Subscr;
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return SFix;

  -- T.12. Conversion from signed to SFix.  Provide subscripts of 
  --       MS and (optionally) LS bit of the resulting SFix.
  --
  function to_SFix(
    N         : signed;
    MSB_index : Fix_Subscr;      
    LSB_index : Fix_Subscr        := FixP;
    overflow  : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding  : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return SFix;

  -- T.13. Conversion from signed to SFix.  Automatically set the
  --       range of the resulting SFix to match the signed value,
  --       as an integral SFix value with no fraction bits.
  --
  function to_SFix( N : signed ) return SFix;

  -- T.14. Conversion from SFix to signed.  All integer bits are
  --       preserved (including adding LS scale bits if necessary).
  --
  function to_signed(
    N        : SFix;
    rounding : Fix_Rounding_Mode   := Fix_Default_Rounding
  ) return signed;

  -- T.15. Conversion from SFix to signed.  Caller specifies
  --       required number of bits in signed result.
  --
  function to_signed(
    N        : SFix;
    bits     : positive;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return signed;

  -- T.16. Conversion from SFix to integer. Up to 32 integer bits are
  --       preserved (including adding LS scale bits if necessary).
  --
  function to_integer(
    N        : SFix;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  ) return integer;
  
  -- T.17. Conversion from UFix to SFix.  This simply adds
  --       an extra more significant bit, set to zero.
  --
  function  to_SFix(U: UFix) return SFix;

  ----------------------------------
  -- V.  Copy-to-variable procedures
  ----------------------------------

  -- Range-aware copying of an expression into a variable.  The
  -- ranges of destination variable and source expression are 
  -- used to determine correct rounding, overflow and scaling
  -- behaviour.

  -- V.1 to V.5: Copy an expression into a UFix variable
  --

  -- V.1. Copy UFix to UFix
  --
  procedure Copy_V(
    target   : out UFix;
    source   : UFix;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );
  --
  -- V.2. Copy SFix to UFix
  --
  procedure Copy_V(
    target   : out UFix;
    source   : SFix;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.3. Copy UNSIGNED to UFix
  --
  procedure Copy_V(
    target   : out UFix;
    source   : unsigned;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.4. Copy SIGNED to UFix
  --
  procedure Copy_V(
    target   : out UFix;
    source   : signed;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.5. Copy integer to UFix
  --
  procedure Copy_V(
    target   : out UFix;
    source   : integer;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.6 to V.10: Copy an expression into a SFix variable
  --

  -- V.6. Copy UFix to SFix
  --
  procedure Copy_V(
    target   : out SFix;
    source   : UFix;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.7. Copy SFix to SFix
  --
  procedure Copy_V(
    target   : out SFix;
    source   : SFix;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.8. Copy UNSIGNED to SFix
  --
  procedure Copy_V(
    target   : out SFix;
    source   : unsigned;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.9. Copy SIGNED to SFix
  --
  procedure Copy_V(
    target   : out SFix;
    source   : signed;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- V.10. Copy integer to SFix
  --
  procedure Copy_V(
    target   : out SFix;
    source   : integer;
    overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
    rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );


  --------------------------------
  -- S.  Copy-to-signal procedures
  --------------------------------
  --
  -- Range-aware copying of an expression into a signal.  The
  -- ranges of destination signal and source expression are 
  -- used to determine correct rounding, overflow and scaling
  -- behaviour.

  -- S.1 to S.5: Copy an expression into a UFix signal
  --

  -- S.1. Copy UFix to UFix
  --
  procedure Copy_S(
    signal target   : out UFix;
           source   : UFix;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.1. Copy SFix to UFix
  --
  procedure Copy_S(
    signal target   : out UFix;
           source   : SFix;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.3. Copy UNSIGNED to UFix
  --
  procedure Copy_S(
    signal target   : out UFix;
           source   : unsigned;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.4. Copy SIGNED to UFix
  --
  procedure Copy_S(
    signal target   : out UFix;
           source   : signed;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.5. Copy integer to UFix
  --
  procedure Copy_S(
    signal target   : out UFix;
           source   : integer;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.6 to S.10: Copy an expression into a SFix signal
  --

  -- S.6. Copy UFix to SFix
  --
  procedure Copy_S(
    signal target   : out SFix;
           source   : UFix;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.7. Copy SFix to SFix
  --
  procedure Copy_S(
    signal target   : out SFix;
           source   : SFix;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.8. Copy UNSIGNED to SFix
  --
  procedure Copy_S(
    signal target   : out SFix;
           source   : unsigned;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.9. Copy SIGNED to SFix
  --
  procedure Copy_S(
    signal target   : out SFix;
           source   : signed;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );

  -- S.10. Copy integer to SFix
  --
  procedure Copy_S(
    signal target   : out SFix;
           source   : integer;
           overflow : Fix_Overflow_Mode := Fix_Default_Overflow;
           rounding : Fix_Rounding_Mode := Fix_Default_Rounding
  );


  ------------------------------------------------------------------
  -- A.  Arithmetic operations involving UFix, SFix and other 
  --     numeric types.
  --     The operators are overloaded for most of the sensible
  --     combinations of SFix, UFix, UNSIGNED, SIGNED and INTEGER.
  --
  -- IMPORTANT NOTE:
  --   Arithmetic operators return a result that is wide enough
  --   and precise enough so that no information is lost.  THIS IS
  --   SIGNIFICANTLY DIFFERENT FROM THE BEHAVIOUR OF numeric_std.
  --   In the detailed description that follow, "scaling" means
  --   the numerical value (weight) of the least significant bit
  --   in a fixed-point value.
  --
  -- ADDITION returns a result whose least significant bit
  -- is the same as the least significant bit in either operand,
  -- and whose most significant bit is one position higher than
  -- the most significant bit in either operand.  Addition of 
  -- two operands having the same bounds therefore results in
  -- a growth of one bit at the most significant end.
  --
  -- SUBTRACTION where one or both operands are signed behaves 
  -- in the same way as addition.  Subtraction where both operands
  -- are unsigned returns a result whose most significant bit
  -- position is the same as the most significant bit in either
  -- operand, and whose least significant bit is the same as the
  -- least significant bit in either operand.
  --
  -- MULTIPLICATION returns a result whose width is the sum of
  -- the widths of its two operands, and whose scaling is the 
  -- product of its two operands' scalings.
  --
  -- UNARY NEGATION always gives a result having one more 
  -- significant bit than the operand.
  --
  -- ABSOLUTE VALUE always gives a result having exactly the
  -- same subtype as its operand.
  --
  -- In binary operations where one operand is a fixed-point type
  -- and the other is an integer numeric type, the integer operand
  -- is first converted to a fixed-point type of the same subtype
  -- as the other operand using Copy_V with default rounding and 
  -- overflow modes.  The operation is then performed between two 
  -- fixed-point operands in the normal way.
  --
  ------------------------------------------------------------------


  ------------------------------------
  -- A.1.  Unary "-" negation operator
  ------------------------------------

  -- A.1.1.  SFix := - UFix
  function "-" (R: UFix) return SFix;

  -- A.1.2.  SFix := - SFix
  function "-" (R: SFix) return SFix;


  --------------------------------------------
  -- A.2.  Unary "abs" absolute-value operator
  --------------------------------------------

  -- A.2.1.  SFix := abs SFix
  function "abs" (R: SFix) return SFix;


  -------------------------------------
  -- A.3.  Binary "+" addition operator
  -------------------------------------

  -- A.3.1.  UFix := UFix + UFix
  function "+" (L: UFix; R: UFix) return UFix;

  -- A.3.2.  UFix := UFix + unsigned
  function "+" (L: UFix; R: unsigned) return UFix;

  -- A.3.3.  UFix := unsigned + UFix
  function "+" (L: unsigned; R: UFix) return UFix;

  -- A.3.4.  UFix := UFix + natural
  function "+" (L: UFix; R: natural) return UFix;

  -- A.3.5.  UFix := natural + UFix
  function "+" (L: natural; R: UFix) return UFix;

  -- A.3.6.  SFix := SFix + SFix
  function "+" (L: SFix; R: SFix) return SFix;

  -- A.3.7.  SFix := SFix + UFix
  function "+" (L: SFix; R: UFix) return SFix;

  -- A.3.8.  SFix := UFix + SFix
  function "+" (L: UFix; R: SFix) return SFix;

  -- A.3.9.  SFix := SFix + signed
  function "+" (L: SFix; R: signed) return SFix;

  -- A.3.10. SFix := signed + SFix
  function "+" (L: signed; R: SFix) return SFix;

  -- A.3.11. SFix := SFix + integer
  function "+" (L: SFix; R: integer) return SFix;

  -- A.3.12. SFix := integer + SFix
  function "+" (L: integer; R: SFix) return SFix;


  ----------------------------------------
  -- A.4.  Binary "-" subtraction operator
  ----------------------------------------
  --
  -- NOTE: There is a special problem with subtraction 
  -- operators that return a UFix result if that result
  -- goes negative.  Our arbitrary decision is that we
  -- truncate most-significant bits in this case.  If you
  -- wish to avoid the risk of this arbitrarily-defined
  -- truncation behaviour, change one or more of your 
  -- operands to SFix and get a SFix result using this
  -- idiom:
  --   SFix := UFix + (-UFix)
  -- or copy one of the UFix operands into a SFix that's
  -- one bit wider, before performing the operation.
  --
  -- Subtractions returning a UFix result take unsigned
  -- operands and do not exhibit bit growth.
  -- Subtractions returning a SFix result take signed or
  -- unsigned operands and exhibit one-bit growth like addition.

  -- A.4.1.  UFix := UFix - UFix
  function "-" (L: UFix; R: UFix) return UFix;

  -- A.4.2.  UFix := UFix - unsigned
  function "-" (L: UFix; R: unsigned) return UFix;

  -- A.4.3.  UFix := unsigned - UFix
  function "-" (L: unsigned; R: UFix) return UFix;

  -- A.4.4.  UFix := UFix - natural
  function "-" (L: UFix; R: natural) return UFix;

  -- A.4.5.  UFix := natural - UFix
  function "-" (L: natural; R: UFix) return UFix;

  -- A.4.6.  SFix := SFix - SFix
  function "-" (L: SFix; R: SFix) return SFix;

  -- A.4.7.  SFix := SFix - UFix
  function "-" (L: SFix; R: UFix) return SFix;

  -- A.4.8.  SFix := UFix - SFix
  function "-" (L: UFix; R: SFix) return SFix;

  -- A.4.9.  SFix := SFix - signed
  function "-" (L: SFix; R: signed) return SFix;

  -- A.4.10. SFix := signed - SFix
  function "-" (L: signed; R: SFix) return SFix;

  -- A.4.11. SFix := SFix - integer
  function "-" (L: SFix; R: integer) return SFix;

  -- A.4.12. SFix := integer - SFix
  function "-" (L: integer; R: SFix) return SFix;


  -------------------------------------------
  -- A.5.  Binary "*" multiplication operator
  -------------------------------------------

  -- A.5.1.  UFix := UFix * UFix
  function "*" (L: UFix; R: UFix) return UFix;

  -- A.5.2.  UFix := UFix * unsigned
  function "*" (L: UFix; R: unsigned) return UFix;

  -- A.5.3.  UFix := unsigned * UFix
  function "*" (L: unsigned; R: UFix) return UFix;

  -- A.5.4.  UFix := UFix * natural
  function "*" (L: UFix; R: natural) return UFix;

  -- A.5.5.  UFix := natural * UFix
  function "*" (L: natural; R: UFix) return UFix;

  -- A.5.6.  SFix := SFix * SFix
  function "*" (L: SFix; R: SFix) return SFix;

  -- A.5.7.  SFix := SFix * UFix
  function "*" (L: SFix; R: UFix) return SFix;

  -- A.5.8.  SFix := UFix * SFix
  function "*" (L: UFix; R: SFix) return SFix;

  -- A.5.9.  SFix := SFix * signed
  function "*" (L: SFix; R: signed) return SFix;

  -- A.5.10. SFix := signed * SFix
  function "*" (L: signed; R: SFix) return SFix;

  -- A.5.11. SFix := SFix * integer
  function "*" (L: SFix; R: integer) return SFix;

  -- A.5.12. SFix := integer * SFix
  function "*" (L: integer; R: SFix) return SFix;


  ------------------------------------------------------------------
  -- R.  Relational operators - arithmetic comparisons involving  
  --     UFix, SFix and other numeric types.
  --     The operators are overloaded for most of the sensible
  --     combinations of SFix, UFix, UNSIGNED, SIGNED and INTEGER.
  --     Note that in all cases comparisons are exact;  if one 
  --     operand has more fraction bits than the other, the less 
  --     precise operand will have its LSBs zero-extended, and 
  --     these zero bits will take part in comparison with whatever 
  --     LSBs exist in the more precise operand.
  ------------------------------------------------------------------

  -------------------------------------
  -- R.1.  Binary "=" equality operator
  -------------------------------------

  -- R.1.1.   UFix = UFix
  function "=" (L: UFix; R: UFix) return boolean;

  -- R.1.2.   UFix = unsigned
  function "=" (L: UFix; R: unsigned) return boolean;

  -- R.1.3.   unsigned = UFix
  function "=" (L: unsigned; R: UFix) return boolean;

  -- R.1.4.   UFix = integer
  function "=" (L: UFix; R: integer) return boolean;

  -- R.1.5.   integer = UFix
  function "=" (L: integer; R: UFix) return boolean;

  -- R.1.6.   SFix = SFix
  function "=" (L: SFix; R: SFix) return boolean;

  -- R.1.7.   SFix = UFix
  function "=" (L: SFix; R: UFix) return boolean;

  -- R.1.8.   UFix = SFix
  function "=" (L: UFix; R: SFix) return boolean;

  -- R.1.9.   SFix = signed
  function "=" (L: SFix; R: signed) return boolean;

  -- R.1.10.  signed = SFix
  function "=" (L: signed; R: SFix) return boolean;

  -- R.1.11.  SFix = integer
  function "=" (L: SFix; R: integer) return boolean;

  -- R.1.12.  integer = SFix
  function "=" (L: integer; R: SFix) return boolean;


  --------------------------------------
  -- R.2.  Binary "<" less-than operator
  --------------------------------------

  -- R.2.1.   UFix < UFix
  function "<" (L: UFix; R: UFix) return boolean;

  -- R.2.2.   UFix < unsigned
  function "<" (L: UFix; R: unsigned) return boolean;

  -- R.2.3.   unsigned < UFix
  function "<" (L: unsigned; R: UFix) return boolean;

  -- R.2.4.   UFix < integer
  function "<" (L: UFix; R: integer) return boolean;

  -- R.2.5.   integer < UFix
  function "<" (L: integer; R: UFix) return boolean;

  -- R.2.6.   SFix < SFix
  function "<" (L: SFix; R: SFix) return boolean;

  -- R.2.7.   SFix < UFix
  function "<" (L: SFix; R: UFix) return boolean;

  -- R.2.8.   UFix < SFix
  function "<" (L: UFix; R: SFix) return boolean;

  -- R.2.9.   SFix < signed
  function "<" (L: SFix; R: signed) return boolean;

  -- R.2.10.  signed < SFix
  function "<" (L: signed; R: SFix) return boolean;

  -- R.2.11.  SFix < integer
  function "<" (L: SFix; R: integer) return boolean;

  -- R.2.12.  integer < SFix
  function "<" (L: integer; R: SFix) return boolean;


  ----------------------------------------
  -- R.3.  Binary "/=" inequality operator
  ----------------------------------------

  -- R.3.1.   UFix /= UFix
  function "/=" (L: UFix; R: UFix) return boolean;

  -- R.3.2.   UFix /= unsigned
  function "/=" (L: UFix; R: unsigned) return boolean;

  -- R.3.3.   unsigned /= UFix
  function "/=" (L: unsigned; R: UFix) return boolean;

  -- R.3.4.   UFix /= integer
  function "/=" (L: UFix; R: integer) return boolean;

  -- R.3.5.   integer /= UFix
  function "/=" (L: integer; R: UFix) return boolean;

  -- R.3.6.   SFix /= SFix
  function "/=" (L: SFix; R: SFix) return boolean;

  -- R.3.7.   SFix /= UFix
  function "/=" (L: SFix; R: UFix) return boolean;

  -- R.3.8.   UFix /= SFix
  function "/=" (L: UFix; R: SFix) return boolean;

  -- R.3.9.   SFix /= signed
  function "/=" (L: SFix; R: signed) return boolean;

  -- R.3.10.  signed /= SFix
  function "/=" (L: signed; R: SFix) return boolean;

  -- R.3.11.  SFix /= integer
  function "/=" (L: SFix; R: integer) return boolean;

  -- R.3.12.  integer /= SFix
  function "/=" (L: integer; R: SFix) return boolean;


  -----------------------------------------
  -- R.4.  Binary ">" greater-than operator
  -----------------------------------------

  -- R.4.1.   UFix > UFix
  function ">" (L: UFix; R: UFix) return boolean;

  -- R.4.2.   UFix > unsigned
  function ">" (L: UFix; R: unsigned) return boolean;

  -- R.4.3.   unsigned > UFix
  function ">" (L: unsigned; R: UFix) return boolean;

  -- R.4.4.   UFix > integer
  function ">" (L: UFix; R: integer) return boolean;

  -- R.4.5.   integer > UFix
  function ">" (L: integer; R: UFix) return boolean;

  -- R.4.6.   SFix > SFix
  function ">" (L: SFix; R: SFix) return boolean;

  -- R.4.7.   SFix > UFix
  function ">" (L: SFix; R: UFix) return boolean;

  -- R.4.8.   UFix > SFix
  function ">" (L: UFix; R: SFix) return boolean;

  -- R.4.9.   SFix > signed
  function ">" (L: SFix; R: signed) return boolean;

  -- R.4.10.  signed > SFix
  function ">" (L: signed; R: SFix) return boolean;

  -- R.4.11.  SFix > integer
  function ">" (L: SFix; R: integer) return boolean;

  -- R.4.12.  integer > SFix
  function ">" (L: integer; R: SFix) return boolean;


  ----------------------------------------------
  -- R.5.  Binary ">=" greater-or-equal operator
  ----------------------------------------------

  -- R.5.1.   UFix >= UFix
  function ">=" (L: UFix; R: UFix) return boolean;

  -- R.5.2.   UFix >= unsigned
  function ">=" (L: UFix; R: unsigned) return boolean;

  -- R.5.3.   unsigned >= UFix
  function ">=" (L: unsigned; R: UFix) return boolean;

  -- R.5.4.   UFix >= integer
  function ">=" (L: UFix; R: integer) return boolean;

  -- R.5.5.   integer >= UFix
  function ">=" (L: integer; R: UFix) return boolean;

  -- R.5.6.   SFix >= SFix
  function ">=" (L: SFix; R: SFix) return boolean;

  -- R.5.7.   SFix >= UFix
  function ">=" (L: SFix; R: UFix) return boolean;

  -- R.5.8.   UFix >= SFix
  function ">=" (L: UFix; R: SFix) return boolean;

  -- R.5.9.   SFix >= signed
  function ">=" (L: SFix; R: signed) return boolean;

  -- R.5.10.  signed >= SFix
  function ">=" (L: signed; R: SFix) return boolean;

  -- R.5.11.  SFix >= integer
  function ">=" (L: SFix; R: integer) return boolean;

  -- R.5.12.  integer >= SFix
  function ">=" (L: integer; R: SFix) return boolean;


  -------------------------------------------
  -- R.6.  Binary "<=" less-or-equal operator
  -------------------------------------------

  -- R.6.1.   UFix <= UFix
  function "<=" (L: UFix; R: UFix) return boolean;

  -- R.6.2.   UFix <= unsigned
  function "<=" (L: UFix; R: unsigned) return boolean;

  -- R.6.3.   unsigned <= UFix
  function "<=" (L: unsigned; R: UFix) return boolean;

  -- R.6.4.   UFix <= integer
  function "<=" (L: UFix; R: integer) return boolean;

  -- R.6.5.   integer <= UFix
  function "<=" (L: integer; R: UFix) return boolean;

  -- R.6.6.   SFix <= SFix
  function "<=" (L: SFix; R: SFix) return boolean;

  -- R.6.7.   SFix <= UFix
  function "<=" (L: SFix; R: UFix) return boolean;

  -- R.6.8.   UFix <= SFix
  function "<=" (L: UFix; R: SFix) return boolean;

  -- R.6.9.   SFix <= signed
  function "<=" (L: SFix; R: signed) return boolean;

  -- R.6.10.  signed <= SFix
  function "<=" (L: signed; R: SFix) return boolean;

  -- R.6.11.  SFix <= integer
  function "<=" (L: SFix; R: integer) return boolean;

  -- R.6.12.  integer <= SFix
  function "<=" (L: integer; R: SFix) return boolean;


  ------------------------------------------------------------------
  -- C.  Concatenation operators between fixed-point operands, and
  --     between fixed-point operands and other reasonable types.
  --     Unlike the implicitly defined "&" operator, they preserve
  --     place value and return an appropriately aligned subtype.
  --     Preservation of place value means that some concatenation
  --     operations are illegal.  In particular, operations
  --     [SFix & SFix] and [UFix & SFix] are illegal, and 
  --     the place values of operands in [SFix & UFix] and 
  --     [UFix & UFix] must match up - the rightmost subscript of
  --     the left operand must be one higher than the leftmost
  --     subscript of the right operand.
  --     Single bits of type std_ulogic may be concatenated with
  --     fixed-point types where there is no risk of losing 
  --     sign-extension information.
  --     Because of the way VHDL defines implicit concatenation,
  --     it is impossible to detect all these errors at compile time.
  --     Instead they are detected by assertion statements at run time.
  --     Tool vendors may choose to implement compile-time checks
  --     so that the run-time checking overhead can be avoided.
  ------------------------------------------------------------------

  -- C.1.1.   UFix := UFix & UFix
  function "&" (L: UFix; R: UFix) return UFix;
  
  -- No need to define "&"[UFix, SFix] explicitly,  because
  -- the types are incompatible and so there's no default

  -- C.1.2.   UFix := UFix & std_ulogic
  function "&" (L: UFix; R: std_ulogic) return UFix;

  -- C.1.3.   UFix := std_ulogic & UFix
  function "&" (L: std_ulogic; R: UFix) return UFix;


  -- C.2.1.   SFix := SFix & UFix
  function "&" (L: SFix; R: UFix) return SFix;

  -- C.2.2.   SFix := SFix & SFix -- ILLEGAL
  function "&" (L: SFix; R: SFix) return SFix;

  -- C.2.3.   SFix := SFix & std_ulogic
  function "&" (L: SFix; R: std_ulogic) return SFix;

  -- C.2.4.   SFix := std_ulogic & SFix
  function "&" (L: std_ulogic; R: SFix) return SFix;


end; -- package fix_std;
