174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds NetWinder Floating Point Emulator 41da177e4SLinus Torvalds (c) Rebel.COM, 1998,1999 51da177e4SLinus Torvalds (c) Philip Blundell, 2001 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds Direct questions, comments to Scott Bambrough <scottb@netwinder.org> 81da177e4SLinus Torvalds 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include "fpa11.h" 121da177e4SLinus Torvalds #include "fpopcode.h" 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include "fpmodule.h" 151da177e4SLinus Torvalds #include "fpmodule.inl" 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <linux/compiler.h> 181da177e4SLinus Torvalds #include <linux/string.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds /* Reset the FPA11 chip. Called to initialize and reset the emulator. */ resetFPA11(void)211da177e4SLinus Torvaldsstatic void resetFPA11(void) 221da177e4SLinus Torvalds { 231da177e4SLinus Torvalds int i; 241da177e4SLinus Torvalds FPA11 *fpa11 = GET_FPA11(); 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds /* initialize the register type array */ 271da177e4SLinus Torvalds for (i = 0; i <= 7; i++) { 281da177e4SLinus Torvalds fpa11->fType[i] = typeNone; 291da177e4SLinus Torvalds } 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ 321da177e4SLinus Torvalds fpa11->fpsr = FP_EMULATOR | BIT_AC; 331da177e4SLinus Torvalds } 341da177e4SLinus Torvalds SetRoundingMode(const unsigned int opcode)35f148af25SRichard Purdieint8 SetRoundingMode(const unsigned int opcode) 361da177e4SLinus Torvalds { 371da177e4SLinus Torvalds switch (opcode & MASK_ROUNDING_MODE) { 381da177e4SLinus Torvalds default: 391da177e4SLinus Torvalds case ROUND_TO_NEAREST: 40f148af25SRichard Purdie return float_round_nearest_even; 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds case ROUND_TO_PLUS_INFINITY: 43f148af25SRichard Purdie return float_round_up; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds case ROUND_TO_MINUS_INFINITY: 46f148af25SRichard Purdie return float_round_down; 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds case ROUND_TO_ZERO: 49f148af25SRichard Purdie return float_round_to_zero; 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds } 521da177e4SLinus Torvalds SetRoundingPrecision(const unsigned int opcode)53f148af25SRichard Purdieint8 SetRoundingPrecision(const unsigned int opcode) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds #ifdef CONFIG_FPE_NWFPE_XP 561da177e4SLinus Torvalds switch (opcode & MASK_ROUNDING_PRECISION) { 571da177e4SLinus Torvalds case ROUND_SINGLE: 58f148af25SRichard Purdie return 32; 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds case ROUND_DOUBLE: 61f148af25SRichard Purdie return 64; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds case ROUND_EXTENDED: 64f148af25SRichard Purdie return 80; 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds default: 67f148af25SRichard Purdie return 80; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds #endif 70f148af25SRichard Purdie return 80; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds nwfpe_init_fpa(union fp_state * fp)731da177e4SLinus Torvaldsvoid nwfpe_init_fpa(union fp_state *fp) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds FPA11 *fpa11 = (FPA11 *)fp; 761da177e4SLinus Torvalds #ifdef NWFPE_DEBUG 771da177e4SLinus Torvalds printk("NWFPE: setting up state.\n"); 781da177e4SLinus Torvalds #endif 791da177e4SLinus Torvalds memset(fpa11, 0, sizeof(FPA11)); 801da177e4SLinus Torvalds resetFPA11(); 811da177e4SLinus Torvalds fpa11->initflag = 1; 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds /* Emulate the instruction in the opcode. */ EmulateAll(unsigned int opcode)851da177e4SLinus Torvaldsunsigned int EmulateAll(unsigned int opcode) 861da177e4SLinus Torvalds { 871da177e4SLinus Torvalds unsigned int code; 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds #ifdef NWFPE_DEBUG 901da177e4SLinus Torvalds printk("NWFPE: emulating opcode %08x\n", opcode); 911da177e4SLinus Torvalds #endif 921da177e4SLinus Torvalds code = opcode & 0x00000f00; 931da177e4SLinus Torvalds if (code == 0x00000100 || code == 0x00000200) { 941da177e4SLinus Torvalds /* For coprocessor 1 or 2 (FPA11) */ 951da177e4SLinus Torvalds code = opcode & 0x0e000000; 961da177e4SLinus Torvalds if (code == 0x0e000000) { 971da177e4SLinus Torvalds if (opcode & 0x00000010) { 981da177e4SLinus Torvalds /* Emulate conversion opcodes. */ 991da177e4SLinus Torvalds /* Emulate register transfer opcodes. */ 1001da177e4SLinus Torvalds /* Emulate comparison opcodes. */ 1011da177e4SLinus Torvalds return EmulateCPRT(opcode); 1021da177e4SLinus Torvalds } else { 1031da177e4SLinus Torvalds /* Emulate monadic arithmetic opcodes. */ 1041da177e4SLinus Torvalds /* Emulate dyadic arithmetic opcodes. */ 1051da177e4SLinus Torvalds return EmulateCPDO(opcode); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds } else if (code == 0x0c000000) { 1081da177e4SLinus Torvalds /* Emulate load/store opcodes. */ 1091da177e4SLinus Torvalds /* Emulate load/store multiple opcodes. */ 1101da177e4SLinus Torvalds return EmulateCPDT(opcode); 1111da177e4SLinus Torvalds } 1121da177e4SLinus Torvalds } 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds /* Invalid instruction detected. Return FALSE. */ 1151da177e4SLinus Torvalds return 0; 1161da177e4SLinus Torvalds } 117