^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*---------------------------------------------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) | errors.c |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) | The error handling functions for wm-FPU-emu |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) | Copyright (C) 1992,1993,1994,1996 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) | E-mail billm@jacobi.maths.monash.edu.au |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) | |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) +---------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /*---------------------------------------------------------------------------+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) | Note: |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) | The file contains code which accesses user memory. |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) | Emulator static data may change when user memory is accessed, due to |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) | other processes using the emulator while swapping is in progress. |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) +---------------------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "fpu_emu.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "fpu_system.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "exception.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "status_w.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include "control_w.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "reg_constant.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include "version.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) /* */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #undef PRINT_MESSAGES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) /* */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) void Un_impl(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) u_char byte1, FPU_modrm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) unsigned long address = FPU_ORIG_EIP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) RE_ENTRANT_CHECK_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* No need to check access_ok(), we have previously fetched these bytes. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) if (FPU_CS == __USER_CS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) FPU_get_user(byte1, (u_char __user *) address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if ((byte1 & 0xf8) == 0xd8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) printk("[%02x]", byte1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) address++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) printk("%02x ", byte1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (FPU_modrm >= 0300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) FPU_modrm & 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) printk("/%d\n", (FPU_modrm >> 3) & 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) printk("cs selector = %04x\n", FPU_CS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) RE_ENTRANT_CHECK_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #endif /* 0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) Called for opcodes which are illegal and which are known to result in a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) SIGILL with a real 80486.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) void FPU_illegal(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) math_abort(FPU_info, SIGILL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) void FPU_printall(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) "DeNorm", "Inf", "NaN"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) u_char byte1, FPU_modrm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) unsigned long address = FPU_ORIG_EIP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) RE_ENTRANT_CHECK_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) /* No need to check access_ok(), we have previously fetched these bytes. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) printk("At %p:", (void *)address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (FPU_CS == __USER_CS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) #define MAX_PRINTED_BYTES 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) for (i = 0; i < MAX_PRINTED_BYTES; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) FPU_get_user(byte1, (u_char __user *) address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) if ((byte1 & 0xf8) == 0xd8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) printk(" %02x", byte1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) printk(" [%02x]", byte1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) address++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (i == MAX_PRINTED_BYTES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) printk(" [more..]\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) FPU_get_user(FPU_modrm, 1 + (u_char __user *) address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) if (FPU_modrm >= 0300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) printk(" %02x (%02x+%d)\n", FPU_modrm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) FPU_modrm & 0xf8, FPU_modrm & 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) printk(" /%d, mod=%d rm=%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) (FPU_modrm >> 3) & 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) (FPU_modrm >> 6) & 3, FPU_modrm & 7);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) printk("%04x\n", FPU_CS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) partial_status = status_word();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) #ifdef DEBUGGING
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (partial_status & SW_Backward)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) printk("SW: backward compatibility\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) if (partial_status & SW_C3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) printk("SW: condition bit 3\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (partial_status & SW_C2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) printk("SW: condition bit 2\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (partial_status & SW_C1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) printk("SW: condition bit 1\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) if (partial_status & SW_C0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) printk("SW: condition bit 0\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (partial_status & SW_Summary)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) printk("SW: exception summary\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (partial_status & SW_Stack_Fault)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) printk("SW: stack fault\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if (partial_status & SW_Precision)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) printk("SW: loss of precision\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (partial_status & SW_Underflow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) printk("SW: underflow\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (partial_status & SW_Overflow)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) printk("SW: overflow\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (partial_status & SW_Zero_Div)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) printk("SW: divide by zero\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) if (partial_status & SW_Denorm_Op)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) printk("SW: denormalized operand\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (partial_status & SW_Invalid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) printk("SW: invalid operation\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) #endif /* DEBUGGING */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) printk(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", partial_status & 0x8000 ? 1 : 0, /* busy */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) (partial_status & 0x3800) >> 11, /* stack top pointer */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) partial_status & 0x80 ? 1 : 0, /* Error summary status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) partial_status & 0x40 ? 1 : 0, /* Stack flag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0, /* cc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0, /* cc */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) partial_status & SW_Precision ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) partial_status & SW_Underflow ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) partial_status & SW_Overflow ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) partial_status & SW_Zero_Div ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) partial_status & SW_Denorm_Op ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) partial_status & SW_Invalid ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) control_word & 0x1000 ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) control_word & 0x80 ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) control_word & SW_Precision ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) control_word & SW_Underflow ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) control_word & SW_Overflow ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) control_word & SW_Zero_Div ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) control_word & SW_Denorm_Op ? 1 : 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) control_word & SW_Invalid ? 1 : 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) for (i = 0; i < 8; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) FPU_REG *r = &st(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) u_char tagi = FPU_gettagi(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) switch (tagi) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) case TAG_Empty:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) case TAG_Zero:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) case TAG_Special:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) /* Update tagi for the printk below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) tagi = FPU_Special(r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) case TAG_Valid:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) getsign(r) ? '-' : '+',
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) (long)(r->sigh >> 16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) (long)(r->sigh & 0xFFFF),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) (long)(r->sigl >> 16),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) (long)(r->sigl & 0xFFFF),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) exponent(r) - EXP_BIAS + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) printk("Whoops! Error in errors.c: tag%d is %d ", i,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) tagi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) printk("%s\n", tag_desc[(int)(unsigned)tagi]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) RE_ENTRANT_CHECK_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) static struct {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) int type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) } exception_names[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) EX_StackOver, "stack overflow"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) EX_StackUnder, "stack underflow"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) EX_Precision, "loss of precision"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) EX_Underflow, "underflow"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) EX_Overflow, "overflow"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) EX_ZeroDiv, "divide by zero"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) EX_Denormal, "denormalized operand"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) EX_Invalid, "invalid operation"}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 0, NULL}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) EX_INTERNAL is always given with a code which indicates where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) error was detected.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) Internal error types:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 0x14 in fpu_etc.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 0x1nn in a *.c file:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 0x101 in reg_add_sub.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 0x102 in reg_mul.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 0x104 in poly_atan.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 0x105 in reg_mul.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 0x107 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 0x108 in reg_compare.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 0x109 in reg_compare.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 0x110 in reg_add_sub.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 0x111 in fpe_entry.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 0x112 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 0x113 in errors.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 0x115 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 0x116 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 0x117 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 0x118 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 0x119 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 0x120 in poly_atan.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 0x121 in reg_compare.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 0x122 in reg_compare.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 0x123 in reg_compare.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 0x125 in fpu_trig.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 0x126 in fpu_entry.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 0x127 in poly_2xm1.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 0x128 in fpu_entry.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 0x129 in fpu_entry.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 0x130 in get_address.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 0x131 in get_address.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 0x132 in get_address.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 0x133 in get_address.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 0x140 in load_store.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 0x141 in load_store.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 0x150 in poly_sin.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 0x151 in poly_sin.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 0x160 in reg_ld_str.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 0x161 in reg_ld_str.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 0x162 in reg_ld_str.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 0x163 in reg_ld_str.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 0x164 in reg_ld_str.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 0x170 in fpu_tags.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 0x171 in fpu_tags.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 0x172 in fpu_tags.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 0x180 in reg_convert.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 0x2nn in an *.S file:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 0x201 in reg_u_add.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 0x202 in reg_u_div.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 0x203 in reg_u_div.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 0x204 in reg_u_div.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 0x205 in reg_u_mul.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 0x206 in reg_u_sub.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 0x207 in wm_sqrt.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 0x208 in reg_div.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 0x209 in reg_u_sub.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 0x210 in reg_u_sub.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 0x211 in reg_u_sub.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 0x212 in reg_u_sub.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 0x213 in wm_sqrt.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 0x214 in wm_sqrt.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 0x215 in wm_sqrt.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 0x220 in reg_norm.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 0x221 in reg_norm.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 0x230 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 0x231 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 0x232 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 0x233 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 0x234 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 0x235 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 0x236 in reg_round.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 0x240 in div_Xsig.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 0x241 in div_Xsig.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 0x242 in div_Xsig.S
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) asmlinkage __visible void FPU_exception(int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int i, int_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) int_type = 0; /* Needed only to stop compiler warnings */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (n & EX_INTERNAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) int_type = n - EX_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) n = EX_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) /* Set lots of exception bits! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) /* Extract only the bits which we use to set the status word */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) n &= (SW_Exc_Mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) /* Set the corresponding exception bit */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) partial_status |= n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) /* Set summary bits iff exception isn't masked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (partial_status & ~control_word & CW_Exceptions)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) partial_status |= (SW_Summary | SW_Backward);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (n & (SW_Stack_Fault | EX_Precision)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) if (!(n & SW_C1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) /* This bit distinguishes over- from underflow for a stack fault,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) and roundup from round-down for precision loss. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) partial_status &= ~SW_C1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) RE_ENTRANT_CHECK_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) /* Get a name string for error reporting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) for (i = 0; exception_names[i].type; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) if ((exception_names[i].type & n) ==
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) exception_names[i].type)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) if (exception_names[i].type) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) #ifdef PRINT_MESSAGES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) printk("FP Exception: %s!\n", exception_names[i].name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) #endif /* PRINT_MESSAGES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) printk("FPU emulator: Unknown Exception: 0x%04x!\n", n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (n == EX_INTERNAL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) printk("FPU emulator: Internal error type 0x%04x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) int_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) FPU_printall();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) #ifdef PRINT_MESSAGES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) FPU_printall();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) #endif /* PRINT_MESSAGES */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) * The 80486 generates an interrupt on the next non-control FPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) * instruction. So we need some means of flagging it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) * We use the ES (Error Summary) bit for this.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) RE_ENTRANT_CHECK_ON;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) #ifdef __DEBUG__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) math_abort(FPU_info, SIGFPE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) #endif /* __DEBUG__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) /* Real operation attempted on a NaN. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* Returns < 0 if the exception is unmasked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) int real_1op_NaN(FPU_REG *a)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) int signalling, isNaN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) /* The default result for the case of two "equal" NaNs (signs may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) differ) is chosen to reproduce 80486 behaviour */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) signalling = isNaN && !(a->sigh & 0x40000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (!signalling) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (!isNaN) { /* pseudo-NaN, or other unsupported? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) /* Masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) reg_copy(&CONST_QNaN, a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return (!(control_word & CW_Invalid) ? FPU_Exception :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) 0) | TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) return TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) if (!(a->sigh & 0x80000000)) { /* pseudo-NaN ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) reg_copy(&CONST_QNaN, a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* ensure a Quiet NaN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) a->sigh |= 0x40000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) /* Real operation attempted on two operands, one a NaN. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) /* Returns < 0 if the exception is unmasked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) int real_2op_NaN(FPU_REG const *b, u_char tagb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) int deststnr, FPU_REG const *defaultNaN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) FPU_REG *dest = &st(deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) FPU_REG const *a = dest;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) u_char taga = FPU_gettagi(deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) FPU_REG const *x;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) int signalling, unsupported;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (taga == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) taga = FPU_Special(a);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (tagb == TAG_Special)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) tagb = FPU_Special(b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) /* TW_NaN is also used for unsupported data types. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) unsupported = ((taga == TW_NaN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) && !((exponent(a) == EXP_OVER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) && (a->sigh & 0x80000000)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) || ((tagb == TW_NaN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (unsupported) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) /* Masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) return (!(control_word & CW_Invalid) ? FPU_Exception : 0) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) if (taga == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) x = a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (tagb == TW_NaN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) signalling = !(a->sigh & b->sigh & 0x40000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if (significand(b) > significand(a))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) x = b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) else if (significand(b) == significand(a)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) /* The default result for the case of two "equal" NaNs (signs may
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) differ) is chosen to reproduce 80486 behaviour */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) x = defaultNaN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) /* return the quiet version of the NaN in a */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) signalling = !(a->sigh & 0x40000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (tagb == TW_NaN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) signalling = !(b->sigh & 0x40000000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) x = b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) #ifdef PARANOID
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) signalling = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) EXCEPTION(EX_INTERNAL | 0x113);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) x = &CONST_QNaN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) #endif /* PARANOID */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) if ((!signalling) || (control_word & CW_Invalid)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (!x)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) x = b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) x = &CONST_QNaN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) FPU_copy_to_regi(x, TAG_Special, deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) if (!signalling)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) return TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) /* ensure a Quiet NaN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) dest->sigh |= 0x40000000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* Invalid arith operation on Valid registers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) /* Returns < 0 if the exception is unmasked */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) asmlinkage __visible int arith_invalid(int deststnr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) EXCEPTION(EX_Invalid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) /* Divide a finite number by zero */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) asmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) FPU_REG *dest = &st(deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) int tag = TAG_Valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) if (control_word & CW_ZeroDiv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) setsign(dest, sign);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) tag = TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) EXCEPTION(EX_ZeroDiv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) /* This may be called often, so keep it lean */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) int set_precision_flag(int flags)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) if (control_word & CW_Precision) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) partial_status &= ~(SW_C1 & flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) partial_status |= flags; /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) EXCEPTION(flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) /* This may be called often, so keep it lean */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) asmlinkage __visible void set_precision_flag_up(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (control_word & CW_Precision)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) partial_status |= (SW_Precision | SW_C1); /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) EXCEPTION(EX_Precision | SW_C1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) /* This may be called often, so keep it lean */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) asmlinkage __visible void set_precision_flag_down(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) if (control_word & CW_Precision) { /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) partial_status &= ~SW_C1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) partial_status |= SW_Precision;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) EXCEPTION(EX_Precision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) asmlinkage __visible int denormal_operand(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) if (control_word & CW_Denormal) { /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) partial_status |= SW_Denorm_Op;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) EXCEPTION(EX_Denormal);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) return TAG_Special | FPU_Exception;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) asmlinkage __visible int arith_overflow(FPU_REG *dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) int tag = TAG_Valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (control_word & CW_Overflow) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) /* ###### The response here depends upon the rounding mode */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) reg_copy(&CONST_INF, dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) tag = TAG_Special;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) /* Subtract the magic number from the exponent */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) addexponent(dest, (-3 * (1 << 13)));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) EXCEPTION(EX_Overflow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) if (control_word & CW_Overflow) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) /* The overflow exception is masked. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) /* By definition, precision is lost.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) The roundup bit (C1) is also set because we have
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) "rounded" upwards to Infinity. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) EXCEPTION(EX_Precision | SW_C1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) return tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) return tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) asmlinkage __visible int arith_underflow(FPU_REG *dest)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) int tag = TAG_Valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) if (control_word & CW_Underflow) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) if (exponent16(dest) <= EXP_UNDER - 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) reg_copy(&CONST_Z, dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) partial_status &= ~SW_C1; /* Round down. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) tag = TAG_Zero;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) stdexp(dest);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* Add the magic number to the exponent. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) EXCEPTION(EX_Underflow);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) if (control_word & CW_Underflow) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) /* The underflow exception is masked. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) EXCEPTION(EX_Precision);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) return tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) return tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) void FPU_stack_overflow(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) top--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) EXCEPTION(EX_StackOver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) void FPU_stack_underflow(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) FPU_copy_to_reg0(&CONST_QNaN, TAG_Special);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) EXCEPTION(EX_StackUnder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) void FPU_stack_underflow_i(int i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) EXCEPTION(EX_StackUnder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) void FPU_stack_underflow_pop(int i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (control_word & CW_Invalid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) /* The masked response */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) FPU_pop();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) EXCEPTION(EX_StackUnder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) }