···51 fpa11->fpsr = FP_EMULATOR | BIT_AC;52}5354-void SetRoundingMode(const unsigned int opcode)55{56 switch (opcode & MASK_ROUNDING_MODE) {57 default:58 case ROUND_TO_NEAREST:59- float_rounding_mode = float_round_nearest_even;60- break;6162 case ROUND_TO_PLUS_INFINITY:63- float_rounding_mode = float_round_up;64- break;6566 case ROUND_TO_MINUS_INFINITY:67- float_rounding_mode = float_round_down;68- break;6970 case ROUND_TO_ZERO:71- float_rounding_mode = float_round_to_zero;72- break;73 }74}7576-void SetRoundingPrecision(const unsigned int opcode)77{78#ifdef CONFIG_FPE_NWFPE_XP79 switch (opcode & MASK_ROUNDING_PRECISION) {80 case ROUND_SINGLE:81- floatx80_rounding_precision = 32;82- break;8384 case ROUND_DOUBLE:85- floatx80_rounding_precision = 64;86- break;8788 case ROUND_EXTENDED:89- floatx80_rounding_precision = 80;90- break;9192 default:93- floatx80_rounding_precision = 80;94 }95#endif096}9798void nwfpe_init_fpa(union fp_state *fp)···97#endif98 memset(fpa11, 0, sizeof(FPA11));99 resetFPA11();100- SetRoundingMode(ROUND_TO_NEAREST);101- SetRoundingPrecision(ROUND_EXTENDED);102 fpa11->initflag = 1;103}104
···51 fpa11->fpsr = FP_EMULATOR | BIT_AC;52}5354+int8 SetRoundingMode(const unsigned int opcode)55{56 switch (opcode & MASK_ROUNDING_MODE) {57 default:58 case ROUND_TO_NEAREST:59+ return float_round_nearest_even;06061 case ROUND_TO_PLUS_INFINITY:62+ return float_round_up;06364 case ROUND_TO_MINUS_INFINITY:65+ return float_round_down;06667 case ROUND_TO_ZERO:68+ return float_round_to_zero;069 }70}7172+int8 SetRoundingPrecision(const unsigned int opcode)73{74#ifdef CONFIG_FPE_NWFPE_XP75 switch (opcode & MASK_ROUNDING_PRECISION) {76 case ROUND_SINGLE:77+ return 32;07879 case ROUND_DOUBLE:80+ return 64;08182 case ROUND_EXTENDED:83+ return 80;08485 default:86+ return 80;87 }88#endif89+ return 80;90}9192void nwfpe_init_fpa(union fp_state *fp)···103#endif104 memset(fpa11, 0, sizeof(FPA11));105 resetFPA11();00106 fpa11->initflag = 1;107}108
+9-2
arch/arm/nwfpe/fpa11.h
···37/* includes */38#include "fpsr.h" /* FP control and status register definitions */39#include "milieu.h"000000040#include "softfloat.h"4142#define typeNone 0x00···91 initialised. */92} FPA11;9394-extern void SetRoundingMode(const unsigned int);95-extern void SetRoundingPrecision(const unsigned int);96extern void nwfpe_init_fpa(union fp_state *fp);9798#endif
···37/* includes */38#include "fpsr.h" /* FP control and status register definitions */39#include "milieu.h"40+41+struct roundingData {42+ int8 mode;43+ int8 precision;44+ signed char exception;45+};46+47#include "softfloat.h"4849#define typeNone 0x00···84 initialised. */85} FPA11;8687+extern int8 SetRoundingMode(const unsigned int);88+extern int8 SetRoundingPrecision(const unsigned int);89extern void nwfpe_init_fpa(union fp_state *fp);9091#endif
+17-11
arch/arm/nwfpe/fpa11_cpdo.c
···24#include "fpa11.h"25#include "fpopcode.h"2627-unsigned int SingleCPDO(const unsigned int opcode, FPREG * rFd);28-unsigned int DoubleCPDO(const unsigned int opcode, FPREG * rFd);29-unsigned int ExtendedCPDO(const unsigned int opcode, FPREG * rFd);3031unsigned int EmulateCPDO(const unsigned int opcode)32{33 FPA11 *fpa11 = GET_FPA11();34 FPREG *rFd;35 unsigned int nType, nDest, nRc;03637 /* Get the destination size. If not valid let Linux perform38 an invalid instruction trap. */···41 if (typeNone == nDest)42 return 0;4344- SetRoundingMode(opcode);004546 /* Compare the size of the operands in Fn and Fm.47 Choose the largest size and perform operations in that size,···6667 switch (nType) {68 case typeSingle:69- nRc = SingleCPDO(opcode, rFd);70 break;71 case typeDouble:72- nRc = DoubleCPDO(opcode, rFd);73 break;74#ifdef CONFIG_FPE_NWFPE_XP75 case typeExtended:76- nRc = ExtendedCPDO(opcode, rFd);77 break;78#endif79 default:···96 case typeSingle:97 {98 if (typeDouble == nType)99- rFd->fSingle = float64_to_float32(rFd->fDouble);100 else101- rFd->fSingle = floatx80_to_float32(rFd->fExtended);102 }103 break;104···107 if (typeSingle == nType)108 rFd->fDouble = float32_to_float64(rFd->fSingle);109 else110- rFd->fDouble = floatx80_to_float64(rFd->fExtended);111 }112 break;113···124#else125 if (nDest != nType) {126 if (nDest == typeSingle)127- rFd->fSingle = float64_to_float32(rFd->fDouble);128 else129 rFd->fDouble = float32_to_float64(rFd->fSingle);130 }131#endif132 }000133134 return nRc;135}
···24#include "fpa11.h"25#include "fpopcode.h"2627+unsigned int SingleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);28+unsigned int DoubleCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);29+unsigned int ExtendedCPDO(struct roundingData *roundData, const unsigned int opcode, FPREG * rFd);3031unsigned int EmulateCPDO(const unsigned int opcode)32{33 FPA11 *fpa11 = GET_FPA11();34 FPREG *rFd;35 unsigned int nType, nDest, nRc;36+ struct roundingData roundData;3738 /* Get the destination size. If not valid let Linux perform39 an invalid instruction trap. */···40 if (typeNone == nDest)41 return 0;4243+ roundData.mode = SetRoundingMode(opcode);44+ roundData.precision = SetRoundingPrecision(opcode);45+ roundData.exception = 0;4647 /* Compare the size of the operands in Fn and Fm.48 Choose the largest size and perform operations in that size,···6364 switch (nType) {65 case typeSingle:66+ nRc = SingleCPDO(&roundData, opcode, rFd);67 break;68 case typeDouble:69+ nRc = DoubleCPDO(&roundData, opcode, rFd);70 break;71#ifdef CONFIG_FPE_NWFPE_XP72 case typeExtended:73+ nRc = ExtendedCPDO(&roundData, opcode, rFd);74 break;75#endif76 default:···93 case typeSingle:94 {95 if (typeDouble == nType)96+ rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);97 else98+ rFd->fSingle = floatx80_to_float32(&roundData, rFd->fExtended);99 }100 break;101···104 if (typeSingle == nType)105 rFd->fDouble = float32_to_float64(rFd->fSingle);106 else107+ rFd->fDouble = floatx80_to_float64(&roundData, rFd->fExtended);108 }109 break;110···121#else122 if (nDest != nType) {123 if (nDest == typeSingle)124+ rFd->fSingle = float64_to_float32(&roundData, rFd->fDouble);125 else126 rFd->fDouble = float32_to_float64(rFd->fSingle);127 }128#endif129 }130+131+ if (roundData.exception)132+ float_raise(roundData.exception);133134 return nRc;135}
+14-8
arch/arm/nwfpe/fpa11_cpdt.c
···96 }97}9899-static inline void storeSingle(const unsigned int Fn, unsigned int __user *pMem)100{101 FPA11 *fpa11 = GET_FPA11();102 union {···106107 switch (fpa11->fType[Fn]) {108 case typeDouble:109- val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble);110 break;111112#ifdef CONFIG_FPE_NWFPE_XP113 case typeExtended:114- val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended);115 break;116#endif117···122 put_user(val.i[0], pMem);123}124125-static inline void storeDouble(const unsigned int Fn, unsigned int __user *pMem)126{127 FPA11 *fpa11 = GET_FPA11();128 union {···137138#ifdef CONFIG_FPE_NWFPE_XP139 case typeExtended:140- val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended);141 break;142#endif143···259{260 unsigned int __user *pBase, *pAddress, *pFinal;261 unsigned int nRc = 1, write_back = WRITE_BACK(opcode);0262263- SetRoundingMode(ROUND_TO_NEAREST);00264265 pBase = (unsigned int __user *) readRegister(getRn(opcode));266 if (REG_PC == getRn(opcode)) {···284285 switch (opcode & MASK_TRANSFER_LENGTH) {286 case TRANSFER_SINGLE:287- storeSingle(getFd(opcode), pAddress);288 break;289 case TRANSFER_DOUBLE:290- storeDouble(getFd(opcode), pAddress);291 break;292#ifdef CONFIG_FPE_NWFPE_XP293 case TRANSFER_EXTENDED:···297 default:298 nRc = 0;299 }000300301 if (write_back)302 writeRegister(getRn(opcode), (unsigned long) pFinal);
···96 }97}9899+static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)100{101 FPA11 *fpa11 = GET_FPA11();102 union {···106107 switch (fpa11->fType[Fn]) {108 case typeDouble:109+ val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);110 break;111112#ifdef CONFIG_FPE_NWFPE_XP113 case typeExtended:114+ val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);115 break;116#endif117···122 put_user(val.i[0], pMem);123}124125+static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)126{127 FPA11 *fpa11 = GET_FPA11();128 union {···137138#ifdef CONFIG_FPE_NWFPE_XP139 case typeExtended:140+ val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);141 break;142#endif143···259{260 unsigned int __user *pBase, *pAddress, *pFinal;261 unsigned int nRc = 1, write_back = WRITE_BACK(opcode);262+ struct roundingData roundData;263264+ roundData.mode = SetRoundingMode(opcode);265+ roundData.precision = SetRoundingPrecision(opcode);266+ roundData.exception = 0;267268 pBase = (unsigned int __user *) readRegister(getRn(opcode));269 if (REG_PC == getRn(opcode)) {···281282 switch (opcode & MASK_TRANSFER_LENGTH) {283 case TRANSFER_SINGLE:284+ storeSingle(&roundData, getFd(opcode), pAddress);285 break;286 case TRANSFER_DOUBLE:287+ storeDouble(&roundData, getFd(opcode), pAddress);288 break;289#ifdef CONFIG_FPE_NWFPE_XP290 case TRANSFER_EXTENDED:···294 default:295 nRc = 0;296 }297+298+ if (roundData.exception)299+ float_raise(roundData.exception);300301 if (write_back)302 writeRegister(getRn(opcode), (unsigned long) pFinal);
+19-9
arch/arm/nwfpe/fpa11_cprt.c
···33extern flag float64_is_nan(float64);34extern flag float32_is_nan(float32);3536-void SetRoundingMode(const unsigned int opcode);37-38unsigned int PerformFLT(const unsigned int opcode);39unsigned int PerformFIX(const unsigned int opcode);40···75unsigned int PerformFLT(const unsigned int opcode)76{77 FPA11 *fpa11 = GET_FPA11();78- SetRoundingMode(opcode);79- SetRoundingPrecision(opcode);0008081 switch (opcode & MASK_ROUNDING_PRECISION) {82 case ROUND_SINGLE:83 {84 fpa11->fType[getFn(opcode)] = typeSingle;85- fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(readRegister(getRd(opcode)));86 }87 break;88···109 return 0;110 }111000112 return 1;113}114···119{120 FPA11 *fpa11 = GET_FPA11();121 unsigned int Fn = getFm(opcode);0122123- SetRoundingMode(opcode);00124125 switch (fpa11->fType[Fn]) {126 case typeSingle:127 {128- writeRegister(getRd(opcode), float32_to_int32(fpa11->fpreg[Fn].fSingle));129 }130 break;131132 case typeDouble:133 {134- writeRegister(getRd(opcode), float64_to_int32(fpa11->fpreg[Fn].fDouble));135 }136 break;137138#ifdef CONFIG_FPE_NWFPE_XP139 case typeExtended:140 {141- writeRegister(getRd(opcode), floatx80_to_int32(fpa11->fpreg[Fn].fExtended));142 }143 break;144#endif···149 default:150 return 0;151 }000152153 return 1;154}
···33extern flag float64_is_nan(float64);34extern flag float32_is_nan(float32);350036unsigned int PerformFLT(const unsigned int opcode);37unsigned int PerformFIX(const unsigned int opcode);38···77unsigned int PerformFLT(const unsigned int opcode)78{79 FPA11 *fpa11 = GET_FPA11();80+ struct roundingData roundData;81+82+ roundData.mode = SetRoundingMode(opcode);83+ roundData.precision = SetRoundingPrecision(opcode);84+ roundData.exception = 0;8586 switch (opcode & MASK_ROUNDING_PRECISION) {87 case ROUND_SINGLE:88 {89 fpa11->fType[getFn(opcode)] = typeSingle;90+ fpa11->fpreg[getFn(opcode)].fSingle = int32_to_float32(&roundData, readRegister(getRd(opcode)));91 }92 break;93···108 return 0;109 }110111+ if (roundData.exception)112+ float_raise(roundData.exception);113+114 return 1;115}116···115{116 FPA11 *fpa11 = GET_FPA11();117 unsigned int Fn = getFm(opcode);118+ struct roundingData roundData;119120+ roundData.mode = SetRoundingMode(opcode);121+ roundData.precision = SetRoundingPrecision(opcode);122+ roundData.exception = 0;123124 switch (fpa11->fType[Fn]) {125 case typeSingle:126 {127+ writeRegister(getRd(opcode), float32_to_int32(&roundData, fpa11->fpreg[Fn].fSingle));128 }129 break;130131 case typeDouble:132 {133+ writeRegister(getRd(opcode), float64_to_int32(&roundData, fpa11->fpreg[Fn].fDouble));134 }135 break;136137#ifdef CONFIG_FPE_NWFPE_XP138 case typeExtended:139 {140+ writeRegister(getRd(opcode), floatx80_to_int32(&roundData, fpa11->fpreg[Fn].fExtended));141 }142 break;143#endif···142 default:143 return 0;144 }145+146+ if (roundData.exception)147+ float_raise(roundData.exception);148149 return 1;150}
+6-9
arch/arm/nwfpe/fpmodule.c
···116code to access data in user space in some other source files at the 117moment (grep for get_user / put_user calls). --philb]118119-float_exception_flags is a global variable in SoftFloat.120-121This function is called by the SoftFloat routines to raise a floating122point exception. We check the trap enable byte in the FPSR, and raise123a SIGFPE exception if necessary. If not the relevant bits in the ···127 register unsigned int fpsr, cumulativeTraps;128129#ifdef CONFIG_DEBUG_USER130- printk(KERN_DEBUG131- "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",132- current->comm, current->pid, flags,133- __builtin_return_address(0), GET_USERREG()->ARM_pc);00134#endif135-136- /* Keep SoftFloat exception flags up to date. */137- float_exception_flags |= flags;138139 /* Read fpsr and initialize the cumulativeTraps. */140 fpsr = readFPSR();
···116code to access data in user space in some other source files at the 117moment (grep for get_user / put_user calls). --philb]11800119This function is called by the SoftFloat routines to raise a floating120point exception. We check the trap enable byte in the FPSR, and raise121a SIGFPE exception if necessary. If not the relevant bits in the ···129 register unsigned int fpsr, cumulativeTraps;130131#ifdef CONFIG_DEBUG_USER132+ /* Ignore inexact errors as there are far too many of them to log */133+ if (flags & ~BIT_IXC)134+ printk(KERN_DEBUG135+ "NWFPE: %s[%d] takes exception %08x at %p from %08lx\n",136+ current->comm, current->pid, flags,137+ __builtin_return_address(0), GET_USERREG()->ARM_pc);138#endif000139140 /* Read fpsr and initialize the cumulativeTraps. */141 fpsr = readFPSR();