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. */ 21static 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 35int8 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 53int8 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 73void 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. */ 85unsigned 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