1*3ebdd119Saurel32 /* 2*3ebdd119Saurel32 NetWinder Floating Point Emulator 3*3ebdd119Saurel32 (c) Rebel.COM, 1998,1999 4*3ebdd119Saurel32 5*3ebdd119Saurel32 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 6*3ebdd119Saurel32 7*3ebdd119Saurel32 This program is free software; you can redistribute it and/or modify 8*3ebdd119Saurel32 it under the terms of the GNU General Public License as published by 9*3ebdd119Saurel32 the Free Software Foundation; either version 2 of the License, or 10*3ebdd119Saurel32 (at your option) any later version. 11*3ebdd119Saurel32 12*3ebdd119Saurel32 This program is distributed in the hope that it will be useful, 13*3ebdd119Saurel32 but WITHOUT ANY WARRANTY; without even the implied warranty of 14*3ebdd119Saurel32 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*3ebdd119Saurel32 GNU General Public License for more details. 16*3ebdd119Saurel32 17*3ebdd119Saurel32 You should have received a copy of the GNU General Public License 18*3ebdd119Saurel32 along with this program; if not, write to the Free Software 19*3ebdd119Saurel32 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*3ebdd119Saurel32 */ 21*3ebdd119Saurel32 22*3ebdd119Saurel32 #include "fpa11.h" 23*3ebdd119Saurel32 24*3ebdd119Saurel32 #include "fpopcode.h" 25*3ebdd119Saurel32 26*3ebdd119Saurel32 //#include "fpmodule.h" 27*3ebdd119Saurel32 //#include "fpmodule.inl" 28*3ebdd119Saurel32 29*3ebdd119Saurel32 //#include <asm/system.h> 30*3ebdd119Saurel32 31*3ebdd119Saurel32 #include <stdio.h> 32*3ebdd119Saurel32 33*3ebdd119Saurel32 /* forward declarations */ 34*3ebdd119Saurel32 unsigned int EmulateCPDO(const unsigned int); 35*3ebdd119Saurel32 unsigned int EmulateCPDT(const unsigned int); 36*3ebdd119Saurel32 unsigned int EmulateCPRT(const unsigned int); 37*3ebdd119Saurel32 38*3ebdd119Saurel32 FPA11* qemufpa=0; 39*3ebdd119Saurel32 CPUARMState* user_registers; 40*3ebdd119Saurel32 41*3ebdd119Saurel32 /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ 42*3ebdd119Saurel32 void resetFPA11(void) 43*3ebdd119Saurel32 { 44*3ebdd119Saurel32 int i; 45*3ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11(); 46*3ebdd119Saurel32 47*3ebdd119Saurel32 /* initialize the register type array */ 48*3ebdd119Saurel32 for (i=0;i<=7;i++) 49*3ebdd119Saurel32 { 50*3ebdd119Saurel32 fpa11->fType[i] = typeNone; 51*3ebdd119Saurel32 } 52*3ebdd119Saurel32 53*3ebdd119Saurel32 /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 54*3ebdd119Saurel32 fpa11->fpsr = FP_EMULATOR | BIT_AC; 55*3ebdd119Saurel32 56*3ebdd119Saurel32 /* FPCR: set SB, AB and DA bits, clear all others */ 57*3ebdd119Saurel32 #if MAINTAIN_FPCR 58*3ebdd119Saurel32 fpa11->fpcr = MASK_RESET; 59*3ebdd119Saurel32 #endif 60*3ebdd119Saurel32 } 61*3ebdd119Saurel32 62*3ebdd119Saurel32 void SetRoundingMode(const unsigned int opcode) 63*3ebdd119Saurel32 { 64*3ebdd119Saurel32 int rounding_mode; 65*3ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11(); 66*3ebdd119Saurel32 67*3ebdd119Saurel32 #if MAINTAIN_FPCR 68*3ebdd119Saurel32 fpa11->fpcr &= ~MASK_ROUNDING_MODE; 69*3ebdd119Saurel32 #endif 70*3ebdd119Saurel32 switch (opcode & MASK_ROUNDING_MODE) 71*3ebdd119Saurel32 { 72*3ebdd119Saurel32 default: 73*3ebdd119Saurel32 case ROUND_TO_NEAREST: 74*3ebdd119Saurel32 rounding_mode = float_round_nearest_even; 75*3ebdd119Saurel32 #if MAINTAIN_FPCR 76*3ebdd119Saurel32 fpa11->fpcr |= ROUND_TO_NEAREST; 77*3ebdd119Saurel32 #endif 78*3ebdd119Saurel32 break; 79*3ebdd119Saurel32 80*3ebdd119Saurel32 case ROUND_TO_PLUS_INFINITY: 81*3ebdd119Saurel32 rounding_mode = float_round_up; 82*3ebdd119Saurel32 #if MAINTAIN_FPCR 83*3ebdd119Saurel32 fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; 84*3ebdd119Saurel32 #endif 85*3ebdd119Saurel32 break; 86*3ebdd119Saurel32 87*3ebdd119Saurel32 case ROUND_TO_MINUS_INFINITY: 88*3ebdd119Saurel32 rounding_mode = float_round_down; 89*3ebdd119Saurel32 #if MAINTAIN_FPCR 90*3ebdd119Saurel32 fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; 91*3ebdd119Saurel32 #endif 92*3ebdd119Saurel32 break; 93*3ebdd119Saurel32 94*3ebdd119Saurel32 case ROUND_TO_ZERO: 95*3ebdd119Saurel32 rounding_mode = float_round_to_zero; 96*3ebdd119Saurel32 #if MAINTAIN_FPCR 97*3ebdd119Saurel32 fpa11->fpcr |= ROUND_TO_ZERO; 98*3ebdd119Saurel32 #endif 99*3ebdd119Saurel32 break; 100*3ebdd119Saurel32 } 101*3ebdd119Saurel32 set_float_rounding_mode(rounding_mode, &fpa11->fp_status); 102*3ebdd119Saurel32 } 103*3ebdd119Saurel32 104*3ebdd119Saurel32 void SetRoundingPrecision(const unsigned int opcode) 105*3ebdd119Saurel32 { 106*3ebdd119Saurel32 int rounding_precision; 107*3ebdd119Saurel32 FPA11 *fpa11 = GET_FPA11(); 108*3ebdd119Saurel32 #if MAINTAIN_FPCR 109*3ebdd119Saurel32 fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; 110*3ebdd119Saurel32 #endif 111*3ebdd119Saurel32 switch (opcode & MASK_ROUNDING_PRECISION) 112*3ebdd119Saurel32 { 113*3ebdd119Saurel32 case ROUND_SINGLE: 114*3ebdd119Saurel32 rounding_precision = 32; 115*3ebdd119Saurel32 #if MAINTAIN_FPCR 116*3ebdd119Saurel32 fpa11->fpcr |= ROUND_SINGLE; 117*3ebdd119Saurel32 #endif 118*3ebdd119Saurel32 break; 119*3ebdd119Saurel32 120*3ebdd119Saurel32 case ROUND_DOUBLE: 121*3ebdd119Saurel32 rounding_precision = 64; 122*3ebdd119Saurel32 #if MAINTAIN_FPCR 123*3ebdd119Saurel32 fpa11->fpcr |= ROUND_DOUBLE; 124*3ebdd119Saurel32 #endif 125*3ebdd119Saurel32 break; 126*3ebdd119Saurel32 127*3ebdd119Saurel32 case ROUND_EXTENDED: 128*3ebdd119Saurel32 rounding_precision = 80; 129*3ebdd119Saurel32 #if MAINTAIN_FPCR 130*3ebdd119Saurel32 fpa11->fpcr |= ROUND_EXTENDED; 131*3ebdd119Saurel32 #endif 132*3ebdd119Saurel32 break; 133*3ebdd119Saurel32 134*3ebdd119Saurel32 default: rounding_precision = 80; 135*3ebdd119Saurel32 } 136*3ebdd119Saurel32 set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); 137*3ebdd119Saurel32 } 138*3ebdd119Saurel32 139*3ebdd119Saurel32 /* Emulate the instruction in the opcode. */ 140*3ebdd119Saurel32 /* ??? This is not thread safe. */ 141*3ebdd119Saurel32 unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) 142*3ebdd119Saurel32 { 143*3ebdd119Saurel32 unsigned int nRc = 0; 144*3ebdd119Saurel32 // unsigned long flags; 145*3ebdd119Saurel32 FPA11 *fpa11; 146*3ebdd119Saurel32 // save_flags(flags); sti(); 147*3ebdd119Saurel32 148*3ebdd119Saurel32 qemufpa=qfpa; 149*3ebdd119Saurel32 user_registers=qregs; 150*3ebdd119Saurel32 151*3ebdd119Saurel32 #if 0 152*3ebdd119Saurel32 fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", 153*3ebdd119Saurel32 opcode, qregs[REG_PC]); 154*3ebdd119Saurel32 #endif 155*3ebdd119Saurel32 fpa11 = GET_FPA11(); 156*3ebdd119Saurel32 157*3ebdd119Saurel32 if (fpa11->initflag == 0) /* good place for __builtin_expect */ 158*3ebdd119Saurel32 { 159*3ebdd119Saurel32 resetFPA11(); 160*3ebdd119Saurel32 SetRoundingMode(ROUND_TO_NEAREST); 161*3ebdd119Saurel32 SetRoundingPrecision(ROUND_EXTENDED); 162*3ebdd119Saurel32 fpa11->initflag = 1; 163*3ebdd119Saurel32 } 164*3ebdd119Saurel32 165*3ebdd119Saurel32 set_float_exception_flags(0, &fpa11->fp_status); 166*3ebdd119Saurel32 167*3ebdd119Saurel32 if (TEST_OPCODE(opcode,MASK_CPRT)) 168*3ebdd119Saurel32 { 169*3ebdd119Saurel32 //fprintf(stderr,"emulating CPRT\n"); 170*3ebdd119Saurel32 /* Emulate conversion opcodes. */ 171*3ebdd119Saurel32 /* Emulate register transfer opcodes. */ 172*3ebdd119Saurel32 /* Emulate comparison opcodes. */ 173*3ebdd119Saurel32 nRc = EmulateCPRT(opcode); 174*3ebdd119Saurel32 } 175*3ebdd119Saurel32 else if (TEST_OPCODE(opcode,MASK_CPDO)) 176*3ebdd119Saurel32 { 177*3ebdd119Saurel32 //fprintf(stderr,"emulating CPDO\n"); 178*3ebdd119Saurel32 /* Emulate monadic arithmetic opcodes. */ 179*3ebdd119Saurel32 /* Emulate dyadic arithmetic opcodes. */ 180*3ebdd119Saurel32 nRc = EmulateCPDO(opcode); 181*3ebdd119Saurel32 } 182*3ebdd119Saurel32 else if (TEST_OPCODE(opcode,MASK_CPDT)) 183*3ebdd119Saurel32 { 184*3ebdd119Saurel32 //fprintf(stderr,"emulating CPDT\n"); 185*3ebdd119Saurel32 /* Emulate load/store opcodes. */ 186*3ebdd119Saurel32 /* Emulate load/store multiple opcodes. */ 187*3ebdd119Saurel32 nRc = EmulateCPDT(opcode); 188*3ebdd119Saurel32 } 189*3ebdd119Saurel32 else 190*3ebdd119Saurel32 { 191*3ebdd119Saurel32 /* Invalid instruction detected. Return FALSE. */ 192*3ebdd119Saurel32 nRc = 0; 193*3ebdd119Saurel32 } 194*3ebdd119Saurel32 195*3ebdd119Saurel32 // restore_flags(flags); 196*3ebdd119Saurel32 if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status)) 197*3ebdd119Saurel32 { 198*3ebdd119Saurel32 //printf("fef 0x%x\n",float_exception_flags); 199*3ebdd119Saurel32 nRc=-get_float_exception_flags(&fpa11->fp_status); 200*3ebdd119Saurel32 } 201*3ebdd119Saurel32 202*3ebdd119Saurel32 //printf("returning %d\n",nRc); 203*3ebdd119Saurel32 return(nRc); 204*3ebdd119Saurel32 } 205*3ebdd119Saurel32 206*3ebdd119Saurel32 #if 0 207*3ebdd119Saurel32 unsigned int EmulateAll1(unsigned int opcode) 208*3ebdd119Saurel32 { 209*3ebdd119Saurel32 switch ((opcode >> 24) & 0xf) 210*3ebdd119Saurel32 { 211*3ebdd119Saurel32 case 0xc: 212*3ebdd119Saurel32 case 0xd: 213*3ebdd119Saurel32 if ((opcode >> 20) & 0x1) 214*3ebdd119Saurel32 { 215*3ebdd119Saurel32 switch ((opcode >> 8) & 0xf) 216*3ebdd119Saurel32 { 217*3ebdd119Saurel32 case 0x1: return PerformLDF(opcode); break; 218*3ebdd119Saurel32 case 0x2: return PerformLFM(opcode); break; 219*3ebdd119Saurel32 default: return 0; 220*3ebdd119Saurel32 } 221*3ebdd119Saurel32 } 222*3ebdd119Saurel32 else 223*3ebdd119Saurel32 { 224*3ebdd119Saurel32 switch ((opcode >> 8) & 0xf) 225*3ebdd119Saurel32 { 226*3ebdd119Saurel32 case 0x1: return PerformSTF(opcode); break; 227*3ebdd119Saurel32 case 0x2: return PerformSFM(opcode); break; 228*3ebdd119Saurel32 default: return 0; 229*3ebdd119Saurel32 } 230*3ebdd119Saurel32 } 231*3ebdd119Saurel32 break; 232*3ebdd119Saurel32 233*3ebdd119Saurel32 case 0xe: 234*3ebdd119Saurel32 if (opcode & 0x10) 235*3ebdd119Saurel32 return EmulateCPDO(opcode); 236*3ebdd119Saurel32 else 237*3ebdd119Saurel32 return EmulateCPRT(opcode); 238*3ebdd119Saurel32 break; 239*3ebdd119Saurel32 240*3ebdd119Saurel32 default: return 0; 241*3ebdd119Saurel32 } 242*3ebdd119Saurel32 } 243*3ebdd119Saurel32 #endif 244*3ebdd119Saurel32 245