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