2008-05-20 03:52:27 +04:00
/*
2005-04-17 02:20:36 +04:00
* arch / sparc64 / math - emu / math . c
*
* Copyright ( C ) 1997 , 1999 Jakub Jelinek ( jj @ ultra . linux . cz )
* Copyright ( C ) 1999 David S . Miller ( davem @ redhat . com )
*
* Emulation routines originate from soft - fp package , which is part
* of glibc and has appropriate copyrights in it .
*/
# include <linux/types.h>
# include <linux/sched.h>
# include <linux/errno.h>
# include <asm/fpumacro.h>
# include <asm/ptrace.h>
# include <asm/uaccess.h>
# include "sfp-util.h"
# include <math-emu/soft-fp.h>
# include <math-emu/single.h>
# include <math-emu/double.h>
# include <math-emu/quad.h>
/* QUAD - ftt == 3 */
# define FMOVQ 0x003
# define FNEGQ 0x007
# define FABSQ 0x00b
# define FSQRTQ 0x02b
# define FADDQ 0x043
# define FSUBQ 0x047
# define FMULQ 0x04b
# define FDIVQ 0x04f
# define FDMULQ 0x06e
# define FQTOX 0x083
# define FXTOQ 0x08c
# define FQTOS 0x0c7
# define FQTOD 0x0cb
# define FITOQ 0x0cc
# define FSTOQ 0x0cd
# define FDTOQ 0x0ce
# define FQTOI 0x0d3
/* SUBNORMAL - ftt == 2 */
# define FSQRTS 0x029
# define FSQRTD 0x02a
# define FADDS 0x041
# define FADDD 0x042
# define FSUBS 0x045
# define FSUBD 0x046
# define FMULS 0x049
# define FMULD 0x04a
# define FDIVS 0x04d
# define FDIVD 0x04e
# define FSMULD 0x069
# define FSTOX 0x081
# define FDTOX 0x082
# define FDTOS 0x0c6
# define FSTOD 0x0c9
# define FSTOI 0x0d1
# define FDTOI 0x0d2
# define FXTOS 0x084 /* Only Ultra-III generates this. */
# define FXTOD 0x088 /* Only Ultra-III generates this. */
#if 0 /* Optimized inline in sparc64/kernel/entry.S */
# define FITOS 0x0c4 /* Only Ultra-III generates this. */
# endif
# define FITOD 0x0c8 /* Only Ultra-III generates this. */
/* FPOP2 */
# define FCMPQ 0x053
# define FCMPEQ 0x057
# define FMOVQ0 0x003
# define FMOVQ1 0x043
# define FMOVQ2 0x083
# define FMOVQ3 0x0c3
# define FMOVQI 0x103
# define FMOVQX 0x183
# define FMOVQZ 0x027
# define FMOVQLE 0x047
# define FMOVQLZ 0x067
# define FMOVQNZ 0x0a7
# define FMOVQGZ 0x0c7
# define FMOVQGE 0x0e7
# define FSR_TEM_SHIFT 23UL
# define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT)
# define FSR_AEXC_SHIFT 5UL
# define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT)
# define FSR_CEXC_SHIFT 0UL
# define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT)
/* All routines returning an exception to raise should detect
* such exceptions _before_ rounding to be consistent with
* the behavior of the hardware in the implemented cases
* ( and thus with the recommendations in the V9 architecture
* manual ) .
*
* We return 0 if a SIGFPE should be sent , 1 otherwise .
*/
static inline int record_exception ( struct pt_regs * regs , int eflag )
{
u64 fsr = current_thread_info ( ) - > xfsr [ 0 ] ;
int would_trap ;
/* Determine if this exception would have generated a trap. */
would_trap = ( fsr & ( ( long ) eflag < < FSR_TEM_SHIFT ) ) ! = 0UL ;
/* If trapping, we only want to signal one bit. */
if ( would_trap ! = 0 ) {
eflag & = ( ( fsr & FSR_TEM_MASK ) > > FSR_TEM_SHIFT ) ;
if ( ( eflag & ( eflag - 1 ) ) ! = 0 ) {
if ( eflag & FP_EX_INVALID )
eflag = FP_EX_INVALID ;
else if ( eflag & FP_EX_OVERFLOW )
eflag = FP_EX_OVERFLOW ;
else if ( eflag & FP_EX_UNDERFLOW )
eflag = FP_EX_UNDERFLOW ;
else if ( eflag & FP_EX_DIVZERO )
eflag = FP_EX_DIVZERO ;
else if ( eflag & FP_EX_INEXACT )
eflag = FP_EX_INEXACT ;
}
}
/* Set CEXC, here is the rule:
*
* In general all FPU ops will set one and only one
* bit in the CEXC field , this is always the case
* when the IEEE exception trap is enabled in TEM .
*/
fsr & = ~ ( FSR_CEXC_MASK ) ;
fsr | = ( ( long ) eflag < < FSR_CEXC_SHIFT ) ;
/* Set the AEXC field, rule is:
*
* If a trap would not be generated , the
* CEXC just generated is OR ' d into the
* existing value of AEXC .
*/
if ( would_trap = = 0 )
fsr | = ( ( long ) eflag < < FSR_AEXC_SHIFT ) ;
/* If trapping, indicate fault trap type IEEE. */
if ( would_trap ! = 0 )
fsr | = ( 1UL < < 14 ) ;
current_thread_info ( ) - > xfsr [ 0 ] = fsr ;
/* If we will not trap, advance the program counter over
* the instruction being handled .
*/
if ( would_trap = = 0 ) {
regs - > tpc = regs - > tnpc ;
regs - > tnpc + = 4 ;
}
return ( would_trap ? 0 : 1 ) ;
}
typedef union {
u32 s ;
u64 d ;
u64 q [ 2 ] ;
} * argp ;
int do_mathemu ( struct pt_regs * regs , struct fpustate * f )
{
unsigned long pc = regs - > tpc ;
unsigned long tstate = regs - > tstate ;
u32 insn = 0 ;
int type = 0 ;
/* ftt tells which ftt it may happen in, r is rd, b is rs2 and a is rs1. The *u arg tells
whether the argument should be packed / unpacked ( 0 - do not unpack / pack , 1 - unpack / pack )
non - u args tells the size of the argument ( 0 - no argument , 1 - single , 2 - double , 3 - quad */
# define TYPE(ftt, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6) | (ftt << 9)
int freg ;
static u64 zero [ 2 ] = { 0L , 0L } ;
int flags ;
FP_DECL_EX ;
FP_DECL_S ( SA ) ; FP_DECL_S ( SB ) ; FP_DECL_S ( SR ) ;
FP_DECL_D ( DA ) ; FP_DECL_D ( DB ) ; FP_DECL_D ( DR ) ;
FP_DECL_Q ( QA ) ; FP_DECL_Q ( QB ) ; FP_DECL_Q ( QR ) ;
int IR ;
long XR , xfsr ;
if ( tstate & TSTATE_PRIV )
die_if_kernel ( " unfinished/unimplemented FPop from kernel " , regs ) ;
if ( test_thread_flag ( TIF_32BIT ) )
pc = ( u32 ) pc ;
if ( get_user ( insn , ( u32 __user * ) pc ) ! = - EFAULT ) {
if ( ( insn & 0xc1f80000 ) = = 0x81a00000 ) /* FPOP1 */ {
switch ( ( insn > > 5 ) & 0x1ff ) {
/* QUAD - ftt == 3 */
case FMOVQ :
case FNEGQ :
case FABSQ : TYPE ( 3 , 3 , 0 , 3 , 0 , 0 , 0 ) ; break ;
case FSQRTQ : TYPE ( 3 , 3 , 1 , 3 , 1 , 0 , 0 ) ; break ;
case FADDQ :
case FSUBQ :
case FMULQ :
case FDIVQ : TYPE ( 3 , 3 , 1 , 3 , 1 , 3 , 1 ) ; break ;
case FDMULQ : TYPE ( 3 , 3 , 1 , 2 , 1 , 2 , 1 ) ; break ;
case FQTOX : TYPE ( 3 , 2 , 0 , 3 , 1 , 0 , 0 ) ; break ;
case FXTOQ : TYPE ( 3 , 3 , 1 , 2 , 0 , 0 , 0 ) ; break ;
case FQTOS : TYPE ( 3 , 1 , 1 , 3 , 1 , 0 , 0 ) ; break ;
case FQTOD : TYPE ( 3 , 2 , 1 , 3 , 1 , 0 , 0 ) ; break ;
case FITOQ : TYPE ( 3 , 3 , 1 , 1 , 0 , 0 , 0 ) ; break ;
case FSTOQ : TYPE ( 3 , 3 , 1 , 1 , 1 , 0 , 0 ) ; break ;
case FDTOQ : TYPE ( 3 , 3 , 1 , 2 , 1 , 0 , 0 ) ; break ;
case FQTOI : TYPE ( 3 , 1 , 0 , 3 , 1 , 0 , 0 ) ; break ;
2006-02-21 03:02:24 +03:00
/* We can get either unimplemented or unfinished
* for these cases . Pre - Niagara systems generate
* unfinished fpop for SUBNORMAL cases , and Niagara
* always gives unimplemented fpop for fsqrt { s , d } .
*/
case FSQRTS : {
unsigned long x = current_thread_info ( ) - > xfsr [ 0 ] ;
x = ( x > > 14 ) & 0xf ;
TYPE ( x , 1 , 1 , 1 , 1 , 0 , 0 ) ;
break ;
}
case FSQRTD : {
unsigned long x = current_thread_info ( ) - > xfsr [ 0 ] ;
x = ( x > > 14 ) & 0xf ;
TYPE ( x , 2 , 1 , 2 , 1 , 0 , 0 ) ;
break ;
}
2005-04-17 02:20:36 +04:00
/* SUBNORMAL - ftt == 2 */
case FADDD :
case FSUBD :
case FMULD :
case FDIVD : TYPE ( 2 , 2 , 1 , 2 , 1 , 2 , 1 ) ; break ;
case FADDS :
case FSUBS :
case FMULS :
case FDIVS : TYPE ( 2 , 1 , 1 , 1 , 1 , 1 , 1 ) ; break ;
case FSMULD : TYPE ( 2 , 2 , 1 , 1 , 1 , 1 , 1 ) ; break ;
case FSTOX : TYPE ( 2 , 2 , 0 , 1 , 1 , 0 , 0 ) ; break ;
case FDTOX : TYPE ( 2 , 2 , 0 , 2 , 1 , 0 , 0 ) ; break ;
case FDTOS : TYPE ( 2 , 1 , 1 , 2 , 1 , 0 , 0 ) ; break ;
case FSTOD : TYPE ( 2 , 2 , 1 , 1 , 1 , 0 , 0 ) ; break ;
case FSTOI : TYPE ( 2 , 1 , 0 , 1 , 1 , 0 , 0 ) ; break ;
case FDTOI : TYPE ( 2 , 1 , 0 , 2 , 1 , 0 , 0 ) ; break ;
/* Only Ultra-III generates these */
case FXTOS : TYPE ( 2 , 1 , 1 , 2 , 0 , 0 , 0 ) ; break ;
case FXTOD : TYPE ( 2 , 2 , 1 , 2 , 0 , 0 , 0 ) ; break ;
#if 0 /* Optimized inline in sparc64/kernel/entry.S */
case FITOS : TYPE ( 2 , 1 , 1 , 1 , 0 , 0 , 0 ) ; break ;
# endif
case FITOD : TYPE ( 2 , 2 , 1 , 1 , 0 , 0 , 0 ) ; break ;
}
}
else if ( ( insn & 0xc1f80000 ) = = 0x81a80000 ) /* FPOP2 */ {
IR = 2 ;
switch ( ( insn > > 5 ) & 0x1ff ) {
case FCMPQ : TYPE ( 3 , 0 , 0 , 3 , 1 , 3 , 1 ) ; break ;
case FCMPEQ : TYPE ( 3 , 0 , 0 , 3 , 1 , 3 , 1 ) ; break ;
/* Now the conditional fmovq support */
case FMOVQ0 :
case FMOVQ1 :
case FMOVQ2 :
case FMOVQ3 :
/* fmovq %fccX, %fY, %fZ */
if ( ! ( ( insn > > 11 ) & 3 ) )
XR = current_thread_info ( ) - > xfsr [ 0 ] > > 10 ;
else
XR = current_thread_info ( ) - > xfsr [ 0 ] > > ( 30 + ( ( insn > > 10 ) & 0x6 ) ) ;
XR & = 3 ;
IR = 0 ;
switch ( ( insn > > 14 ) & 0x7 ) {
/* case 0: IR = 0; break; */ /* Never */
case 1 : if ( XR ) IR = 1 ; break ; /* Not Equal */
case 2 : if ( XR = = 1 | | XR = = 2 ) IR = 1 ; break ; /* Less or Greater */
case 3 : if ( XR & 1 ) IR = 1 ; break ; /* Unordered or Less */
case 4 : if ( XR = = 1 ) IR = 1 ; break ; /* Less */
case 5 : if ( XR & 2 ) IR = 1 ; break ; /* Unordered or Greater */
case 6 : if ( XR = = 2 ) IR = 1 ; break ; /* Greater */
case 7 : if ( XR = = 3 ) IR = 1 ; break ; /* Unordered */
}
if ( ( insn > > 14 ) & 8 )
IR ^ = 1 ;
break ;
case FMOVQI :
case FMOVQX :
/* fmovq %[ix]cc, %fY, %fZ */
XR = regs - > tstate > > 32 ;
if ( ( insn > > 5 ) & 0x80 )
XR > > = 4 ;
XR & = 0xf ;
IR = 0 ;
freg = ( ( XR > > 2 ) ^ XR ) & 2 ;
switch ( ( insn > > 14 ) & 0x7 ) {
/* case 0: IR = 0; break; */ /* Never */
case 1 : if ( XR & 4 ) IR = 1 ; break ; /* Equal */
case 2 : if ( ( XR & 4 ) | | freg ) IR = 1 ; break ; /* Less or Equal */
case 3 : if ( freg ) IR = 1 ; break ; /* Less */
case 4 : if ( XR & 5 ) IR = 1 ; break ; /* Less or Equal Unsigned */
case 5 : if ( XR & 1 ) IR = 1 ; break ; /* Carry Set */
case 6 : if ( XR & 8 ) IR = 1 ; break ; /* Negative */
case 7 : if ( XR & 2 ) IR = 1 ; break ; /* Overflow Set */
}
if ( ( insn > > 14 ) & 8 )
IR ^ = 1 ;
break ;
case FMOVQZ :
case FMOVQLE :
case FMOVQLZ :
case FMOVQNZ :
case FMOVQGZ :
case FMOVQGE :
freg = ( insn > > 14 ) & 0x1f ;
if ( ! freg )
XR = 0 ;
else if ( freg < 16 )
XR = regs - > u_regs [ freg ] ;
else if ( test_thread_flag ( TIF_32BIT ) ) {
struct reg_window32 __user * win32 ;
flushw_user ( ) ;
win32 = ( struct reg_window32 __user * ) ( ( unsigned long ) ( ( u32 ) regs - > u_regs [ UREG_FP ] ) ) ;
get_user ( XR , & win32 - > locals [ freg - 16 ] ) ;
} else {
struct reg_window __user * win ;
flushw_user ( ) ;
win = ( struct reg_window __user * ) ( regs - > u_regs [ UREG_FP ] + STACK_BIAS ) ;
get_user ( XR , & win - > locals [ freg - 16 ] ) ;
}
IR = 0 ;
switch ( ( insn > > 10 ) & 3 ) {
case 1 : if ( ! XR ) IR = 1 ; break ; /* Register Zero */
case 2 : if ( XR < = 0 ) IR = 1 ; break ; /* Register Less Than or Equal to Zero */
case 3 : if ( XR < 0 ) IR = 1 ; break ; /* Register Less Than Zero */
}
if ( ( insn > > 10 ) & 4 )
IR ^ = 1 ;
break ;
}
if ( IR = = 0 ) {
/* The fmov test was false. Do a nop instead */
current_thread_info ( ) - > xfsr [ 0 ] & = ~ ( FSR_CEXC_MASK ) ;
regs - > tpc = regs - > tnpc ;
regs - > tnpc + = 4 ;
return 1 ;
} else if ( IR = = 1 ) {
/* Change the instruction into plain fmovq */
insn = ( insn & 0x3e00001f ) | 0x81a00060 ;
TYPE ( 3 , 3 , 0 , 3 , 0 , 0 , 0 ) ;
}
}
}
if ( type ) {
argp rs1 = NULL , rs2 = NULL , rd = NULL ;
freg = ( current_thread_info ( ) - > xfsr [ 0 ] > > 14 ) & 0xf ;
if ( freg ! = ( type > > 9 ) )
goto err ;
current_thread_info ( ) - > xfsr [ 0 ] & = ~ 0x1c000 ;
freg = ( ( insn > > 14 ) & 0x1f ) ;
switch ( type & 0x3 ) {
case 3 : if ( freg & 2 ) {
current_thread_info ( ) - > xfsr [ 0 ] | = ( 6 < < 14 ) /* invalid_fp_register */ ;
goto err ;
}
case 2 : freg = ( ( freg & 1 ) < < 5 ) | ( freg & 0x1e ) ;
case 1 : rs1 = ( argp ) & f - > regs [ freg ] ;
flags = ( freg < 32 ) ? FPRS_DL : FPRS_DU ;
if ( ! ( current_thread_info ( ) - > fpsaved [ 0 ] & flags ) )
rs1 = ( argp ) & zero ;
break ;
}
switch ( type & 0x7 ) {
case 7 : FP_UNPACK_QP ( QA , rs1 ) ; break ;
case 6 : FP_UNPACK_DP ( DA , rs1 ) ; break ;
case 5 : FP_UNPACK_SP ( SA , rs1 ) ; break ;
}
freg = ( insn & 0x1f ) ;
switch ( ( type > > 3 ) & 0x3 ) {
case 3 : if ( freg & 2 ) {
current_thread_info ( ) - > xfsr [ 0 ] | = ( 6 < < 14 ) /* invalid_fp_register */ ;
goto err ;
}
case 2 : freg = ( ( freg & 1 ) < < 5 ) | ( freg & 0x1e ) ;
case 1 : rs2 = ( argp ) & f - > regs [ freg ] ;
flags = ( freg < 32 ) ? FPRS_DL : FPRS_DU ;
if ( ! ( current_thread_info ( ) - > fpsaved [ 0 ] & flags ) )
rs2 = ( argp ) & zero ;
break ;
}
switch ( ( type > > 3 ) & 0x7 ) {
case 7 : FP_UNPACK_QP ( QB , rs2 ) ; break ;
case 6 : FP_UNPACK_DP ( DB , rs2 ) ; break ;
case 5 : FP_UNPACK_SP ( SB , rs2 ) ; break ;
}
freg = ( ( insn > > 25 ) & 0x1f ) ;
switch ( ( type > > 6 ) & 0x3 ) {
case 3 : if ( freg & 2 ) {
current_thread_info ( ) - > xfsr [ 0 ] | = ( 6 < < 14 ) /* invalid_fp_register */ ;
goto err ;
}
case 2 : freg = ( ( freg & 1 ) < < 5 ) | ( freg & 0x1e ) ;
case 1 : rd = ( argp ) & f - > regs [ freg ] ;
flags = ( freg < 32 ) ? FPRS_DL : FPRS_DU ;
if ( ! ( current_thread_info ( ) - > fpsaved [ 0 ] & FPRS_FEF ) ) {
current_thread_info ( ) - > fpsaved [ 0 ] = FPRS_FEF ;
current_thread_info ( ) - > gsr [ 0 ] = 0 ;
}
if ( ! ( current_thread_info ( ) - > fpsaved [ 0 ] & flags ) ) {
if ( freg < 32 )
memset ( f - > regs , 0 , 32 * sizeof ( u32 ) ) ;
else
memset ( f - > regs + 32 , 0 , 32 * sizeof ( u32 ) ) ;
}
current_thread_info ( ) - > fpsaved [ 0 ] | = flags ;
break ;
}
switch ( ( insn > > 5 ) & 0x1ff ) {
/* + */
case FADDS : FP_ADD_S ( SR , SA , SB ) ; break ;
case FADDD : FP_ADD_D ( DR , DA , DB ) ; break ;
case FADDQ : FP_ADD_Q ( QR , QA , QB ) ; break ;
/* - */
case FSUBS : FP_SUB_S ( SR , SA , SB ) ; break ;
case FSUBD : FP_SUB_D ( DR , DA , DB ) ; break ;
case FSUBQ : FP_SUB_Q ( QR , QA , QB ) ; break ;
/* * */
case FMULS : FP_MUL_S ( SR , SA , SB ) ; break ;
case FSMULD : FP_CONV ( D , S , 1 , 1 , DA , SA ) ;
FP_CONV ( D , S , 1 , 1 , DB , SB ) ;
case FMULD : FP_MUL_D ( DR , DA , DB ) ; break ;
case FDMULQ : FP_CONV ( Q , D , 2 , 1 , QA , DA ) ;
FP_CONV ( Q , D , 2 , 1 , QB , DB ) ;
case FMULQ : FP_MUL_Q ( QR , QA , QB ) ; break ;
/* / */
case FDIVS : FP_DIV_S ( SR , SA , SB ) ; break ;
case FDIVD : FP_DIV_D ( DR , DA , DB ) ; break ;
case FDIVQ : FP_DIV_Q ( QR , QA , QB ) ; break ;
/* sqrt */
case FSQRTS : FP_SQRT_S ( SR , SB ) ; break ;
case FSQRTD : FP_SQRT_D ( DR , DB ) ; break ;
case FSQRTQ : FP_SQRT_Q ( QR , QB ) ; break ;
/* mov */
case FMOVQ : rd - > q [ 0 ] = rs2 - > q [ 0 ] ; rd - > q [ 1 ] = rs2 - > q [ 1 ] ; break ;
case FABSQ : rd - > q [ 0 ] = rs2 - > q [ 0 ] & 0x7fffffffffffffffUL ; rd - > q [ 1 ] = rs2 - > q [ 1 ] ; break ;
case FNEGQ : rd - > q [ 0 ] = rs2 - > q [ 0 ] ^ 0x8000000000000000UL ; rd - > q [ 1 ] = rs2 - > q [ 1 ] ; break ;
/* float to int */
case FSTOI : FP_TO_INT_S ( IR , SB , 32 , 1 ) ; break ;
case FDTOI : FP_TO_INT_D ( IR , DB , 32 , 1 ) ; break ;
case FQTOI : FP_TO_INT_Q ( IR , QB , 32 , 1 ) ; break ;
case FSTOX : FP_TO_INT_S ( XR , SB , 64 , 1 ) ; break ;
case FDTOX : FP_TO_INT_D ( XR , DB , 64 , 1 ) ; break ;
case FQTOX : FP_TO_INT_Q ( XR , QB , 64 , 1 ) ; break ;
/* int to float */
case FITOQ : IR = rs2 - > s ; FP_FROM_INT_Q ( QR , IR , 32 , int ) ; break ;
case FXTOQ : XR = rs2 - > d ; FP_FROM_INT_Q ( QR , XR , 64 , long ) ; break ;
/* Only Ultra-III generates these */
case FXTOS : XR = rs2 - > d ; FP_FROM_INT_S ( SR , XR , 64 , long ) ; break ;
case FXTOD : XR = rs2 - > d ; FP_FROM_INT_D ( DR , XR , 64 , long ) ; break ;
#if 0 /* Optimized inline in sparc64/kernel/entry.S */
case FITOS : IR = rs2 - > s ; FP_FROM_INT_S ( SR , IR , 32 , int ) ; break ;
# endif
case FITOD : IR = rs2 - > s ; FP_FROM_INT_D ( DR , IR , 32 , int ) ; break ;
/* float to float */
case FSTOD : FP_CONV ( D , S , 1 , 1 , DR , SB ) ; break ;
case FSTOQ : FP_CONV ( Q , S , 2 , 1 , QR , SB ) ; break ;
case FDTOQ : FP_CONV ( Q , D , 2 , 1 , QR , DB ) ; break ;
case FDTOS : FP_CONV ( S , D , 1 , 1 , SR , DB ) ; break ;
case FQTOS : FP_CONV ( S , Q , 1 , 2 , SR , QB ) ; break ;
case FQTOD : FP_CONV ( D , Q , 1 , 2 , DR , QB ) ; break ;
/* comparison */
case FCMPQ :
case FCMPEQ :
FP_CMP_Q ( XR , QB , QA , 3 ) ;
if ( XR = = 3 & &
( ( ( insn > > 5 ) & 0x1ff ) = = FCMPEQ | |
FP_ISSIGNAN_Q ( QA ) | |
FP_ISSIGNAN_Q ( QB ) ) )
FP_SET_EXCEPTION ( FP_EX_INVALID ) ;
}
if ( ! FP_INHIBIT_RESULTS ) {
switch ( ( type > > 6 ) & 0x7 ) {
case 0 : xfsr = current_thread_info ( ) - > xfsr [ 0 ] ;
if ( XR = = - 1 ) XR = 2 ;
switch ( freg & 3 ) {
/* fcc0, 1, 2, 3 */
case 0 : xfsr & = ~ 0xc00 ; xfsr | = ( XR < < 10 ) ; break ;
case 1 : xfsr & = ~ 0x300000000UL ; xfsr | = ( XR < < 32 ) ; break ;
case 2 : xfsr & = ~ 0xc00000000UL ; xfsr | = ( XR < < 34 ) ; break ;
case 3 : xfsr & = ~ 0x3000000000UL ; xfsr | = ( XR < < 36 ) ; break ;
}
current_thread_info ( ) - > xfsr [ 0 ] = xfsr ;
break ;
case 1 : rd - > s = IR ; break ;
case 2 : rd - > d = XR ; break ;
case 5 : FP_PACK_SP ( rd , SR ) ; break ;
case 6 : FP_PACK_DP ( rd , DR ) ; break ;
case 7 : FP_PACK_QP ( rd , QR ) ; break ;
}
}
if ( _fex ! = 0 )
return record_exception ( regs , _fex ) ;
/* Success and no exceptions detected. */
current_thread_info ( ) - > xfsr [ 0 ] & = ~ ( FSR_CEXC_MASK ) ;
regs - > tpc = regs - > tnpc ;
regs - > tnpc + = 4 ;
return 1 ;
}
err : return 0 ;
}