FreeCalypso > hg > gsmhr-codec-ref
diff mathhalf.c @ 0:9008dbc8ca74
import original C code from GSM 06.06
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 14 Jun 2024 23:27:16 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mathhalf.c Fri Jun 14 23:27:16 2024 +0000 @@ -0,0 +1,1953 @@ +/*************************************************************************** + * + * File Name: mathhalf.c + * + * Purpose: Contains functions which implement the primitive + * arithmetic operations. + * + * The functions in this file are listed below. Some of them are + * defined in terms of other basic operations. One of the + * routines, saturate() is static. This is not a basic + * operation, and is not referenced outside the scope of this + * file. + * + * + * abs_s() + * add() + * divide_s() + * extract_h() + * extract_l() + * L_abs() + * L_add() + * L_deposit_h() + * L_deposit_l() + * L_mac() + * L_msu() + * L_mult() + * L_negate() + * L_shift_r() + * L_shl() + * L_shr() + * L_sub() + * mac_r() + * msu_r() + * mult() + * mult_r() + * negate() + * norm_l() + * norm_s() + * round() + * saturate() + * shift_r() + * shl() + * shr() + * sub() + * + **************************************************************************/ + +/*_________________________________________________________________________ + | | + | Include Files | + |_________________________________________________________________________| +*/ + +#include "typedefs.h" +#include "mathhalf.h" + +/*************************************************************************** + * + * FUNCTION NAME: saturate + * + * PURPOSE: + * + * Limit the 32 bit input to the range of a 16 bit word. + * + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * KEYWORDS: saturation, limiting, limit, saturate, 16 bits + * + *************************************************************************/ + +static Shortword saturate(Longword L_var1) +{ + Shortword swOut; + + if (L_var1 > SW_MAX) + { + swOut = SW_MAX; + } + else if (L_var1 < SW_MIN) + { + swOut = SW_MIN; + } + else + swOut = (Shortword) L_var1; /* automatic type conversion */ + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: abs_s + * + * PURPOSE: + * + * Take the absolute value of the 16 bit input. An input of + * -0x8000 results in a return value of 0x7fff. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0x0000 0000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Take the absolute value of the 16 bit input. An input of + * -0x8000 results in a return value of 0x7fff. + * + * KEYWORDS: absolute value, abs + * + *************************************************************************/ + +Shortword abs_s(Shortword var1) +{ + Shortword swOut; + + if (var1 == SW_MIN) + { + swOut = SW_MAX; + } + else + { + if (var1 < 0) + swOut = -var1; + else + swOut = var1; + } + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: add + * + * PURPOSE: + * + * Perform the addition of the two 16 bit input variable with + * saturation. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Perform the addition of the two 16 bit input variable with + * saturation. + * + * swOut = var1 + var2 + * + * swOut is set to 0x7fff if the operation results in an + * overflow. swOut is set to 0x8000 if the operation results + * in an underflow. + * + * KEYWORDS: add, addition + * + *************************************************************************/ + +Shortword add(Shortword var1, Shortword var2) +{ + Longword L_sum; + Shortword swOut; + + L_sum = (Longword) var1 + var2; + swOut = saturate(L_sum); + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: divide_s + * + * PURPOSE: + * + * Divide var1 by var2. Note that both must be positive, and + * var1 >= var2. The output is set to 0 if invalid input is + * provided. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * In the case where var1==var2 the function returns 0x7fff. The output + * is undefined for invalid inputs. This implementation returns zero + * and issues a warning via stdio if invalid input is presented. + * + * KEYWORDS: divide + * + *************************************************************************/ + +Shortword divide_s(Shortword var1, Shortword var2) +{ + Longword L_div; + Shortword swOut; + + if (var1 < 0 || var2 < 0 || var1 > var2) + { + /* undefined output for invalid input into divide_s */ + return (0); + } + + if (var1 == var2) + return (0x7fff); + + L_div = ((0x00008000L * (Longword) var1) / (Longword) var2); + swOut = saturate(L_div); + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: extract_h + * + * PURPOSE: + * + * Extract the 16 MS bits of a 32 bit Longword. Return the 16 bit + * number as a Shortword. This is used as a "truncation" of a fractional + * number. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * KEYWORDS: assign, truncate + * + *************************************************************************/ + +Shortword extract_h(Longword L_var1) +{ + Shortword var2; + + var2 = (Shortword) (0x0000ffffL & (L_var1 >> 16)); + return (var2); +} + +/*************************************************************************** + * + * FUNCTION NAME: extract_l + * + * PURPOSE: + * + * Extract the 16 LS bits of a 32 bit Longword. Return the 16 bit + * number as a Shortword. The upper portion of the input Longword + * has no impact whatsoever on the output. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * + * KEYWORDS: extract, assign + * + *************************************************************************/ + +Shortword extract_l(Longword L_var1) +{ + Shortword var2; + + var2 = (Shortword) (0x0000ffffL & L_var1); + return (var2); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_abs + * + * PURPOSE: + * + * Take the absolute value of the 32 bit input. An input of + * -0x8000 0000 results in a return value of 0x7fff ffff. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * + * + * KEYWORDS: absolute value, abs + * + *************************************************************************/ +Longword L_abs(Longword L_var1) +{ + Longword L_Out; + + if (L_var1 == LW_MIN) + { + L_Out = LW_MAX; + } + else + { + if (L_var1 < 0) + L_Out = -L_var1; + else + L_Out = L_var1; + } + return (L_Out); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_add + * + * PURPOSE: + * + * Perform the addition of the two 32 bit input variables with + * saturation. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * L_var2 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var2 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * IMPLEMENTATION: + * + * Perform the addition of the two 32 bit input variables with + * saturation. + * + * L_Out = L_var1 + L_var2 + * + * L_Out is set to 0x7fff ffff if the operation results in an + * overflow. L_Out is set to 0x8000 0000 if the operation + * results in an underflow. + * + * KEYWORDS: add, addition + * + *************************************************************************/ +Longword L_add(Longword L_var1, Longword L_var2) +{ + + Longword L_Sum, + L_SumLow, + L_SumHigh; + + L_Sum = L_var1 + L_var2; + + if ((L_var1 > 0 && L_var2 > 0) || (L_var1 < 0 && L_var2 < 0)) + { + + /* an overflow is possible */ + + L_SumLow = (L_var1 & 0xffff) + (L_var2 & 0xffff); + L_SumHigh = ((L_var1 >> 16) & 0xffff) + ((L_var2 >> 16) & 0xffff); + if (L_SumLow & 0x10000) + { + /* carry into high word is set */ + L_SumHigh += 1; + } + + /* update sum only if there is an overflow or underflow */ + /*------------------------------------------------------*/ + + if ((0x10000 & L_SumHigh) && !(0x8000 & L_SumHigh)) + L_Sum = LW_MIN; /* underflow */ + else if (!(0x10000 & L_SumHigh) && (0x8000 & L_SumHigh)) + L_Sum = LW_MAX; /* overflow */ + } + + return (L_Sum); + +} + +/*************************************************************************** + * + * FUNCTION NAME: L_deposit_h + * + * PURPOSE: + * + * Put the 16 bit input into the 16 MSB's of the output Longword. The + * LS 16 bits are zeroed. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff 0000. + * + * + * KEYWORDS: deposit, assign, fractional assign + * + *************************************************************************/ + +Longword L_deposit_h(Shortword var1) +{ + Longword L_var2; + + L_var2 = (Longword) var1 << 16; + return (L_var2); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_deposit_l + * + * PURPOSE: + * + * Put the 16 bit input into the 16 LSB's of the output Longword with + * sign extension i.e. the top 16 bits are set to either 0 or 0xffff. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0xffff 8000 <= L_var1 <= 0x0000 7fff. + * + * KEYWORDS: deposit, assign + * + *************************************************************************/ + +Longword L_deposit_l(Shortword var1) +{ + Longword L_Out; + + L_Out = var1; + return (L_Out); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_mac + * + * PURPOSE: + * + * Multiply accumulate. Fractionally multiply two 16 bit + * numbers together with saturation. Add that result to the + * 32 bit input with saturation. Return the 32 bit result. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * L_var3 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var2 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * IMPLEMENTATION: + * + * Fractionally multiply two 16 bit numbers together with + * saturation. The only numbers which will cause saturation on + * the multiply are 0x8000 * 0x8000. + * + * Add that result to the 32 bit input with saturation. + * Return the 32 bit result. + * + * Please note that this is not a true multiply accumulate as + * most processors would implement it. The 0x8000*0x8000 + * causes and overflow for this instruction. On most + * processors this would cause an overflow only if the 32 bit + * input added to it were positive or zero. + * + * KEYWORDS: mac, multiply accumulate + * + *************************************************************************/ + +Longword L_mac(Longword L_var3, Shortword var1, Shortword var2) +{ + return (L_add(L_var3, L_mult(var1, var2))); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_msu + * + * PURPOSE: + * + * Multiply and subtract. Fractionally multiply two 16 bit + * numbers together with saturation. Subtract that result from + * the 32 bit input with saturation. Return the 32 bit result. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * L_var3 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var2 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * IMPLEMENTATION: + * + * Fractionally multiply two 16 bit numbers together with + * saturation. The only numbers which will cause saturation on + * the multiply are 0x8000 * 0x8000. + * + * Subtract that result from the 32 bit input with saturation. + * Return the 32 bit result. + * + * Please note that this is not a true multiply accumulate as + * most processors would implement it. The 0x8000*0x8000 + * causes and overflow for this instruction. On most + * processors this would cause an overflow only if the 32 bit + * input added to it were negative or zero. + * + * KEYWORDS: mac, multiply accumulate, msu + * + *************************************************************************/ + +Longword L_msu(Longword L_var3, Shortword var1, Shortword var2) +{ + return (L_sub(L_var3, L_mult(var1, var2))); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_mult + * + * PURPOSE: + * + * Perform a fractional multipy of the two 16 bit input numbers + * with saturation. Output a 32 bit number. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * IMPLEMENTATION: + * + * Multiply the two the two 16 bit input numbers. If the + * result is within this range, left shift the result by one + * and output the 32 bit number. The only possible overflow + * occurs when var1==var2==-0x8000. In this case output + * 0x7fff ffff. + * + * KEYWORDS: multiply, mult, mpy + * + *************************************************************************/ + +Longword L_mult(Shortword var1, Shortword var2) +{ + Longword L_product; + + if (var1 == SW_MIN && var2 == SW_MIN) + L_product = LW_MAX; /* overflow */ + else + { + L_product = (Longword) var1 *var2; /* integer multiply */ + + L_product = L_product << 1; + } + return (L_product); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_negate + * + * PURPOSE: + * + * Negate the 32 bit input. 0x8000 0000's negated value is + * 0x7fff ffff. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0001 <= L_var1 <= 0x7fff ffff. + * + * KEYWORDS: negate, negative + * + *************************************************************************/ + +Longword L_negate(Longword L_var1) +{ + Longword L_Out; + + if (L_var1 == LW_MIN) + L_Out = LW_MAX; + else + L_Out = -L_var1; + return (L_Out); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_shift_r + * + * PURPOSE: + * + * Shift and round. Perform a shift right. After shifting, use + * the last bit shifted out of the LSB to round the result up + * or down. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * + * IMPLEMENTATION: + * + * Shift and round. Perform a shift right. After shifting, use + * the last bit shifted out of the LSB to round the result up + * or down. This is just like shift_r above except that the + * input/output is 32 bits as opposed to 16. + * + * if var2 is positve perform a arithmetic left shift + * with saturation (see L_shl() above). + * + * If var2 is zero simply return L_var1. + * + * If var2 is negative perform a arithmetic right shift (L_shr) + * of L_var1 by (-var2)+1. Add the LS bit of the result to + * L_var1 shifted right (L_shr) by -var2. + * + * Note that there is no constraint on var2, so if var2 is + * -0xffff 8000 then -var2 is 0x0000 8000, not 0x0000 7fff. + * This is the reason the L_shl function is used. + * + * + * KEYWORDS: + * + *************************************************************************/ + +Longword L_shift_r(Longword L_var1, Shortword var2) +{ + Longword L_Out, + L_rnd; + + if (var2 < -31) + { + L_Out = 0; + } + else if (var2 < 0) + { + /* right shift */ + L_rnd = L_shl(L_var1, var2 + 1) & 0x1; + L_Out = L_add(L_shl(L_var1, var2), L_rnd); + } + else + L_Out = L_shl(L_var1, var2); + + return (L_Out); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_shl + * + * PURPOSE: + * + * Arithmetic shift left (or right). + * Arithmetically shift the input left by var2. If var2 is + * negative then an arithmetic shift right (L_shr) of L_var1 by + * -var2 is performed. + * + * INPUTS: + * + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * + * IMPLEMENTATION: + * + * Arithmetically shift the 32 bit input left by var2. This + * operation maintains the sign of the input number. If var2 is + * negative then an arithmetic shift right (L_shr) of L_var1 by + * -var2 is performed. See description of L_shr for details. + * + * Equivalent to the Full-Rate GSM ">> n" operation. Note that + * ANSI-C does not guarantee operation of the C ">>" or "<<" + * operator for negative numbers. + * + * KEYWORDS: shift, arithmetic shift left, + * + *************************************************************************/ + +Longword L_shl(Longword L_var1, Shortword var2) +{ + + Longword L_Mask, + L_Out; + int i, + iOverflow = 0; + + if (var2 == 0 || L_var1 == 0) + { + L_Out = L_var1; + } + else if (var2 < 0) + { + if (var2 <= -31) + { + if (L_var1 > 0) + L_Out = 0; + else + L_Out = 0xffffffffL; + } + else + L_Out = L_shr(L_var1, -var2); + } + else + { + + if (var2 >= 31) + iOverflow = 1; + + else + { + + if (L_var1 < 0) + L_Mask = LW_SIGN; /* sign bit mask */ + else + L_Mask = 0x0; + L_Out = L_var1; + for (i = 0; i < var2 && !iOverflow; i++) + { + /* check the sign bit */ + L_Out = (L_Out & 0x7fffffffL) << 1; + if ((L_Mask ^ L_Out) & LW_SIGN) + iOverflow = 1; + } + } + + if (iOverflow) + { + /* saturate */ + if (L_var1 > 0) + L_Out = LW_MAX; + else + L_Out = LW_MIN; + } + } + + return (L_Out); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_shr + * + * PURPOSE: + * + * Arithmetic shift right (or left). + * Arithmetically shift the input right by var2. If var2 is + * negative then an arithmetic shift left (shl) of var1 by + * -var2 is performed. + * + * INPUTS: + * + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * + * IMPLEMENTATION: + * + * Arithmetically shift the input right by var2. This + * operation maintains the sign of the input number. If var2 is + * negative then an arithmetic shift left (shl) of L_var1 by + * -var2 is performed. See description of L_shl for details. + * + * The input is a 32 bit number, as is the output. + * + * Equivalent to the Full-Rate GSM ">> n" operation. Note that + * ANSI-C does not guarantee operation of the C ">>" or "<<" + * operator for negative numbers. + * + * KEYWORDS: shift, arithmetic shift right, + * + *************************************************************************/ + +Longword L_shr(Longword L_var1, Shortword var2) +{ + + Longword L_Mask, + L_Out; + + if (var2 == 0 || L_var1 == 0) + { + L_Out = L_var1; + } + else if (var2 < 0) + { + /* perform a left shift */ + /*----------------------*/ + if (var2 <= -31) + { + /* saturate */ + if (L_var1 > 0) + L_Out = LW_MAX; + else + L_Out = LW_MIN; + } + else + L_Out = L_shl(L_var1, -var2); + } + else + { + + if (var2 >= 31) + { + if (L_var1 > 0) + L_Out = 0; + else + L_Out = 0xffffffffL; + } + else + { + L_Mask = 0; + + if (L_var1 < 0) + { + L_Mask = ~L_Mask << (32 - var2); + } + + L_var1 >>= var2; + L_Out = L_Mask | L_var1; + } + } + return (L_Out); +} + +/*************************************************************************** + * + * FUNCTION NAME: L_sub + * + * PURPOSE: + * + * Perform the subtraction of the two 32 bit input variables with + * saturation. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * L_var2 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var2 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * L_Out + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * IMPLEMENTATION: + * + * Perform the subtraction of the two 32 bit input variables with + * saturation. + * + * L_Out = L_var1 - L_var2 + * + * L_Out is set to 0x7fff ffff if the operation results in an + * overflow. L_Out is set to 0x8000 0000 if the operation + * results in an underflow. + * + * KEYWORDS: sub, subtraction + * + *************************************************************************/ +Longword L_sub(Longword L_var1, Longword L_var2) +{ + Longword L_Sum; + + /* check for overflow */ + if ((L_var1 > 0 && L_var2 < 0) || (L_var1 < 0 && L_var2 > 0)) + { + if (L_var2 == LW_MIN) + { + L_Sum = L_add(L_var1, LW_MAX); + L_Sum = L_add(L_Sum, 1); + } + else + L_Sum = L_add(L_var1, -L_var2); + } + else + { /* no overflow possible */ + L_Sum = L_var1 - L_var2; + } + return (L_Sum); +} + +/*************************************************************************** + * + * FUNCTION NAME:mac_r + * + * PURPOSE: + * + * Multiply accumulate and round. Fractionally multiply two 16 + * bit numbers together with saturation. Add that result to + * the 32 bit input with saturation. Finally round the result + * into a 16 bit number. + * + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * L_var3 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var2 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Fractionally multiply two 16 bit numbers together with + * saturation. The only numbers which will cause saturation on + * the multiply are 0x8000 * 0x8000. + * + * Add that result to the 32 bit input with saturation. + * Round the 32 bit result by adding 0x0000 8000 to the input. + * The result may overflow due to the add. If so, the result + * is saturated. The 32 bit rounded number is then shifted + * down 16 bits and returned as a Shortword. + * + * Please note that this is not a true multiply accumulate as + * most processors would implement it. The 0x8000*0x8000 + * causes and overflow for this instruction. On most + * processors this would cause an overflow only if the 32 bit + * input added to it were positive or zero. + * + * KEYWORDS: mac, multiply accumulate, macr + * + *************************************************************************/ + +Shortword mac_r(Longword L_var3, Shortword var1, Shortword var2) +{ + return (round(L_add(L_var3, L_mult(var1, var2)))); +} + +/*************************************************************************** + * + * FUNCTION NAME: msu_r + * + * PURPOSE: + * + * Multiply subtract and round. Fractionally multiply two 16 + * bit numbers together with saturation. Subtract that result from + * the 32 bit input with saturation. Finally round the result + * into a 16 bit number. + * + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * L_var3 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var2 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Fractionally multiply two 16 bit numbers together with + * saturation. The only numbers which will cause saturation on + * the multiply are 0x8000 * 0x8000. + * + * Subtract that result from the 32 bit input with saturation. + * Round the 32 bit result by adding 0x0000 8000 to the input. + * The result may overflow due to the add. If so, the result + * is saturated. The 32 bit rounded number is then shifted + * down 16 bits and returned as a Shortword. + * + * Please note that this is not a true multiply accumulate as + * most processors would implement it. The 0x8000*0x8000 + * causes and overflow for this instruction. On most + * processors this would cause an overflow only if the 32 bit + * input added to it were positive or zero. + * + * KEYWORDS: mac, multiply accumulate, macr + * + *************************************************************************/ + +Shortword msu_r(Longword L_var3, Shortword var1, Shortword var2) +{ + return (round(L_sub(L_var3, L_mult(var1, var2)))); +} + +/*************************************************************************** + * + * FUNCTION NAME: mult + * + * PURPOSE: + * + * Perform a fractional multipy of the two 16 bit input numbers + * with saturation and truncation. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Perform a fractional multipy of the two 16 bit input + * numbers. If var1 == var2 == -0x8000, output 0x7fff. + * Otherwise output var1*var2 >> 15. The output is a + * 16 bit number. + * + * KEYWORDS: mult, mulitply, mpy + * + *************************************************************************/ + +Shortword mult(Shortword var1, Shortword var2) +{ + Longword L_product; + Shortword swOut; + + L_product = L_mult(var1, var2); + swOut = extract_h(L_product); + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: mult_r + * + * PURPOSE: + * + * Perform a fractional multipy and round of the two 16 bit + * input numbers with saturation. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * This routine is defined as the concatenation of the multiply + * operation and the round operation. + * + * The fractional multiply (L_mult) produces a saturated 32 bit + * output. This is followed by a an add of 0x0000 8000 to the + * 32 bit result. The result may overflow due to the add. If + * so, the result is saturated. The 32 bit rounded number is + * then shifted down 16 bits and returned as a Shortword. + * + * + * KEYWORDS: multiply and round, round, mult_r, mpyr + * + *************************************************************************/ + + +Shortword mult_r(Shortword var1, Shortword var2) +{ + Shortword swOut; + + swOut = round(L_mult(var1, var2)); + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: negate + * + * PURPOSE: + * + * Negate the 16 bit input. 0x8000's negated value is 0x7fff. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8001 <= swOut <= 0x0000 7fff. + * + * KEYWORDS: negate, negative, invert + * + *************************************************************************/ + +Shortword negate(Shortword var1) +{ + Shortword swOut; + + if (var1 == SW_MIN) + swOut = SW_MAX; + else + swOut = -var1; + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: norm_l + * + * PURPOSE: + * + * Get normalize shift count: + * + * A 32 bit number is input (possiblly unnormalized). Output + * the positive (or zero) shift count required to normalize the + * input. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0 <= swOut <= 31 + * + * + * + * IMPLEMENTATION: + * + * Get normalize shift count: + * + * A 32 bit number is input (possiblly unnormalized). Output + * the positive (or zero) shift count required to normalize the + * input. + * + * If zero in input, return 0 as the shift count. + * + * For non-zero numbers, count the number of left shift + * required to get the number to fall into the range: + * + * 0x4000 0000 >= normlzd number >= 0x7fff ffff (positive number) + * or + * 0x8000 0000 <= normlzd number < 0xc000 0000 (negative number) + * + * Return the number of shifts. + * + * This instruction corresponds exactly to the Full-Rate "norm" + * instruction. + * + * KEYWORDS: norm, normalization + * + *************************************************************************/ + +Shortword norm_l(Longword L_var1) +{ + + Shortword swShiftCnt; + + if (L_var1 != 0) + { + if (!(L_var1 & LW_SIGN)) + { + + /* positive input */ + for (swShiftCnt = 0; !(L_var1 <= LW_MAX && L_var1 >= 0x40000000L); + swShiftCnt++) + { + L_var1 = L_var1 << 1; + } + + } + else + { + /* negative input */ + for (swShiftCnt = 0; + !(L_var1 >= LW_MIN && L_var1 < (Longword) 0xc0000000L); + swShiftCnt++) + { + L_var1 = L_var1 << 1; + } + } + } + else + { + swShiftCnt = 0; + } + return (swShiftCnt); +} + +/*************************************************************************** + * + * FUNCTION NAME: norm_s + * + * PURPOSE: + * + * Get normalize shift count: + * + * A 16 bit number is input (possiblly unnormalized). Output + * the positive (or zero) shift count required to normalize the + * input. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0 <= swOut <= 15 + * + * + * + * IMPLEMENTATION: + * + * Get normalize shift count: + * + * A 16 bit number is input (possiblly unnormalized). Output + * the positive (or zero) shift count required to normalize the + * input. + * + * If zero in input, return 0 as the shift count. + * + * For non-zero numbers, count the number of left shift + * required to get the number to fall into the range: + * + * 0x4000 >= normlzd number >= 0x7fff (positive number) + * or + * 0x8000 <= normlzd number < 0xc000 (negative number) + * + * Return the number of shifts. + * + * This instruction corresponds exactly to the Full-Rate "norm" + * instruction. + * + * KEYWORDS: norm, normalization + * + *************************************************************************/ + +Shortword norm_s(Shortword var1) +{ + + short swShiftCnt; + Longword L_var1; + + L_var1 = L_deposit_h(var1); + swShiftCnt = norm_l(L_var1); + return (swShiftCnt); +} + +/*************************************************************************** + * + * FUNCTION NAME: round + * + * PURPOSE: + * + * Round the 32 bit Longword into a 16 bit shortword with saturation. + * + * INPUTS: + * + * L_var1 + * 32 bit long signed integer (Longword) whose value + * falls in the range + * 0x8000 0000 <= L_var1 <= 0x7fff ffff. + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Perform a two's complement round on the input Longword with + * saturation. + * + * This is equivalent to adding 0x0000 8000 to the input. The + * result may overflow due to the add. If so, the result is + * saturated. The 32 bit rounded number is then shifted down + * 16 bits and returned as a Shortword. + * + * + * KEYWORDS: round + * + *************************************************************************/ + +Shortword round(Longword L_var1) +{ + Longword L_Prod; + + L_Prod = L_add(L_var1, 0x00008000L); /* round MSP */ + return (extract_h(L_Prod)); +} + +/*************************************************************************** + * + * FUNCTION NAME: shift_r + * + * PURPOSE: + * + * Shift and round. Perform a shift right. After shifting, use + * the last bit shifted out of the LSB to round the result up + * or down. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * + * IMPLEMENTATION: + * + * Shift and round. Perform a shift right. After shifting, use + * the last bit shifted out of the LSB to round the result up + * or down. + * + * If var2 is positive perform a arithmetic left shift + * with saturation (see shl() above). + * + * If var2 is zero simply return var1. + * + * If var2 is negative perform a arithmetic right shift (shr) + * of var1 by (-var2)+1. Add the LS bit of the result to var1 + * shifted right (shr) by -var2. + * + * Note that there is no constraint on var2, so if var2 is + * -0xffff 8000 then -var2 is 0x0000 8000, not 0x0000 7fff. + * This is the reason the shl function is used. + * + * + * KEYWORDS: + * + *************************************************************************/ + +Shortword shift_r(Shortword var1, Shortword var2) +{ + Shortword swOut, + swRnd; + + if (var2 >= 0) + swOut = shl(var1, var2); + else + { + + /* right shift */ + + if (var2 < -15) + { + + swOut = 0; + + } + else + { + + swRnd = shl(var1, var2 + 1) & 0x1; + swOut = add(shl(var1, var2), swRnd); + + } + } + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: shl + * + * PURPOSE: + * + * Arithmetically shift the input left by var2. + * + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * If Arithmetically shift the input left by var2. If var2 is + * negative then an arithmetic shift right (shr) of var1 by + * -var2 is performed. See description of shr for details. + * When an arithmetic shift left is performed the var2 LS bits + * are zero filled. + * + * The only exception is if the left shift causes an overflow + * or underflow. In this case the LS bits are not modified. + * The number returned is 0x8000 in the case of an underflow or + * 0x7fff in the case of an overflow. + * + * The shl is equivalent to the Full-Rate GSM "<< n" operation. + * Note that ANSI-C does not guarantee operation of the C ">>" + * or "<<" operator for negative numbers - it is not specified + * whether this shift is an arithmetic or logical shift. + * + * KEYWORDS: asl, arithmetic shift left, shift + * + *************************************************************************/ + +Shortword shl(Shortword var1, Shortword var2) +{ + Shortword swOut; + Longword L_Out; + + if (var2 == 0 || var1 == 0) + { + swOut = var1; + } + else if (var2 < 0) + { + + /* perform a right shift */ + /*-----------------------*/ + + if (var2 <= -15) + { + if (var1 < 0) + swOut = (Shortword) 0xffff; + else + swOut = 0x0; + } + else + swOut = shr(var1, -var2); + + } + else + { + /* var2 > 0 */ + if (var2 >= 15) + { + /* saturate */ + if (var1 > 0) + swOut = SW_MAX; + else + swOut = SW_MIN; + } + else + { + + L_Out = (Longword) var1 *(1 << var2); + + swOut = (Shortword) L_Out; /* copy low portion to swOut, overflow + * could have hpnd */ + if (swOut != L_Out) + { + /* overflow */ + if (var1 > 0) + swOut = SW_MAX; /* saturate */ + else + swOut = SW_MIN; /* saturate */ + } + } + } + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: shr + * + * PURPOSE: + * + * Arithmetic shift right (or left). + * Arithmetically shift the input right by var2. If var2 is + * negative then an arithmetic shift left (shl) of var1 by + * -var2 is performed. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Arithmetically shift the input right by var2. This + * operation maintains the sign of the input number. If var2 is + * negative then an arithmetic shift left (shl) of var1 by + * -var2 is performed. See description of shl for details. + * + * Equivalent to the Full-Rate GSM ">> n" operation. Note that + * ANSI-C does not guarantee operation of the C ">>" or "<<" + * operator for negative numbers. + * + * KEYWORDS: shift, arithmetic shift right, + * + *************************************************************************/ + +Shortword shr(Shortword var1, Shortword var2) +{ + + Shortword swMask, + swOut; + + if (var2 == 0 || var1 == 0) + swOut = var1; + + else if (var2 < 0) + { + /* perform an arithmetic left shift */ + /*----------------------------------*/ + if (var2 <= -15) + { + /* saturate */ + if (var1 > 0) + swOut = SW_MAX; + else + swOut = SW_MIN; + } + else + swOut = shl(var1, -var2); + } + + else + { + + /* positive shift count */ + /*----------------------*/ + + if (var2 >= 15) + { + if (var1 < 0) + swOut = (Shortword) 0xffff; + else + swOut = 0x0; + } + else + { + /* take care of sign extension */ + /*-----------------------------*/ + + swMask = 0; + if (var1 < 0) + { + swMask = ~swMask << (16 - var2); + } + + var1 >>= var2; + swOut = swMask | var1; + + } + } + return (swOut); +} + +/*************************************************************************** + * + * FUNCTION NAME: sub + * + * PURPOSE: + * + * Perform the subtraction of the two 16 bit input variable with + * saturation. + * + * INPUTS: + * + * var1 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var1 <= 0x0000 7fff. + * var2 + * 16 bit short signed integer (Shortword) whose value + * falls in the range 0xffff 8000 <= var2 <= 0x0000 7fff. + * + * OUTPUTS: + * + * none + * + * RETURN VALUE: + * + * swOut + * 16 bit short signed integer (Shortword) whose value + * falls in the range + * 0xffff 8000 <= swOut <= 0x0000 7fff. + * + * IMPLEMENTATION: + * + * Perform the subtraction of the two 16 bit input variable with + * saturation. + * + * swOut = var1 - var2 + * + * swOut is set to 0x7fff if the operation results in an + * overflow. swOut is set to 0x8000 if the operation results + * in an underflow. + * + * KEYWORDS: sub, subtraction + * + *************************************************************************/ +Shortword sub(Shortword var1, Shortword var2) +{ + Longword L_diff; + Shortword swOut; + + L_diff = (Longword) var1 - var2; + swOut = saturate(L_diff); + + return (swOut); +}