/**
* @file arithmetic.c
* @author Raviraj Joshi (raviraj@student.unsw.edu.au)
* @author Saeid Nooshabadi (saeid@unsw.edu.au)
* @date 1 August 2004
* @version 1.1
*
* The 'arithmetic.c' file contains functions for single and double floating
* point addition, subtraction, multiplication, division, copy, absolute
* negation, square root, compare, compare with exception, compare with zero
* compare with zero and exception, conversion between single and double
* precision, conversion from unsigned integer to float, conversion from signed
* integer to float, conversion from float to unsigned integer, conversion from
* float to signed integer, and fused multiplicaiton and addition. See the
* 'CHANGES.txt' file for list of modifications made to this file.
*/
#include "armvfp.h"
/* ------------------------------- Addition ------------------------------- */
/**
* @fn void faddition( Float *fd, Float *fn, Float *fm, int precision )
* @param fd The destination floating point number.
* @param fn The first floating point number operand.
* @param fm The second floating point number operand.
* @param precision SINGLE or DOUBLE floating point representation.
*
* The 'faddition' function adds 2 floating point numbers together:
* - Fd = Fn + Fm
*
* Floating point addition, involving the mantisa, exponent, and sign:
* - z = x + y
*
* - x = (Sx, Ex, Mx)
* - y = (Sy, Ey, My)
* - z = (Sz, Ez, Mz)
*
* - Mz = Mx + My * 2^(Ey - Ex), if Ex >= Ey
* - Mz = My + Mx * 2^(Ex - Ey), if Ex < Ey
*
* - Ez = max(Ex,Ey)
*
* - Sz = MSB(Mz) in 2's complement representation
*/
void faddition( Float *fd, Float *fn, Float *fm, int precision )
{
unsigned long int sticky_bit;
/**
* Invalid operation exceptions are treated as follows:
* - NaN:
* - if greater than or equal to 1 operand is a NaN, then
* - if anyone of those NaN operands = signalling NaN, then
* - if untrapped exception, then
* - set IOC flag
* - return quiet NaN <- first operand or only signalling
* NaN with MSB(F) = 1
* - else if all NaN operands = quiet NaNs, then
* - set IOC flag
* - return first operand or only quiet NaN
* - Addition:
* - if both operands = infinifty with opposite signs, then
* - if untrapped exception, then
* - set IOC flag
* - return quiet NaN with MSB(F) = 1, rest of LSB = 0
*/
if( is_signalling_nan(fn,precision) && !check_flag(IOE) )
{
set_flag( IOC );
fd->sign = fn->sign;
fd->exponent = fn->exponent;
(precision == SINGLE)? (fd->mantissa.s = fn->mantissa.s | 0x02000000) :
(fd->mantissa.d = fn->mantissa.d | 0x0040000000000000);
return;
}
else if( is_signalling_nan(fm,precision) && !check_flag(IOE) )
{
set_flag( IOC );
fd->sign = fm->sign;
fd->exponent = fm->exponent;
(precision == SINGLE)? (fd->mantissa.s = fm->mantissa.s | 0x02000000) :
(fd->mantissa.d = fm->mantissa.d | 0x0040000000000000);
return;
}
if( is_quiet_nan(fn,precision) )
{
set_flag( IOC );
fd->sign = fn->sign;
fd->exponent = fn->exponent;
(precision == SINGLE)? (fd->mantissa.s = fn->mantissa.s) :
(fd->mantissa.d = fn->mantissa.d);
return;
}
else if( is_quiet_nan(fm,precision) )
{
set_flag( IOC );
fd->sign = fm->sign;
fd->exponent = fm->exponent;
(precision == SINGLE)? (fd->mantissa.s = fm->mantissa.s) :
(fd->mantissa.d = fm->mantissa.d);
return;
}
if( is_infinity(fn,precision) && is_infinity(fm,precision) &&
(fn->sign ^ fm->sign) && !check_flag(IOE) )
{
set_flag( IOC );
fd->sign = 0;
(precision == SINGLE)? (fd->exponent = 255) :
(fd->exponent = 2047);
(precision == SINGLE)? (fd->mantissa.s = 0x06000000) :
(fd->mantissa.d = 0x00C0000000000000);
return;
}
/**
* The floating point significands are aligned as follows:
* - shift right the significand of the operand with smallest exponent a
* number of positions corresponding to the difference between the two
* operand exponents,
* - round mantissa each time it is right shifted one position, and
* - select larger exponent as the exponent result
*/
if( fn->exponent >= fm->exponent )
{
int d = fn->exponent - fm->exponent;
fd->exponent = fn->exponent;
switch( precision )
{
case SINGLE:
if (d <= 32)
sticky_bit = ((fm->mantissa.s) << (32 - d))? 1: 0;
else
sticky_bit = (fm->mantissa.s)? 1: 0;
fm->mantissa.s = (fm->mantissa.s >>= d) | sticky_bit;
break;
case DOUBLE:
if (d <= 64)
sticky_bit = ((fm->mantissa.d) << (64 - d))? 1: 0;
else
sticky_bit = (fm->mantissa.d)? 1: 0;
fm->mantissa.d = (fm->mantissa.d >>= d) | sticky_bit;
break;
}
}
else if( fn->exponent < fm->exponent )
{
int d = fm->exponent - fn->exponent;
fd->exponent = fm->exponent;
switch( precision )
{
case SINGLE:
if (d <= 32)
sticky_bit = ((fn->mantissa.s) << (32 - d))? 1: 0;
else
sticky_bit = (fn->mantissa.s)? 1: 0;
fn->mantissa.s = (fn->mantissa.s >>= d) | sticky_bit;
break;
case DOUBLE:
if (d <= 64)
sticky_bit = ((fn->mantissa.d) << (64 - d))? 1: 0;
else
sticky_bit = (fn->mantissa.d)? 1: 0;
fn->mantissa.d = (fn->mantissa.d >>= d) | sticky_bit;
break;
}
}
/**
* Add significands, M(fd) = M(fn) + M(fm), using 2's complement addition:
*
* @verbatim
sign(fn) sign(fm) mantissa(fd)
--------- --------- -----------------------
(+) plus (+) plus [ M(fn) ] + [ M(fm) ]
(+) plus (-) minus [ M(fn) ] + [ -M(fm) ]
(-) minus (+) plus [ -M(fn) ] + [ M(fm) ]
(-) minus (-) minus [ -M(fn) ] + [ -M(fm) ]
@endverbatim
*
* Before adding, convert mantissa of fn and fm to 2's complement
* representation if minus.
*
* If the significand of the result of addition is zero, then
* return zero floating point number with E = 0 and F = 0.
*
* Produce sign of result:
* - negative, if MSB(mantissa) in 2's complement representation = 1
* - positive, if MSB(mantissa) in 2's complement representation = 0
* - convert fd mantissa to positive value from 2's complement
* representation if sign is negative
*/
switch( precision )
{
case SINGLE:
if( fn->sign == NEGATIVE )
fn->mantissa.s = ~(fn->mantissa.s) + 0x1;
if( fm->sign == NEGATIVE )
fm->mantissa.s = ~(fm->mantissa.s) + 0x1;
fd->mantissa.s = fn->mantissa.s + fm->mantissa.s;
if( fd->mantissa.s == 0 )
{
fd->exponent = 0;
return;
}
if( (fd->sign = (fd->mantissa.s >> 31)) == NEGATIVE )
fd->mantissa.s = ~(fd->mantissa.s) + 0x1;
break;
case DOUBLE:
if( f
评论0