1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 NetWinder Floating Point Emulator 4 (c) Rebel.COM, 1998,1999 5 (c) Philip Blundell, 2001 6 7 Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 8 9 */ 10 11 #include "fpa11.h" 12 #include "fpopcode.h" 13 14 #include "fpmodule.h" 15 #include "fpmodule.inl" 16 17 #include <linux/compiler.h> 18 #include <linux/string.h> 19 20 /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ 21 static void resetFPA11(void) 22 { 23 int i; 24 FPA11 *fpa11 = GET_FPA11(); 25 26 /* initialize the register type array */ 27 for (i = 0; i <= 7; i++) { 28 fpa11->fType[i] = typeNone; 29 } 30 31 /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 32 fpa11->fpsr = FP_EMULATOR | BIT_AC; 33 } 34 35 int8 SetRoundingMode(const unsigned int opcode) 36 { 37 switch (opcode & MASK_ROUNDING_MODE) { 38 default: 39 case ROUND_TO_NEAREST: 40 return float_round_nearest_even; 41 42 case ROUND_TO_PLUS_INFINITY: 43 return float_round_up; 44 45 case ROUND_TO_MINUS_INFINITY: 46 return float_round_down; 47 48 case ROUND_TO_ZERO: 49 return float_round_to_zero; 50 } 51 } 52 53 int8 SetRoundingPrecision(const unsigned int opcode) 54 { 55 #ifdef CONFIG_FPE_NWFPE_XP 56 switch (opcode & MASK_ROUNDING_PRECISION) { 57 case ROUND_SINGLE: 58 return 32; 59 60 case ROUND_DOUBLE: 61 return 64; 62 63 case ROUND_EXTENDED: 64 return 80; 65 66 default: 67 return 80; 68 } 69 #endif 70 return 80; 71 } 72 73 void nwfpe_init_fpa(union fp_state *fp) 74 { 75 FPA11 *fpa11 = (FPA11 *)fp; 76 #ifdef NWFPE_DEBUG 77 printk("NWFPE: setting up state.\n"); 78 #endif 79 memset(fpa11, 0, sizeof(FPA11)); 80 resetFPA11(); 81 fpa11->initflag = 1; 82 } 83 84 /* Emulate the instruction in the opcode. */ 85 unsigned int EmulateAll(unsigned int opcode) 86 { 87 unsigned int code; 88 89 #ifdef NWFPE_DEBUG 90 printk("NWFPE: emulating opcode %08x\n", opcode); 91 #endif 92 code = opcode & 0x00000f00; 93 if (code == 0x00000100 || code == 0x00000200) { 94 /* For coprocessor 1 or 2 (FPA11) */ 95 code = opcode & 0x0e000000; 96 if (code == 0x0e000000) { 97 if (opcode & 0x00000010) { 98 /* Emulate conversion opcodes. */ 99 /* Emulate register transfer opcodes. */ 100 /* Emulate comparison opcodes. */ 101 return EmulateCPRT(opcode); 102 } else { 103 /* Emulate monadic arithmetic opcodes. */ 104 /* Emulate dyadic arithmetic opcodes. */ 105 return EmulateCPDO(opcode); 106 } 107 } else if (code == 0x0c000000) { 108 /* Emulate load/store opcodes. */ 109 /* Emulate load/store multiple opcodes. */ 110 return EmulateCPDT(opcode); 111 } 112 } 113 114 /* Invalid instruction detected. Return FALSE. */ 115 return 0; 116 } 117