
/*
  ===========================================================================
   File: ENH40.C                                         v.2.3 - 30.Nov.2009
  ===========================================================================

            ITU-T  STL  BASIC OPERATORS

            40-BIT ARITHMETIC OPERATORS

   History:
   07 Nov 04   v2.0     Incorporation of new 32-bit / 40-bit / control
                        operators for the ITU-T Standard Tool Library as
                        described in Geneva, 20-30 January 2004 WP 3/16 Q10/16
                        TD 11 document and subsequent discussions on the
                        wp3audio@yahoogroups.com email reflector.

  ============================================================================
*/


/*****************************************************************************
 *
 *  Enhanced 40 bit operators :
 *
 *    L40_add()
 *    L40_sub()
 *    L40_abs()
 *    L40_negate()
 *    L40_max()
 *    L40_min()
 *    L40_shr()
 *    L40_shr_r()
 *    L40_shl()
 *    L40_shl_r()
 *    norm_L40()
 *    L40_mult()
 *    L40_mac()
 *    L40_msu()
 *    mac_r40()
 *    msu_r40()
 *    Mpy_32_16_ss()
 *    Mpy_32_32_ss()
 *    L40_lshl()
 *    L40_lshr()
 *    L40_round()
 *    L_saturate40()
 *    L40_set()
 *    Extract40_H()
 *    Extract40_L()
 *    L_Extract40()
 *    L40_deposit_h()
 *    L40_deposit_l()
 *    L40_deposit32()
 *
 *****************************************************************************/


/*****************************************************************************
 *
 *  Include-Files
 *
 *****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "stl.h"

namespace evs { 


/*****************************************************************************
 *
 *  Local Functions
 *
 *****************************************************************************/


/*****************************************************************************
 *
 *  Constants and Globals
 *
 *****************************************************************************/


/*****************************************************************************
 *
 *  Functions
 *
 *****************************************************************************/

