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