fpa11.c (6008B)
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, see <http://www.gnu.org/licenses/>. 19*/ 20 21#include "qemu/osdep.h" 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 32FPA11* qemufpa = NULL; 33CPUARMState* user_registers; 34 35/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ 36void resetFPA11(void) 37{ 38 int i; 39 FPA11 *fpa11 = GET_FPA11(); 40 41 /* initialize the register type array */ 42 for (i=0;i<=7;i++) 43 { 44 fpa11->fType[i] = typeNone; 45 } 46 47 /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 48 fpa11->fpsr = FP_EMULATOR | BIT_AC; 49 50 /* FPCR: set SB, AB and DA bits, clear all others */ 51#ifdef MAINTAIN_FPCR 52 fpa11->fpcr = MASK_RESET; 53#endif 54} 55 56void SetRoundingMode(const unsigned int opcode) 57{ 58 int rounding_mode; 59 FPA11 *fpa11 = GET_FPA11(); 60 61#ifdef MAINTAIN_FPCR 62 fpa11->fpcr &= ~MASK_ROUNDING_MODE; 63#endif 64 switch (opcode & MASK_ROUNDING_MODE) 65 { 66 default: 67 case ROUND_TO_NEAREST: 68 rounding_mode = float_round_nearest_even; 69#ifdef MAINTAIN_FPCR 70 fpa11->fpcr |= ROUND_TO_NEAREST; 71#endif 72 break; 73 74 case ROUND_TO_PLUS_INFINITY: 75 rounding_mode = float_round_up; 76#ifdef MAINTAIN_FPCR 77 fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; 78#endif 79 break; 80 81 case ROUND_TO_MINUS_INFINITY: 82 rounding_mode = float_round_down; 83#ifdef MAINTAIN_FPCR 84 fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; 85#endif 86 break; 87 88 case ROUND_TO_ZERO: 89 rounding_mode = float_round_to_zero; 90#ifdef MAINTAIN_FPCR 91 fpa11->fpcr |= ROUND_TO_ZERO; 92#endif 93 break; 94 } 95 set_float_rounding_mode(rounding_mode, &fpa11->fp_status); 96} 97 98void SetRoundingPrecision(const unsigned int opcode) 99{ 100 FloatX80RoundPrec rounding_precision; 101 FPA11 *fpa11 = GET_FPA11(); 102#ifdef MAINTAIN_FPCR 103 fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; 104#endif 105 switch (opcode & MASK_ROUNDING_PRECISION) { 106 case ROUND_SINGLE: 107 rounding_precision = floatx80_precision_s; 108#ifdef MAINTAIN_FPCR 109 fpa11->fpcr |= ROUND_SINGLE; 110#endif 111 break; 112 113 case ROUND_DOUBLE: 114 rounding_precision = floatx80_precision_d; 115#ifdef MAINTAIN_FPCR 116 fpa11->fpcr |= ROUND_DOUBLE; 117#endif 118 break; 119 120 case ROUND_EXTENDED: 121 rounding_precision = floatx80_precision_x; 122#ifdef MAINTAIN_FPCR 123 fpa11->fpcr |= ROUND_EXTENDED; 124#endif 125 break; 126 127 default: 128 rounding_precision = floatx80_precision_x; 129 break; 130 } 131 set_floatx80_rounding_precision(rounding_precision, &fpa11->fp_status); 132} 133 134/* Emulate the instruction in the opcode. */ 135/* ??? This is not thread safe. */ 136unsigned int EmulateAll(unsigned int opcode, FPA11* qfpa, CPUARMState* qregs) 137{ 138 unsigned int nRc = 0; 139// unsigned long flags; 140 FPA11 *fpa11; 141 unsigned int cp; 142// save_flags(flags); sti(); 143 144 /* Check that this is really an FPA11 instruction: the coprocessor 145 * field in bits [11:8] must be 1 or 2. 146 */ 147 cp = (opcode >> 8) & 0xf; 148 if (cp != 1 && cp != 2) { 149 return 0; 150 } 151 152 qemufpa=qfpa; 153 user_registers=qregs; 154 155#if 0 156 fprintf(stderr,"emulating FP insn 0x%08x, PC=0x%08x\n", 157 opcode, qregs[ARM_REG_PC]); 158#endif 159 fpa11 = GET_FPA11(); 160 161 if (fpa11->initflag == 0) /* good place for __builtin_expect */ 162 { 163 resetFPA11(); 164 SetRoundingMode(ROUND_TO_NEAREST); 165 SetRoundingPrecision(ROUND_EXTENDED); 166 fpa11->initflag = 1; 167 } 168 169 set_float_exception_flags(0, &fpa11->fp_status); 170 171 if (TEST_OPCODE(opcode,MASK_CPRT)) 172 { 173 //fprintf(stderr,"emulating CPRT\n"); 174 /* Emulate conversion opcodes. */ 175 /* Emulate register transfer opcodes. */ 176 /* Emulate comparison opcodes. */ 177 nRc = EmulateCPRT(opcode); 178 } 179 else if (TEST_OPCODE(opcode,MASK_CPDO)) 180 { 181 //fprintf(stderr,"emulating CPDO\n"); 182 /* Emulate monadic arithmetic opcodes. */ 183 /* Emulate dyadic arithmetic opcodes. */ 184 nRc = EmulateCPDO(opcode); 185 } 186 else if (TEST_OPCODE(opcode,MASK_CPDT)) 187 { 188 //fprintf(stderr,"emulating CPDT\n"); 189 /* Emulate load/store opcodes. */ 190 /* Emulate load/store multiple opcodes. */ 191 nRc = EmulateCPDT(opcode); 192 } 193 else 194 { 195 /* Invalid instruction detected. Return FALSE. */ 196 nRc = 0; 197 } 198 199// restore_flags(flags); 200 if(nRc == 1 && get_float_exception_flags(&fpa11->fp_status)) 201 { 202 //printf("fef 0x%x\n",float_exception_flags); 203 nRc = -get_float_exception_flags(&fpa11->fp_status); 204 } 205 206 //printf("returning %d\n",nRc); 207 return(nRc); 208} 209 210#if 0 211unsigned int EmulateAll1(unsigned int opcode) 212{ 213 switch ((opcode >> 24) & 0xf) 214 { 215 case 0xc: 216 case 0xd: 217 if ((opcode >> 20) & 0x1) 218 { 219 switch ((opcode >> 8) & 0xf) 220 { 221 case 0x1: return PerformLDF(opcode); break; 222 case 0x2: return PerformLFM(opcode); break; 223 default: return 0; 224 } 225 } 226 else 227 { 228 switch ((opcode >> 8) & 0xf) 229 { 230 case 0x1: return PerformSTF(opcode); break; 231 case 0x2: return PerformSFM(opcode); break; 232 default: return 0; 233 } 234 } 235 break; 236 237 case 0xe: 238 if (opcode & 0x10) 239 return EmulateCPDO(opcode); 240 else 241 return EmulateCPRT(opcode); 242 break; 243 244 default: return 0; 245 } 246} 247#endif