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