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/* forward declarations */ 32unsigned int EmulateCPDO(const unsigned int); 33unsigned int EmulateCPDT(const unsigned int); 34unsigned int EmulateCPRT(const unsigned int); 35 36/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ 37void resetFPA11(void) 38{ 39 int i; 40 FPA11 *fpa11 = GET_FPA11(); 41 42 /* initialize the register type array */ 43 for (i=0;i<=7;i++) 44 { 45 fpa11->fType[i] = typeNone; 46 } 47 48 /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 49 fpa11->fpsr = FP_EMULATOR | BIT_AC; 50 51 /* FPCR: set SB, AB and DA bits, clear all others */ 52#if MAINTAIN_FPCR 53 fpa11->fpcr = MASK_RESET; 54#endif 55} 56 57void SetRoundingMode(const unsigned int opcode) 58{ 59#if MAINTAIN_FPCR 60 FPA11 *fpa11 = GET_FPA11(); 61 fpa11->fpcr &= ~MASK_ROUNDING_MODE; 62#endif 63 switch (opcode & MASK_ROUNDING_MODE) 64 { 65 default: 66 case ROUND_TO_NEAREST: 67 float_rounding_mode = float_round_nearest_even; 68#if MAINTAIN_FPCR 69 fpa11->fpcr |= ROUND_TO_NEAREST; 70#endif 71 break; 72 73 case ROUND_TO_PLUS_INFINITY: 74 float_rounding_mode = float_round_up; 75#if MAINTAIN_FPCR 76 fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; 77#endif 78 break; 79 80 case ROUND_TO_MINUS_INFINITY: 81 float_rounding_mode = float_round_down; 82#if MAINTAIN_FPCR 83 fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; 84#endif 85 break; 86 87 case ROUND_TO_ZERO: 88 float_rounding_mode = float_round_to_zero; 89#if MAINTAIN_FPCR 90 fpa11->fpcr |= ROUND_TO_ZERO; 91#endif 92 break; 93 } 94} 95 96void SetRoundingPrecision(const unsigned int opcode) 97{ 98#if MAINTAIN_FPCR 99 FPA11 *fpa11 = GET_FPA11(); 100 fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; 101#endif 102 switch (opcode & MASK_ROUNDING_PRECISION) 103 { 104 case ROUND_SINGLE: 105 floatx80_rounding_precision = 32; 106#if MAINTAIN_FPCR 107 fpa11->fpcr |= ROUND_SINGLE; 108#endif 109 break; 110 111 case ROUND_DOUBLE: 112 floatx80_rounding_precision = 64; 113#if MAINTAIN_FPCR 114 fpa11->fpcr |= ROUND_DOUBLE; 115#endif 116 break; 117 118 case ROUND_EXTENDED: 119 floatx80_rounding_precision = 80; 120#if MAINTAIN_FPCR 121 fpa11->fpcr |= ROUND_EXTENDED; 122#endif 123 break; 124 125 default: floatx80_rounding_precision = 80; 126 } 127} 128 129/* Emulate the instruction in the opcode. */ 130unsigned int EmulateAll(unsigned int opcode) 131{ 132 unsigned int nRc = 0; 133 unsigned long flags; 134 FPA11 *fpa11; 135 save_flags(flags); sti(); 136 137 fpa11 = GET_FPA11(); 138 139 if (fpa11->initflag == 0) /* good place for __builtin_expect */ 140 { 141 resetFPA11(); 142 SetRoundingMode(ROUND_TO_NEAREST); 143 SetRoundingPrecision(ROUND_EXTENDED); 144 fpa11->initflag = 1; 145 } 146 147 if (TEST_OPCODE(opcode,MASK_CPRT)) 148 { 149 /* Emulate conversion opcodes. */ 150 /* Emulate register transfer opcodes. */ 151 /* Emulate comparison opcodes. */ 152 nRc = EmulateCPRT(opcode); 153 } 154 else if (TEST_OPCODE(opcode,MASK_CPDO)) 155 { 156 /* Emulate monadic arithmetic opcodes. */ 157 /* Emulate dyadic arithmetic opcodes. */ 158 nRc = EmulateCPDO(opcode); 159 } 160 else if (TEST_OPCODE(opcode,MASK_CPDT)) 161 { 162 /* Emulate load/store opcodes. */ 163 /* Emulate load/store multiple opcodes. */ 164 nRc = EmulateCPDT(opcode); 165 } 166 else 167 { 168 /* Invalid instruction detected. Return FALSE. */ 169 nRc = 0; 170 } 171 172 restore_flags(flags); 173 174 return(nRc); 175} 176 177 178