/*****************************************************************************
 *
 *  Function Name : L40_shl
 *
 *  Purpose :
 *
 *    Arithmetically shifts left L40_var1 by var2 positions.
 *    - If var2 is negative, L40_var1 is shifted to the LSBits by (-var2)
 *      positions with extension of the sign bit.
 *    - If var2 is positive, L40_var1 is shifted to the MSBits by (var2)
 *      positions.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : MIN_16 <= var2 <= MAX_16.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_shl( Word40 L40_var1, Word16 var2)
{

    Word40 L40_var_out;
    Word40 L40_constant;

#if defined(_MSC_VER) && (_MSC_VER <= 1200)
    L40_constant = L40_set( 0xc000000000);
#else
    L40_constant = L40_set( 0xc000000000LL);
#endif

    if( var2 < 0)
    {
        var2 = -var2;
        L40_var_out = L40_shr( L40_var1, var2);
    }

    else
    {
        L40_var_out = L40_var1;

        for ( ; var2 > 0; var2--)
        {
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
            if( L40_var_out > 0x003fffffffff)
            {
#else
            if( L40_var_out > 0x003fffffffffLL)
            {
#endif
                Overflow = 1;
                exit(1);
                /*            L40_var_out = L40_OVERFLOW_OCCURED( L40_var_out); */
                break;
            }

            else if ( L40_var_out < L40_constant)
            {
                Overflow = 1;
                exit(2);
                /*            L40_var_out = L40_UNDERFLOW_OCCURED( L40_var_out); */
                break;
            }

            else
            {
                L40_var_out = L40_var_out << 1;
            }
        }
    }

    BASOP_CHECK();


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_shr
 *
 *  Purpose :
 *
 *    Arithmetically shifts right L40_var1 by var2 positions.
 *    - If var2 is positive, L40_var1 is shifted to the LSBits by (var2)
 *      positions with extension of the sign bit.
 *    - If var2 is negative, L40_var1 is shifted to the MSBits by (-var2)
 *      positions.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : MIN_16 <= var2 <= MAX_16.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_shr( Word40 L40_var1, Word16 var2)
{
    Word40 L40_var_out;

    if( var2 < 0)
    {
        var2 = -var2;
        L40_var_out  = L40_shl ( L40_var1, var2);
    }
    else
    {
        L40_var_out = L40_var1 >> var2;

    }


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_negate
 *
 *  Purpose :
 *
 *    Negates L40_var1.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_negate( Word40 L40_var1)
{
    Word40 L40_var_out;

    L40_var_out = L40_add( ~L40_var1, 0x01);

    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_add
 *
 *  Purpose :
 *
 *    Adds L40_var1 and L40_var2 and returns the 40-bit result.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    L40_var2    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var2 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_add( Word40 L40_var1, Word40 L40_var2)
{
    Word40 L40_var_out;

    L40_var_out = L40_var1 + L40_var2;

#if defined(_MSC_VER) && (_MSC_VER <= 1200)
    if(  ((( L40_var1    & 0x8000000000) >> 39) != 0)
            && ((( L40_var2    & 0x8000000000) >> 39) != 0)
            && ((( L40_var_out & 0x8000000000) >> 39) == 0))
    {
        Overflow = 1;
        exit(2);
        /*      L40_var_out = L40_UNDERFLOW_OCCURED( L40_var_out); */

    }
    else if( (((L40_var1    & 0x8000000000) >> 39) == 0)
             && (((L40_var2    & 0x8000000000) >> 39) == 0)
             && (((L40_var_out & 0x8000000000) >> 39) != 0))
    {
        Overflow = 1;
        exit(1);
        /*      L40_var_out = L40_OVERFLOW_OCCURED( L40_var_out); */
    }
#else
    if(  ((( L40_var1    & 0x8000000000LL) >> 39) != 0)
            && ((( L40_var2    & 0x8000000000LL) >> 39) != 0)
            && ((( L40_var_out & 0x8000000000LL) >> 39) == 0))
    {
        Overflow = 1;
        exit(2);
        /*      L40_var_out = L40_UNDERFLOW_OCCURED( L40_var_out); */

    }
    else if( (((L40_var1    & 0x8000000000LL) >> 39) == 0)
             && (((L40_var2    & 0x8000000000LL) >> 39) == 0)
             && (((L40_var_out & 0x8000000000LL) >> 39) != 0))
    {
        Overflow = 1;
        exit(1);
        /*      L40_var_out = L40_OVERFLOW_OCCURED( L40_var_out); */
    }
#endif

    BASOP_CHECK();


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_sub
 *
 *  Purpose :
 *
 *    Subtracts L40_var2 from L40_var1.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    L40_var2    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var2 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_sub( Word40 L40_var1, Word40 L40_var2)
{
    Word40 L40_var_out;

    L40_var_out = L40_var1 - L40_var2;

#if defined(_MSC_VER) && (_MSC_VER <= 1200)
    if( (((L40_var1    & 0x8000000000) >> 39) != 0)
            && (((L40_var2    & 0x8000000000) >> 39) == 0)
            && (((L40_var_out & 0x8000000000) >> 39) == 0))
    {
        Overflow = 1;
        exit(2);
        /*      L40_var_out = L40_UNDERFLOW_OCCURED( L40_var_out); */

    }
    else if( (((L40_var1    & 0x8000000000) >> 39) == 0)
             && (((L40_var2    & 0x8000000000) >> 39) != 0)
             && (((L40_var_out & 0x8000000000) >> 39) != 0))
    {
        Overflow = 1;
        exit(1);
        /*      L40_var_out = L40_OVERFLOW_OCCURED( L40_var_out); */
    }
#else
    if( (((L40_var1    & 0x8000000000LL) >> 39) != 0)
            && (((L40_var2    & 0x8000000000LL) >> 39) == 0)
            && (((L40_var_out & 0x8000000000LL) >> 39) == 0))
    {
        Overflow = 1;
        exit(2);
        /*      L40_var_out = L40_UNDERFLOW_OCCURED( L40_var_out); */

    }
    else if( (((L40_var1    & 0x8000000000LL) >> 39) == 0)
             && (((L40_var2    & 0x8000000000LL) >> 39) != 0)
             && (((L40_var_out & 0x8000000000LL) >> 39) != 0))
    {
        Overflow = 1;
        exit(1);
        /*      L40_var_out = L40_OVERFLOW_OCCURED( L40_var_out); */
    }
#endif

    BASOP_CHECK();


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_abs
 *
 *  Purpose :
 *
 *    Returns the absolute value of L40_var1.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : 0x00 0000 0000 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_abs( Word40 L40_var1)
{
    Word40 L40_var_out;

    if( L40_var1 < 0)
    {
        L40_var_out = L40_negate ( L40_var1);
    }
    else
    {
        L40_var_out = L40_var1;
    }


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_max
 *
 *  Purpose :
 *
 *    Compares L40_var1 and L40_var2 and returns the maximum value.
 *
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    L40_var2    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var2 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_max( Word40 L40_var1, Word40 L40_var2)
{
    Word40 L40_var_out;

    if( L40_var1 < L40_var2)
        L40_var_out = L40_var2;
    else
        L40_var_out = L40_var1;


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_min
 *
 *  Purpose :
 *
 *    Compares L40_var1 and L40_var2 and returns the minimum value.
 *
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    L40_var2    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var2 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_min( Word40 L40_var1, Word40 L40_var2)
{
    Word40 L40_var_out;

    if( L40_var1 < L40_var2)
        L40_var_out = L40_var1;
    else
        L40_var_out = L40_var2;


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L_saturate40
 *
 *  Purpose :
 *
 *    If L40_var1 is greater than MAX_32, returns MAX_32.
 *    If L40_var1 is lower   than MIN_32, returns MIN_32.
 *    If not,                             returns L_Extract40( L40_var1).
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L_var_out   32 bit long signed integer (Word32) whose value falls in
 *                the range : 0x8000 0000 <= L_var_out <= 0x7fff ffff.
 *
 *****************************************************************************/
Word32 L_saturate40( Word40 L40_var1)
{
    Word32 L_var_out;

    Word40 UNDER_L40_var2 = ( Word40) ~(((( Word40) 1) << 31) - ( Word40) 1 );
    Word40 OVER_L40_var2  = ( Word40)  (((( Word40) 1) << 31) - ( Word40) 1 );

    if( L40_var1 < UNDER_L40_var2)
    {
        L40_var1 = UNDER_L40_var2;
        Overflow = 1;
    }

    if( L40_var1 > OVER_L40_var2)
    {
        L40_var1 = OVER_L40_var2;
        Overflow = 1;
    }

    L_var_out = L_Extract40( L40_var1);

    BASOP_CHECK();


    return( L_var_out);
}


/*****************************************************************************
 *
 *  Function Name :  Mpy_32_16_ss
 *
 *  Purpose :
 *
 *    Multiplies the 2 signed values L_var1 and var2 with saturation control
 *    on 48-bit. The operation is performed in fractional mode :
 *    - L_var1 is supposed to be in 1Q31 format.
 *    - var2   is supposed to be in 1Q15 format.
 *    - The result is produced in 1Q47 format : L_varout_h points to the
 *      32 MSBits while varout_l points to the 16 LSBits.
 *
 *  Complexity weight : 2
 *
 *  Inputs :
 *
 *    L_var1      32 bit long signed integer (Word32) whose value falls in
 *                the range : 0x8000 0000 <= L_var1 <= 0x7fff ffff.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : 0xffff 8000 <= var2 <= 0x0000 7fff.
 *
 *  Outputs :
 *
 *    *L_varout_h 32 bit long signed integer (Word32) whose value falls in
 *                the range : 0x8000 0000 <= L_varout_h <= 0x7fff ffff.
 *
 *    *varout_l   16 bit short unsigned integer (UWord16) whose value falls in
 *                the range : 0x0000 0000 <= varout_l <= 0x0000 ffff.
 *
 *  Return Value :
 *
 *    none
 *
 *****************************************************************************/
void Mpy_32_16_ss( Word32 L_var1, Word16 var2, Word32 *L_varout_h, UWord16 *varout_l)
{
    Word16 var1_h;
    UWord16 uvar1_l;
    Word40 L40_var1;

    if( (L_var1 == ( Word32) 0x80000000)
            && (var2   == ( Word16) 0x8000))
    {
        *L_varout_h = 0x7fffffff;
        *varout_l = ( UWord16) 0xffff;

    }
    else
    {
        uvar1_l = extract_l( L_var1);
        var1_h = extract_h( L_var1);

        /* Below line can not overflow, so we can use << instead of L40_shl.  */
        L40_var1 = (( Word40) (( Word32) var2 * ( Word32) uvar1_l)) << 1;

        *varout_l = Extract40_L( L40_var1);

        L40_var1 = L40_shr( L40_var1, 16);
        L40_var1 = L40_mac( L40_var1, var2, var1_h);

        *L_varout_h = L_Extract40( L40_var1);
    }


    return;
}


/*****************************************************************************
 *
 *  Function Name :  Mpy_32_32_ss
 *
 *  Purpose :
 *
 *    Multiplies the 2 signed values L_var1 and L_var2 with saturation control
 *    on 64-bit. The operation is performed in fractional mode :
 *    - L_var1 and L_var2 are supposed to be in 1Q31 format.
 *    - The result is produced in 1Q63 format : L_varout_h points to the
 *      32 MSBits while L_varout_l points to the 32 LSBits.
 *
 *  Complexity weight : 4
 *
 *  Inputs :
 *
 *    L_var1      32 bit long signed integer (Word32) whose value falls in the
 *                range : 0x8000 0000  <= L_var1 <= 0x7fff ffff.
 *
 *    L_var2      32 bit long signed integer (Word32) whose value falls in the
 *                range : 0x8000 0000  <= L_var2 <= 0x7fff ffff.
 *
 *  Outputs :
 *
 *    *L_varout_h 32 bit long signed integer (Word32) whose value falls in
 *                the range : 0x8000 0000 <= L_varout_h <= 0x7fff ffff.
 *
 *    *L_varout_l 32 bit short unsigned integer (UWord32) whose value falls in
 *                the range : 0x0000 0000 <= L_varout_l <= 0xffff ffff.
 *
 *
 *  Return Value :
 *
 *    none
 *
 *****************************************************************************/
void Mpy_32_32_ss( Word32 L_var1, Word32 L_var2, Word32 *L_varout_h, UWord32 *L_varout_l)
{
    UWord16 uvar1_l, uvar2_l;
    Word16   var1_h,  var2_h;
    Word40 L40_var1;

    if( (L_var1 == ( Word32)0x80000000)
            && (L_var2 == ( Word32)0x80000000))
    {
        *L_varout_h = 0x7fffffff;
        *L_varout_l = ( UWord32)0xffffffff;

    }
    else
    {

        uvar1_l = extract_l( L_var1);
        var1_h = extract_h( L_var1);
        uvar2_l = extract_l( L_var2);
        var2_h = extract_h( L_var2);

        /* Below line can not overflow, so we can use << instead of L40_shl.  */
        L40_var1 = (( Word40) (( UWord32) uvar2_l * ( UWord32) uvar1_l)) << 1;

        *L_varout_l = 0x0000ffff & L_Extract40( L40_var1);

        L40_var1 = L40_shr( L40_var1, 16);
        L40_var1 = L40_add( L40_var1, (( Word40) (( Word32) var2_h * ( Word32) uvar1_l)) << 1);
        L40_var1 = L40_add( L40_var1, (( Word40) (( Word32) var1_h * ( Word32) uvar2_l)) << 1);
        *L_varout_l |= (L_Extract40( L40_var1)) << 16;

        L40_var1 = L40_shr( L40_var1, 16);
        L40_var1 = L40_mac( L40_var1, var1_h, var2_h);

        *L_varout_h = L_Extract40( L40_var1);
    }


    return;
}


/*****************************************************************************
 *
 *  Function Name : L40_lshl
 *
 *  Purpose :
 *
 *    Logically shifts left L40_var1 by var2 positions.
 *    - If var2 is negative, L40_var1 is shifted to the LSBits by (-var2)
 *      positions with insertion of 0 at the MSBit.
 *    - If var2 is positive, L40_var1 is shifted to the MSBits by (var2)
 *      positions.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : MIN_16 <= var2 <= MAX_16.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_lshl( Word40 L40_var1, Word16 var2)
{
    Word40 L40_var_out;

    if( var2 <= 0)
    {
        var2 = -var2;
        L40_var_out = L40_lshr  ( L40_var1, var2);
    }
    else
    {
        if( var2 >= 40)
            L40_var_out = 0x0000000000;
        else
        {
            L40_var_out = L40_var1 << var2;
        }
        L40_var_out = L40_set( L40_var_out);
    }

    BASOP_CHECK();


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_lshr
 *
 *  Purpose :
 *
 *    Logically shifts right L40_var1 by var2 positions.
 *    - If var2 is positive, L40_var1 is shifted to the LSBits by (var2)
 *      positions with insertion of 0 at the MSBit.
 *    - If var2 is negative, L40_var1 is shifted to the MSBits by (-var2)
 *      positions.
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : MIN_16 <= var2 <= MAX_16.
*
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_lshr( Word40 L40_var1, Word16 var2)
{
    Word40 L40_var_out;

    if( var2 < 0)
    {
        var2 = -var2;
        L40_var_out = L40_lshl ( L40_var1, var2);
    }
    else
    {
        if( var2 >= 40)
            L40_var_out = 0x0000000000;
        else
        {
#if defined(_MSC_VER) && (_MSC_VER <= 1200)
            L40_var_out = (L40_var1 & 0xffffffffff) >> var2;
#else
            L40_var_out = (L40_var1 & 0xffffffffffLL) >> var2;
#endif
        }
    }

    BASOP_CHECK();


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : norm_L40
 *
 *  Purpose :
 *
 *    Produces the number of left shifts needed to normalize in 32 bit format
 *    the 40 bit variable L40_var1. This returned value can be used to scale
 *    L_40_var1 into the following intervals :
 *    - [(MAX_32+1)/2 .. MAX_32       ] for positive values.
 *    - [ MIN_32      .. (MIN_32/2)+1 ] for negative values.
 *    - [ 0           .. 0            ] for null     values.
 *    In order to normalize the result, the following operation must be done :
 *    normelized_L40_var1 = L40_shl( L40_var1, norm_L40( L40_var1))
 *
 *  Complexity weight : 1
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    var_out     16 bit short signed integer (Word16) whose value falls in
 *                the range : -8 <= var_out <= 31.
 *
 *****************************************************************************/
Word16 norm_L40( Word40 L40_var1)
{
    Word16 var_out;

    var_out = 0;

    if( L40_var1 != 0)
    {
        while( (L40_var1 > ( Word32)0x80000000L)
                && (L40_var1 < ( Word32)0x7fffffffL))
        {

            L40_var1 = L40_shl( L40_var1, 1);
            var_out++;
        }

        while( (L40_var1 < ( Word32)0x80000000L)
                || (L40_var1 > ( Word32)0x7fffffffL))
        {

            L40_var1 = L40_shl( L40_var1, -1);
            var_out--;
        }
    }


    return( var_out);
}






/*****************************************************************************
 *
 *  Function Name : L40_shr_r
 *
 *  Purpose :
 *
 *    Arithmetically shifts right L40_var1 by var2 positions and rounds the
 *    result. It is equivalent to L40_shr( L40_var1, var2) except that if the
 *    last bit shifted out to the LSBit is 1, then the shifted result is
 *    incremented by 1.
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 3
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : 0xffff 8000 <= var2 <= 0x0000 7fff.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_shr_r( Word40 L40_var1, Word16 var2)
{
    Word40 L40_var_out;

    if( var2 > 39)
    {
        L40_var_out = 0;
    }
    else
    {
        L40_var_out = L40_shr( L40_var1, var2);

        if( var2 > 0)
        {
            if( ( L40_var1 & (( Word40) 1 << (var2 - 1))) != 0)
            {
                /* below line can not generate overflows on 40-bit */
                L40_var_out++;
            }
        }
    }

    BASOP_CHECK();


    return( L40_var_out);
}


/*****************************************************************************
 *
 *  Function Name : L40_shl_r
 *
 *  Purpose :
 *
 *    Arithmetically shifts left L40_var1 by var2 positions and rounds the
 *    result. It is equivalent to L40_shl( L40_var1, var2) except if var2 is
 *    negative. In that case, it does the same as
 *    L40_shr_r( L40_var1, (-var2)).
 *    Calls the macro L40_UNDERFLOW_OCCURED() in case of underflow on 40-bit.
 *    Calls the macro L40_OVERFLOW_OCCURED()  in case of overflow  on 40-bit.
 *
 *  Complexity weight : 3
 *
 *  Inputs :
 *
 *    L40_var1    40 bit long signed integer (Word40) whose value falls in the
 *                range : MIN_40 <= L40_var1 <= MAX_40.
 *
 *    var2        16 bit short signed integer (Word16) whose value falls in
 *                the range : 0xffff 8000 <= var2 <= 0x0000 7fff.
 *
 *  Outputs :
 *
 *    none
 *
 *  Return Value :
 *
 *    L40_var_out 40 bit long signed integer (Word40) whose value falls in
 *                the range : MIN_40 <= L40_var_out <= MAX_40.
 *
 *****************************************************************************/
Word40 L40_shl_r( Word40 L40_var1, Word16 var2)
{
    Word40 L40_var_out;

    if( var2 >= 0)
    {
        L40_var_out = L40_shl( L40_var1, var2);
    }
    else
    {
        var2 = -var2;
        L40_var_out = L40_shr_r ( L40_var1, var2);
    }


    return( L40_var_out);
}


/* end of file */

} // end of namespace
