2015-08-13 10:56:31 +03:00
/*
* IEEE754 floating point arithmetic
* single precision : MADDF . f ( Fused Multiply Add )
* MADDF . fmt : FPR [ fd ] = FPR [ fd ] + ( FPR [ fs ] x FPR [ ft ] )
*
* MIPS floating point support
* Copyright ( C ) 2015 Imagination Technologies , Ltd .
* Author : Markos Chandras < markos . chandras @ imgtec . com >
*
* This program is free software ; you can distribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; version 2 of the License .
*/
# include "ieee754sp.h"
2016-04-21 16:04:49 +03:00
enum maddf_flags {
maddf_negate_product = 1 < < 0 ,
} ;
static union ieee754sp _sp_maddf ( union ieee754sp z , union ieee754sp x ,
union ieee754sp y , enum maddf_flags flags )
2015-08-13 10:56:31 +03:00
{
int re ;
int rs ;
unsigned rm ;
unsigned short lxm ;
unsigned short hxm ;
unsigned short lym ;
unsigned short hym ;
unsigned lrm ;
unsigned hrm ;
unsigned t ;
unsigned at ;
int s ;
COMPXSP ;
COMPYSP ;
2016-04-21 16:04:51 +03:00
COMPZSP ;
2015-08-13 10:56:31 +03:00
EXPLODEXSP ;
EXPLODEYSP ;
2016-04-21 16:04:51 +03:00
EXPLODEZSP ;
2015-08-13 10:56:31 +03:00
FLUSHXSP ;
FLUSHYSP ;
2016-04-21 16:04:51 +03:00
FLUSHZSP ;
2015-08-13 10:56:31 +03:00
ieee754_clearcx ( ) ;
switch ( zc ) {
case IEEE754_CLASS_SNAN :
ieee754_setcx ( IEEE754_INVALID_OPERATION ) ;
return ieee754sp_nanxcpt ( z ) ;
case IEEE754_CLASS_DNORM :
2016-04-21 16:04:51 +03:00
SPDNORMZ ;
2015-08-13 10:56:31 +03:00
/* QNAN is handled separately below */
}
switch ( CLPAIR ( xc , yc ) ) {
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_SNAN ) :
return ieee754sp_nanxcpt ( y ) ;
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_SNAN ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_DNORM ) :
case CLPAIR ( IEEE754_CLASS_SNAN , IEEE754_CLASS_INF ) :
return ieee754sp_nanxcpt ( x ) ;
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_QNAN ) :
return y ;
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_QNAN ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_DNORM ) :
case CLPAIR ( IEEE754_CLASS_QNAN , IEEE754_CLASS_INF ) :
return x ;
/*
* Infinity handling
*/
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_INF ) :
if ( zc = = IEEE754_CLASS_QNAN )
return z ;
ieee754_setcx ( IEEE754_INVALID_OPERATION ) ;
return ieee754sp_indef ( ) ;
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_INF ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_INF ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_DNORM ) :
case CLPAIR ( IEEE754_CLASS_INF , IEEE754_CLASS_INF ) :
if ( zc = = IEEE754_CLASS_QNAN )
return z ;
return ieee754sp_inf ( xs ^ ys ) ;
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_NORM ) :
case CLPAIR ( IEEE754_CLASS_ZERO , IEEE754_CLASS_DNORM ) :
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_ZERO ) :
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_ZERO ) :
if ( zc = = IEEE754_CLASS_INF )
return ieee754sp_inf ( zs ) ;
/* Multiplication is 0 so just return z */
return z ;
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_DNORM ) :
SPDNORMX ;
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_DNORM ) :
if ( zc = = IEEE754_CLASS_QNAN )
return z ;
else if ( zc = = IEEE754_CLASS_INF )
return ieee754sp_inf ( zs ) ;
SPDNORMY ;
break ;
case CLPAIR ( IEEE754_CLASS_DNORM , IEEE754_CLASS_NORM ) :
if ( zc = = IEEE754_CLASS_QNAN )
return z ;
else if ( zc = = IEEE754_CLASS_INF )
return ieee754sp_inf ( zs ) ;
SPDNORMX ;
break ;
case CLPAIR ( IEEE754_CLASS_NORM , IEEE754_CLASS_NORM ) :
if ( zc = = IEEE754_CLASS_QNAN )
return z ;
else if ( zc = = IEEE754_CLASS_INF )
return ieee754sp_inf ( zs ) ;
/* fall through to real computations */
}
/* Finally get to do some computation */
/*
* Do the multiplication bit first
*
* rm = xm * ym , re = xe + ye basically
*
* At this point xm and ym should have been normalized .
*/
/* rm = xm * ym, re = xe+ye basically */
assert ( xm & SP_HIDDEN_BIT ) ;
assert ( ym & SP_HIDDEN_BIT ) ;
re = xe + ye ;
rs = xs ^ ys ;
2016-04-21 16:04:49 +03:00
if ( flags & maddf_negate_product )
rs ^ = 1 ;
2015-08-13 10:56:31 +03:00
/* shunt to top of word */
xm < < = 32 - ( SP_FBITS + 1 ) ;
ym < < = 32 - ( SP_FBITS + 1 ) ;
/*
* Multiply 32 bits xm , ym to give high 32 bits rm with stickness .
*/
lxm = xm & 0xffff ;
hxm = xm > > 16 ;
lym = ym & 0xffff ;
hym = ym > > 16 ;
lrm = lxm * lym ; /* 16 * 16 => 32 */
hrm = hxm * hym ; /* 16 * 16 => 32 */
t = lxm * hym ; /* 16 * 16 => 32 */
at = lrm + ( t < < 16 ) ;
hrm + = at < lrm ;
lrm = at ;
hrm = hrm + ( t > > 16 ) ;
t = hxm * lym ; /* 16 * 16 => 32 */
at = lrm + ( t < < 16 ) ;
hrm + = at < lrm ;
lrm = at ;
hrm = hrm + ( t > > 16 ) ;
rm = hrm | ( lrm ! = 0 ) ;
/*
* Sticky shift down to normal rounding precision .
*/
if ( ( int ) rm < 0 ) {
rm = ( rm > > ( 32 - ( SP_FBITS + 1 + 3 ) ) ) |
( ( rm < < ( SP_FBITS + 1 + 3 ) ) ! = 0 ) ;
re + + ;
} else {
rm = ( rm > > ( 32 - ( SP_FBITS + 1 + 3 + 1 ) ) ) |
( ( rm < < ( SP_FBITS + 1 + 3 + 1 ) ) ! = 0 ) ;
}
assert ( rm & ( SP_HIDDEN_BIT < < 3 ) ) ;
/* And now the addition */
assert ( zm & SP_HIDDEN_BIT ) ;
/*
* Provide guard , round and stick bit space .
*/
zm < < = 3 ;
if ( ze > re ) {
/*
2016-04-21 16:04:54 +03:00
* Have to shift r fraction right to align .
2015-08-13 10:56:31 +03:00
*/
s = ze - re ;
2016-04-21 16:04:54 +03:00
rm = XSPSRS ( rm , s ) ;
re + = s ;
2015-08-13 10:56:31 +03:00
} else if ( re > ze ) {
/*
2016-04-21 16:04:54 +03:00
* Have to shift z fraction right to align .
2015-08-13 10:56:31 +03:00
*/
s = re - ze ;
2016-04-21 16:04:54 +03:00
zm = XSPSRS ( zm , s ) ;
ze + = s ;
2015-08-13 10:56:31 +03:00
}
assert ( ze = = re ) ;
assert ( ze < = SP_EMAX ) ;
if ( zs = = rs ) {
/*
* Generate 28 bit result of adding two 27 bit numbers
* leaving result in zm , zs and ze .
*/
zm = zm + rm ;
if ( zm > > ( SP_FBITS + 1 + 3 ) ) { /* carry out */
2016-04-21 16:04:54 +03:00
zm = XSPSRS1 ( zm ) ;
ze + + ;
2015-08-13 10:56:31 +03:00
}
} else {
if ( zm > = rm ) {
zm = zm - rm ;
} else {
zm = rm - zm ;
zs = rs ;
}
if ( zm = = 0 )
return ieee754sp_zero ( ieee754_csr . rm = = FPU_CSR_RD ) ;
/*
* Normalize in extended single precision
*/
while ( ( zm > > ( SP_MBITS + 3 ) ) = = 0 ) {
zm < < = 1 ;
ze - - ;
}
}
return ieee754sp_format ( zs , ze , zm ) ;
}
2016-04-21 16:04:49 +03:00
union ieee754sp ieee754sp_maddf ( union ieee754sp z , union ieee754sp x ,
union ieee754sp y )
{
return _sp_maddf ( z , x , y , 0 ) ;
}
union ieee754sp ieee754sp_msubf ( union ieee754sp z , union ieee754sp x ,
union ieee754sp y )
{
return _sp_maddf ( z , x , y , maddf_negate_product ) ;
}