18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------+ 38c2ecf20Sopenharmony_ci | errors.c | 48c2ecf20Sopenharmony_ci | | 58c2ecf20Sopenharmony_ci | The error handling functions for wm-FPU-emu | 68c2ecf20Sopenharmony_ci | | 78c2ecf20Sopenharmony_ci | Copyright (C) 1992,1993,1994,1996 | 88c2ecf20Sopenharmony_ci | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | 98c2ecf20Sopenharmony_ci | E-mail billm@jacobi.maths.monash.edu.au | 108c2ecf20Sopenharmony_ci | | 118c2ecf20Sopenharmony_ci | | 128c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/*---------------------------------------------------------------------------+ 158c2ecf20Sopenharmony_ci | Note: | 168c2ecf20Sopenharmony_ci | The file contains code which accesses user memory. | 178c2ecf20Sopenharmony_ci | Emulator static data may change when user memory is accessed, due to | 188c2ecf20Sopenharmony_ci | other processes using the emulator while swapping is in progress. | 198c2ecf20Sopenharmony_ci +---------------------------------------------------------------------------*/ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/signal.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "fpu_emu.h" 268c2ecf20Sopenharmony_ci#include "fpu_system.h" 278c2ecf20Sopenharmony_ci#include "exception.h" 288c2ecf20Sopenharmony_ci#include "status_w.h" 298c2ecf20Sopenharmony_ci#include "control_w.h" 308c2ecf20Sopenharmony_ci#include "reg_constant.h" 318c2ecf20Sopenharmony_ci#include "version.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* */ 348c2ecf20Sopenharmony_ci#undef PRINT_MESSAGES 358c2ecf20Sopenharmony_ci/* */ 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#if 0 388c2ecf20Sopenharmony_civoid Un_impl(void) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci u_char byte1, FPU_modrm; 418c2ecf20Sopenharmony_ci unsigned long address = FPU_ORIG_EIP; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci RE_ENTRANT_CHECK_OFF; 448c2ecf20Sopenharmony_ci /* No need to check access_ok(), we have previously fetched these bytes. */ 458c2ecf20Sopenharmony_ci printk("Unimplemented FPU Opcode at eip=%p : ", (void __user *)address); 468c2ecf20Sopenharmony_ci if (FPU_CS == __USER_CS) { 478c2ecf20Sopenharmony_ci while (1) { 488c2ecf20Sopenharmony_ci FPU_get_user(byte1, (u_char __user *) address); 498c2ecf20Sopenharmony_ci if ((byte1 & 0xf8) == 0xd8) 508c2ecf20Sopenharmony_ci break; 518c2ecf20Sopenharmony_ci printk("[%02x]", byte1); 528c2ecf20Sopenharmony_ci address++; 538c2ecf20Sopenharmony_ci } 548c2ecf20Sopenharmony_ci printk("%02x ", byte1); 558c2ecf20Sopenharmony_ci FPU_get_user(FPU_modrm, 1 + (u_char __user *) address); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (FPU_modrm >= 0300) 588c2ecf20Sopenharmony_ci printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, 598c2ecf20Sopenharmony_ci FPU_modrm & 7); 608c2ecf20Sopenharmony_ci else 618c2ecf20Sopenharmony_ci printk("/%d\n", (FPU_modrm >> 3) & 7); 628c2ecf20Sopenharmony_ci } else { 638c2ecf20Sopenharmony_ci printk("cs selector = %04x\n", FPU_CS); 648c2ecf20Sopenharmony_ci } 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci RE_ENTRANT_CHECK_ON; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci#endif /* 0 */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* 748c2ecf20Sopenharmony_ci Called for opcodes which are illegal and which are known to result in a 758c2ecf20Sopenharmony_ci SIGILL with a real 80486. 768c2ecf20Sopenharmony_ci */ 778c2ecf20Sopenharmony_civoid FPU_illegal(void) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci math_abort(FPU_info, SIGILL); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_civoid FPU_printall(void) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci int i; 858c2ecf20Sopenharmony_ci static const char *tag_desc[] = { "Valid", "Zero", "ERROR", "Empty", 868c2ecf20Sopenharmony_ci "DeNorm", "Inf", "NaN" 878c2ecf20Sopenharmony_ci }; 888c2ecf20Sopenharmony_ci u_char byte1, FPU_modrm; 898c2ecf20Sopenharmony_ci unsigned long address = FPU_ORIG_EIP; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci RE_ENTRANT_CHECK_OFF; 928c2ecf20Sopenharmony_ci /* No need to check access_ok(), we have previously fetched these bytes. */ 938c2ecf20Sopenharmony_ci printk("At %p:", (void *)address); 948c2ecf20Sopenharmony_ci if (FPU_CS == __USER_CS) { 958c2ecf20Sopenharmony_ci#define MAX_PRINTED_BYTES 20 968c2ecf20Sopenharmony_ci for (i = 0; i < MAX_PRINTED_BYTES; i++) { 978c2ecf20Sopenharmony_ci FPU_get_user(byte1, (u_char __user *) address); 988c2ecf20Sopenharmony_ci if ((byte1 & 0xf8) == 0xd8) { 998c2ecf20Sopenharmony_ci printk(" %02x", byte1); 1008c2ecf20Sopenharmony_ci break; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci printk(" [%02x]", byte1); 1038c2ecf20Sopenharmony_ci address++; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci if (i == MAX_PRINTED_BYTES) 1068c2ecf20Sopenharmony_ci printk(" [more..]\n"); 1078c2ecf20Sopenharmony_ci else { 1088c2ecf20Sopenharmony_ci FPU_get_user(FPU_modrm, 1 + (u_char __user *) address); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci if (FPU_modrm >= 0300) 1118c2ecf20Sopenharmony_ci printk(" %02x (%02x+%d)\n", FPU_modrm, 1128c2ecf20Sopenharmony_ci FPU_modrm & 0xf8, FPU_modrm & 7); 1138c2ecf20Sopenharmony_ci else 1148c2ecf20Sopenharmony_ci printk(" /%d, mod=%d rm=%d\n", 1158c2ecf20Sopenharmony_ci (FPU_modrm >> 3) & 7, 1168c2ecf20Sopenharmony_ci (FPU_modrm >> 6) & 3, FPU_modrm & 7); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci } else { 1198c2ecf20Sopenharmony_ci printk("%04x\n", FPU_CS); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci partial_status = status_word(); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#ifdef DEBUGGING 1258c2ecf20Sopenharmony_ci if (partial_status & SW_Backward) 1268c2ecf20Sopenharmony_ci printk("SW: backward compatibility\n"); 1278c2ecf20Sopenharmony_ci if (partial_status & SW_C3) 1288c2ecf20Sopenharmony_ci printk("SW: condition bit 3\n"); 1298c2ecf20Sopenharmony_ci if (partial_status & SW_C2) 1308c2ecf20Sopenharmony_ci printk("SW: condition bit 2\n"); 1318c2ecf20Sopenharmony_ci if (partial_status & SW_C1) 1328c2ecf20Sopenharmony_ci printk("SW: condition bit 1\n"); 1338c2ecf20Sopenharmony_ci if (partial_status & SW_C0) 1348c2ecf20Sopenharmony_ci printk("SW: condition bit 0\n"); 1358c2ecf20Sopenharmony_ci if (partial_status & SW_Summary) 1368c2ecf20Sopenharmony_ci printk("SW: exception summary\n"); 1378c2ecf20Sopenharmony_ci if (partial_status & SW_Stack_Fault) 1388c2ecf20Sopenharmony_ci printk("SW: stack fault\n"); 1398c2ecf20Sopenharmony_ci if (partial_status & SW_Precision) 1408c2ecf20Sopenharmony_ci printk("SW: loss of precision\n"); 1418c2ecf20Sopenharmony_ci if (partial_status & SW_Underflow) 1428c2ecf20Sopenharmony_ci printk("SW: underflow\n"); 1438c2ecf20Sopenharmony_ci if (partial_status & SW_Overflow) 1448c2ecf20Sopenharmony_ci printk("SW: overflow\n"); 1458c2ecf20Sopenharmony_ci if (partial_status & SW_Zero_Div) 1468c2ecf20Sopenharmony_ci printk("SW: divide by zero\n"); 1478c2ecf20Sopenharmony_ci if (partial_status & SW_Denorm_Op) 1488c2ecf20Sopenharmony_ci printk("SW: denormalized operand\n"); 1498c2ecf20Sopenharmony_ci if (partial_status & SW_Invalid) 1508c2ecf20Sopenharmony_ci printk("SW: invalid operation\n"); 1518c2ecf20Sopenharmony_ci#endif /* DEBUGGING */ 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 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 */ 1548c2ecf20Sopenharmony_ci (partial_status & 0x3800) >> 11, /* stack top pointer */ 1558c2ecf20Sopenharmony_ci partial_status & 0x80 ? 1 : 0, /* Error summary status */ 1568c2ecf20Sopenharmony_ci partial_status & 0x40 ? 1 : 0, /* Stack flag */ 1578c2ecf20Sopenharmony_ci partial_status & SW_C3 ? 1 : 0, partial_status & SW_C2 ? 1 : 0, /* cc */ 1588c2ecf20Sopenharmony_ci partial_status & SW_C1 ? 1 : 0, partial_status & SW_C0 ? 1 : 0, /* cc */ 1598c2ecf20Sopenharmony_ci partial_status & SW_Precision ? 1 : 0, 1608c2ecf20Sopenharmony_ci partial_status & SW_Underflow ? 1 : 0, 1618c2ecf20Sopenharmony_ci partial_status & SW_Overflow ? 1 : 0, 1628c2ecf20Sopenharmony_ci partial_status & SW_Zero_Div ? 1 : 0, 1638c2ecf20Sopenharmony_ci partial_status & SW_Denorm_Op ? 1 : 0, 1648c2ecf20Sopenharmony_ci partial_status & SW_Invalid ? 1 : 0); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci printk(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n", 1678c2ecf20Sopenharmony_ci control_word & 0x1000 ? 1 : 0, 1688c2ecf20Sopenharmony_ci (control_word & 0x800) >> 11, (control_word & 0x400) >> 10, 1698c2ecf20Sopenharmony_ci (control_word & 0x200) >> 9, (control_word & 0x100) >> 8, 1708c2ecf20Sopenharmony_ci control_word & 0x80 ? 1 : 0, 1718c2ecf20Sopenharmony_ci control_word & SW_Precision ? 1 : 0, 1728c2ecf20Sopenharmony_ci control_word & SW_Underflow ? 1 : 0, 1738c2ecf20Sopenharmony_ci control_word & SW_Overflow ? 1 : 0, 1748c2ecf20Sopenharmony_ci control_word & SW_Zero_Div ? 1 : 0, 1758c2ecf20Sopenharmony_ci control_word & SW_Denorm_Op ? 1 : 0, 1768c2ecf20Sopenharmony_ci control_word & SW_Invalid ? 1 : 0); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 1798c2ecf20Sopenharmony_ci FPU_REG *r = &st(i); 1808c2ecf20Sopenharmony_ci u_char tagi = FPU_gettagi(i); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci switch (tagi) { 1838c2ecf20Sopenharmony_ci case TAG_Empty: 1848c2ecf20Sopenharmony_ci continue; 1858c2ecf20Sopenharmony_ci case TAG_Zero: 1868c2ecf20Sopenharmony_ci case TAG_Special: 1878c2ecf20Sopenharmony_ci /* Update tagi for the printk below */ 1888c2ecf20Sopenharmony_ci tagi = FPU_Special(r); 1898c2ecf20Sopenharmony_ci fallthrough; 1908c2ecf20Sopenharmony_ci case TAG_Valid: 1918c2ecf20Sopenharmony_ci printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6d ", i, 1928c2ecf20Sopenharmony_ci getsign(r) ? '-' : '+', 1938c2ecf20Sopenharmony_ci (long)(r->sigh >> 16), 1948c2ecf20Sopenharmony_ci (long)(r->sigh & 0xFFFF), 1958c2ecf20Sopenharmony_ci (long)(r->sigl >> 16), 1968c2ecf20Sopenharmony_ci (long)(r->sigl & 0xFFFF), 1978c2ecf20Sopenharmony_ci exponent(r) - EXP_BIAS + 1); 1988c2ecf20Sopenharmony_ci break; 1998c2ecf20Sopenharmony_ci default: 2008c2ecf20Sopenharmony_ci printk("Whoops! Error in errors.c: tag%d is %d ", i, 2018c2ecf20Sopenharmony_ci tagi); 2028c2ecf20Sopenharmony_ci continue; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci printk("%s\n", tag_desc[(int)(unsigned)tagi]); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci RE_ENTRANT_CHECK_ON; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic struct { 2128c2ecf20Sopenharmony_ci int type; 2138c2ecf20Sopenharmony_ci const char *name; 2148c2ecf20Sopenharmony_ci} exception_names[] = { 2158c2ecf20Sopenharmony_ci { 2168c2ecf20Sopenharmony_ci EX_StackOver, "stack overflow"}, { 2178c2ecf20Sopenharmony_ci EX_StackUnder, "stack underflow"}, { 2188c2ecf20Sopenharmony_ci EX_Precision, "loss of precision"}, { 2198c2ecf20Sopenharmony_ci EX_Underflow, "underflow"}, { 2208c2ecf20Sopenharmony_ci EX_Overflow, "overflow"}, { 2218c2ecf20Sopenharmony_ci EX_ZeroDiv, "divide by zero"}, { 2228c2ecf20Sopenharmony_ci EX_Denormal, "denormalized operand"}, { 2238c2ecf20Sopenharmony_ci EX_Invalid, "invalid operation"}, { 2248c2ecf20Sopenharmony_ci EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION}, { 2258c2ecf20Sopenharmony_ci 0, NULL} 2268c2ecf20Sopenharmony_ci}; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* 2298c2ecf20Sopenharmony_ci EX_INTERNAL is always given with a code which indicates where the 2308c2ecf20Sopenharmony_ci error was detected. 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci Internal error types: 2338c2ecf20Sopenharmony_ci 0x14 in fpu_etc.c 2348c2ecf20Sopenharmony_ci 0x1nn in a *.c file: 2358c2ecf20Sopenharmony_ci 0x101 in reg_add_sub.c 2368c2ecf20Sopenharmony_ci 0x102 in reg_mul.c 2378c2ecf20Sopenharmony_ci 0x104 in poly_atan.c 2388c2ecf20Sopenharmony_ci 0x105 in reg_mul.c 2398c2ecf20Sopenharmony_ci 0x107 in fpu_trig.c 2408c2ecf20Sopenharmony_ci 0x108 in reg_compare.c 2418c2ecf20Sopenharmony_ci 0x109 in reg_compare.c 2428c2ecf20Sopenharmony_ci 0x110 in reg_add_sub.c 2438c2ecf20Sopenharmony_ci 0x111 in fpe_entry.c 2448c2ecf20Sopenharmony_ci 0x112 in fpu_trig.c 2458c2ecf20Sopenharmony_ci 0x113 in errors.c 2468c2ecf20Sopenharmony_ci 0x115 in fpu_trig.c 2478c2ecf20Sopenharmony_ci 0x116 in fpu_trig.c 2488c2ecf20Sopenharmony_ci 0x117 in fpu_trig.c 2498c2ecf20Sopenharmony_ci 0x118 in fpu_trig.c 2508c2ecf20Sopenharmony_ci 0x119 in fpu_trig.c 2518c2ecf20Sopenharmony_ci 0x120 in poly_atan.c 2528c2ecf20Sopenharmony_ci 0x121 in reg_compare.c 2538c2ecf20Sopenharmony_ci 0x122 in reg_compare.c 2548c2ecf20Sopenharmony_ci 0x123 in reg_compare.c 2558c2ecf20Sopenharmony_ci 0x125 in fpu_trig.c 2568c2ecf20Sopenharmony_ci 0x126 in fpu_entry.c 2578c2ecf20Sopenharmony_ci 0x127 in poly_2xm1.c 2588c2ecf20Sopenharmony_ci 0x128 in fpu_entry.c 2598c2ecf20Sopenharmony_ci 0x129 in fpu_entry.c 2608c2ecf20Sopenharmony_ci 0x130 in get_address.c 2618c2ecf20Sopenharmony_ci 0x131 in get_address.c 2628c2ecf20Sopenharmony_ci 0x132 in get_address.c 2638c2ecf20Sopenharmony_ci 0x133 in get_address.c 2648c2ecf20Sopenharmony_ci 0x140 in load_store.c 2658c2ecf20Sopenharmony_ci 0x141 in load_store.c 2668c2ecf20Sopenharmony_ci 0x150 in poly_sin.c 2678c2ecf20Sopenharmony_ci 0x151 in poly_sin.c 2688c2ecf20Sopenharmony_ci 0x160 in reg_ld_str.c 2698c2ecf20Sopenharmony_ci 0x161 in reg_ld_str.c 2708c2ecf20Sopenharmony_ci 0x162 in reg_ld_str.c 2718c2ecf20Sopenharmony_ci 0x163 in reg_ld_str.c 2728c2ecf20Sopenharmony_ci 0x164 in reg_ld_str.c 2738c2ecf20Sopenharmony_ci 0x170 in fpu_tags.c 2748c2ecf20Sopenharmony_ci 0x171 in fpu_tags.c 2758c2ecf20Sopenharmony_ci 0x172 in fpu_tags.c 2768c2ecf20Sopenharmony_ci 0x180 in reg_convert.c 2778c2ecf20Sopenharmony_ci 0x2nn in an *.S file: 2788c2ecf20Sopenharmony_ci 0x201 in reg_u_add.S 2798c2ecf20Sopenharmony_ci 0x202 in reg_u_div.S 2808c2ecf20Sopenharmony_ci 0x203 in reg_u_div.S 2818c2ecf20Sopenharmony_ci 0x204 in reg_u_div.S 2828c2ecf20Sopenharmony_ci 0x205 in reg_u_mul.S 2838c2ecf20Sopenharmony_ci 0x206 in reg_u_sub.S 2848c2ecf20Sopenharmony_ci 0x207 in wm_sqrt.S 2858c2ecf20Sopenharmony_ci 0x208 in reg_div.S 2868c2ecf20Sopenharmony_ci 0x209 in reg_u_sub.S 2878c2ecf20Sopenharmony_ci 0x210 in reg_u_sub.S 2888c2ecf20Sopenharmony_ci 0x211 in reg_u_sub.S 2898c2ecf20Sopenharmony_ci 0x212 in reg_u_sub.S 2908c2ecf20Sopenharmony_ci 0x213 in wm_sqrt.S 2918c2ecf20Sopenharmony_ci 0x214 in wm_sqrt.S 2928c2ecf20Sopenharmony_ci 0x215 in wm_sqrt.S 2938c2ecf20Sopenharmony_ci 0x220 in reg_norm.S 2948c2ecf20Sopenharmony_ci 0x221 in reg_norm.S 2958c2ecf20Sopenharmony_ci 0x230 in reg_round.S 2968c2ecf20Sopenharmony_ci 0x231 in reg_round.S 2978c2ecf20Sopenharmony_ci 0x232 in reg_round.S 2988c2ecf20Sopenharmony_ci 0x233 in reg_round.S 2998c2ecf20Sopenharmony_ci 0x234 in reg_round.S 3008c2ecf20Sopenharmony_ci 0x235 in reg_round.S 3018c2ecf20Sopenharmony_ci 0x236 in reg_round.S 3028c2ecf20Sopenharmony_ci 0x240 in div_Xsig.S 3038c2ecf20Sopenharmony_ci 0x241 in div_Xsig.S 3048c2ecf20Sopenharmony_ci 0x242 in div_Xsig.S 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ciasmlinkage __visible void FPU_exception(int n) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int i, int_type; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci int_type = 0; /* Needed only to stop compiler warnings */ 3128c2ecf20Sopenharmony_ci if (n & EX_INTERNAL) { 3138c2ecf20Sopenharmony_ci int_type = n - EX_INTERNAL; 3148c2ecf20Sopenharmony_ci n = EX_INTERNAL; 3158c2ecf20Sopenharmony_ci /* Set lots of exception bits! */ 3168c2ecf20Sopenharmony_ci partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward); 3178c2ecf20Sopenharmony_ci } else { 3188c2ecf20Sopenharmony_ci /* Extract only the bits which we use to set the status word */ 3198c2ecf20Sopenharmony_ci n &= (SW_Exc_Mask); 3208c2ecf20Sopenharmony_ci /* Set the corresponding exception bit */ 3218c2ecf20Sopenharmony_ci partial_status |= n; 3228c2ecf20Sopenharmony_ci /* Set summary bits iff exception isn't masked */ 3238c2ecf20Sopenharmony_ci if (partial_status & ~control_word & CW_Exceptions) 3248c2ecf20Sopenharmony_ci partial_status |= (SW_Summary | SW_Backward); 3258c2ecf20Sopenharmony_ci if (n & (SW_Stack_Fault | EX_Precision)) { 3268c2ecf20Sopenharmony_ci if (!(n & SW_C1)) 3278c2ecf20Sopenharmony_ci /* This bit distinguishes over- from underflow for a stack fault, 3288c2ecf20Sopenharmony_ci and roundup from round-down for precision loss. */ 3298c2ecf20Sopenharmony_ci partial_status &= ~SW_C1; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci RE_ENTRANT_CHECK_OFF; 3348c2ecf20Sopenharmony_ci if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) { 3358c2ecf20Sopenharmony_ci /* Get a name string for error reporting */ 3368c2ecf20Sopenharmony_ci for (i = 0; exception_names[i].type; i++) 3378c2ecf20Sopenharmony_ci if ((exception_names[i].type & n) == 3388c2ecf20Sopenharmony_ci exception_names[i].type) 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (exception_names[i].type) { 3428c2ecf20Sopenharmony_ci#ifdef PRINT_MESSAGES 3438c2ecf20Sopenharmony_ci printk("FP Exception: %s!\n", exception_names[i].name); 3448c2ecf20Sopenharmony_ci#endif /* PRINT_MESSAGES */ 3458c2ecf20Sopenharmony_ci } else 3468c2ecf20Sopenharmony_ci printk("FPU emulator: Unknown Exception: 0x%04x!\n", n); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (n == EX_INTERNAL) { 3498c2ecf20Sopenharmony_ci printk("FPU emulator: Internal error type 0x%04x\n", 3508c2ecf20Sopenharmony_ci int_type); 3518c2ecf20Sopenharmony_ci FPU_printall(); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci#ifdef PRINT_MESSAGES 3548c2ecf20Sopenharmony_ci else 3558c2ecf20Sopenharmony_ci FPU_printall(); 3568c2ecf20Sopenharmony_ci#endif /* PRINT_MESSAGES */ 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* 3598c2ecf20Sopenharmony_ci * The 80486 generates an interrupt on the next non-control FPU 3608c2ecf20Sopenharmony_ci * instruction. So we need some means of flagging it. 3618c2ecf20Sopenharmony_ci * We use the ES (Error Summary) bit for this. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci RE_ENTRANT_CHECK_ON; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci#ifdef __DEBUG__ 3678c2ecf20Sopenharmony_ci math_abort(FPU_info, SIGFPE); 3688c2ecf20Sopenharmony_ci#endif /* __DEBUG__ */ 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* Real operation attempted on a NaN. */ 3738c2ecf20Sopenharmony_ci/* Returns < 0 if the exception is unmasked */ 3748c2ecf20Sopenharmony_ciint real_1op_NaN(FPU_REG *a) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci int signalling, isNaN; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci isNaN = (exponent(a) == EXP_OVER) && (a->sigh & 0x80000000); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* The default result for the case of two "equal" NaNs (signs may 3818c2ecf20Sopenharmony_ci differ) is chosen to reproduce 80486 behaviour */ 3828c2ecf20Sopenharmony_ci signalling = isNaN && !(a->sigh & 0x40000000); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!signalling) { 3858c2ecf20Sopenharmony_ci if (!isNaN) { /* pseudo-NaN, or other unsupported? */ 3868c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 3878c2ecf20Sopenharmony_ci /* Masked response */ 3888c2ecf20Sopenharmony_ci reg_copy(&CONST_QNaN, a); 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 3918c2ecf20Sopenharmony_ci return (!(control_word & CW_Invalid) ? FPU_Exception : 3928c2ecf20Sopenharmony_ci 0) | TAG_Special; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci return TAG_Special; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 3988c2ecf20Sopenharmony_ci /* The masked response */ 3998c2ecf20Sopenharmony_ci if (!(a->sigh & 0x80000000)) { /* pseudo-NaN ? */ 4008c2ecf20Sopenharmony_ci reg_copy(&CONST_QNaN, a); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci /* ensure a Quiet NaN */ 4038c2ecf20Sopenharmony_ci a->sigh |= 0x40000000; 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci/* Real operation attempted on two operands, one a NaN. */ 4128c2ecf20Sopenharmony_ci/* Returns < 0 if the exception is unmasked */ 4138c2ecf20Sopenharmony_ciint real_2op_NaN(FPU_REG const *b, u_char tagb, 4148c2ecf20Sopenharmony_ci int deststnr, FPU_REG const *defaultNaN) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci FPU_REG *dest = &st(deststnr); 4178c2ecf20Sopenharmony_ci FPU_REG const *a = dest; 4188c2ecf20Sopenharmony_ci u_char taga = FPU_gettagi(deststnr); 4198c2ecf20Sopenharmony_ci FPU_REG const *x; 4208c2ecf20Sopenharmony_ci int signalling, unsupported; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (taga == TAG_Special) 4238c2ecf20Sopenharmony_ci taga = FPU_Special(a); 4248c2ecf20Sopenharmony_ci if (tagb == TAG_Special) 4258c2ecf20Sopenharmony_ci tagb = FPU_Special(b); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci /* TW_NaN is also used for unsupported data types. */ 4288c2ecf20Sopenharmony_ci unsupported = ((taga == TW_NaN) 4298c2ecf20Sopenharmony_ci && !((exponent(a) == EXP_OVER) 4308c2ecf20Sopenharmony_ci && (a->sigh & 0x80000000))) 4318c2ecf20Sopenharmony_ci || ((tagb == TW_NaN) 4328c2ecf20Sopenharmony_ci && !((exponent(b) == EXP_OVER) && (b->sigh & 0x80000000))); 4338c2ecf20Sopenharmony_ci if (unsupported) { 4348c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 4358c2ecf20Sopenharmony_ci /* Masked response */ 4368c2ecf20Sopenharmony_ci FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 4398c2ecf20Sopenharmony_ci return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | 4408c2ecf20Sopenharmony_ci TAG_Special; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (taga == TW_NaN) { 4448c2ecf20Sopenharmony_ci x = a; 4458c2ecf20Sopenharmony_ci if (tagb == TW_NaN) { 4468c2ecf20Sopenharmony_ci signalling = !(a->sigh & b->sigh & 0x40000000); 4478c2ecf20Sopenharmony_ci if (significand(b) > significand(a)) 4488c2ecf20Sopenharmony_ci x = b; 4498c2ecf20Sopenharmony_ci else if (significand(b) == significand(a)) { 4508c2ecf20Sopenharmony_ci /* The default result for the case of two "equal" NaNs (signs may 4518c2ecf20Sopenharmony_ci differ) is chosen to reproduce 80486 behaviour */ 4528c2ecf20Sopenharmony_ci x = defaultNaN; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci } else { 4558c2ecf20Sopenharmony_ci /* return the quiet version of the NaN in a */ 4568c2ecf20Sopenharmony_ci signalling = !(a->sigh & 0x40000000); 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci } else 4598c2ecf20Sopenharmony_ci#ifdef PARANOID 4608c2ecf20Sopenharmony_ci if (tagb == TW_NaN) 4618c2ecf20Sopenharmony_ci#endif /* PARANOID */ 4628c2ecf20Sopenharmony_ci { 4638c2ecf20Sopenharmony_ci signalling = !(b->sigh & 0x40000000); 4648c2ecf20Sopenharmony_ci x = b; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci#ifdef PARANOID 4678c2ecf20Sopenharmony_ci else { 4688c2ecf20Sopenharmony_ci signalling = 0; 4698c2ecf20Sopenharmony_ci EXCEPTION(EX_INTERNAL | 0x113); 4708c2ecf20Sopenharmony_ci x = &CONST_QNaN; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci#endif /* PARANOID */ 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if ((!signalling) || (control_word & CW_Invalid)) { 4758c2ecf20Sopenharmony_ci if (!x) 4768c2ecf20Sopenharmony_ci x = b; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */ 4798c2ecf20Sopenharmony_ci x = &CONST_QNaN; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci FPU_copy_to_regi(x, TAG_Special, deststnr); 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (!signalling) 4848c2ecf20Sopenharmony_ci return TAG_Special; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci /* ensure a Quiet NaN */ 4878c2ecf20Sopenharmony_ci dest->sigh |= 0x40000000; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Special; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci/* Invalid arith operation on Valid registers */ 4968c2ecf20Sopenharmony_ci/* Returns < 0 if the exception is unmasked */ 4978c2ecf20Sopenharmony_ciasmlinkage __visible int arith_invalid(int deststnr) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci EXCEPTION(EX_Invalid); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 5038c2ecf20Sopenharmony_ci /* The masked response */ 5048c2ecf20Sopenharmony_ci FPU_copy_to_regi(&CONST_QNaN, TAG_Special, deststnr); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return (!(control_word & CW_Invalid) ? FPU_Exception : 0) | TAG_Valid; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci} 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci/* Divide a finite number by zero */ 5128c2ecf20Sopenharmony_ciasmlinkage __visible int FPU_divide_by_zero(int deststnr, u_char sign) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci FPU_REG *dest = &st(deststnr); 5158c2ecf20Sopenharmony_ci int tag = TAG_Valid; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci if (control_word & CW_ZeroDiv) { 5188c2ecf20Sopenharmony_ci /* The masked response */ 5198c2ecf20Sopenharmony_ci FPU_copy_to_regi(&CONST_INF, TAG_Special, deststnr); 5208c2ecf20Sopenharmony_ci setsign(dest, sign); 5218c2ecf20Sopenharmony_ci tag = TAG_Special; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci EXCEPTION(EX_ZeroDiv); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci return (!(control_word & CW_ZeroDiv) ? FPU_Exception : 0) | tag; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci/* This may be called often, so keep it lean */ 5318c2ecf20Sopenharmony_ciint set_precision_flag(int flags) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci if (control_word & CW_Precision) { 5348c2ecf20Sopenharmony_ci partial_status &= ~(SW_C1 & flags); 5358c2ecf20Sopenharmony_ci partial_status |= flags; /* The masked response */ 5368c2ecf20Sopenharmony_ci return 0; 5378c2ecf20Sopenharmony_ci } else { 5388c2ecf20Sopenharmony_ci EXCEPTION(flags); 5398c2ecf20Sopenharmony_ci return 1; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci/* This may be called often, so keep it lean */ 5448c2ecf20Sopenharmony_ciasmlinkage __visible void set_precision_flag_up(void) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci if (control_word & CW_Precision) 5478c2ecf20Sopenharmony_ci partial_status |= (SW_Precision | SW_C1); /* The masked response */ 5488c2ecf20Sopenharmony_ci else 5498c2ecf20Sopenharmony_ci EXCEPTION(EX_Precision | SW_C1); 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci/* This may be called often, so keep it lean */ 5538c2ecf20Sopenharmony_ciasmlinkage __visible void set_precision_flag_down(void) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci if (control_word & CW_Precision) { /* The masked response */ 5568c2ecf20Sopenharmony_ci partial_status &= ~SW_C1; 5578c2ecf20Sopenharmony_ci partial_status |= SW_Precision; 5588c2ecf20Sopenharmony_ci } else 5598c2ecf20Sopenharmony_ci EXCEPTION(EX_Precision); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ciasmlinkage __visible int denormal_operand(void) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci if (control_word & CW_Denormal) { /* The masked response */ 5658c2ecf20Sopenharmony_ci partial_status |= SW_Denorm_Op; 5668c2ecf20Sopenharmony_ci return TAG_Special; 5678c2ecf20Sopenharmony_ci } else { 5688c2ecf20Sopenharmony_ci EXCEPTION(EX_Denormal); 5698c2ecf20Sopenharmony_ci return TAG_Special | FPU_Exception; 5708c2ecf20Sopenharmony_ci } 5718c2ecf20Sopenharmony_ci} 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ciasmlinkage __visible int arith_overflow(FPU_REG *dest) 5748c2ecf20Sopenharmony_ci{ 5758c2ecf20Sopenharmony_ci int tag = TAG_Valid; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (control_word & CW_Overflow) { 5788c2ecf20Sopenharmony_ci /* The masked response */ 5798c2ecf20Sopenharmony_ci/* ###### The response here depends upon the rounding mode */ 5808c2ecf20Sopenharmony_ci reg_copy(&CONST_INF, dest); 5818c2ecf20Sopenharmony_ci tag = TAG_Special; 5828c2ecf20Sopenharmony_ci } else { 5838c2ecf20Sopenharmony_ci /* Subtract the magic number from the exponent */ 5848c2ecf20Sopenharmony_ci addexponent(dest, (-3 * (1 << 13))); 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci EXCEPTION(EX_Overflow); 5888c2ecf20Sopenharmony_ci if (control_word & CW_Overflow) { 5898c2ecf20Sopenharmony_ci /* The overflow exception is masked. */ 5908c2ecf20Sopenharmony_ci /* By definition, precision is lost. 5918c2ecf20Sopenharmony_ci The roundup bit (C1) is also set because we have 5928c2ecf20Sopenharmony_ci "rounded" upwards to Infinity. */ 5938c2ecf20Sopenharmony_ci EXCEPTION(EX_Precision | SW_C1); 5948c2ecf20Sopenharmony_ci return tag; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return tag; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ciasmlinkage __visible int arith_underflow(FPU_REG *dest) 6028c2ecf20Sopenharmony_ci{ 6038c2ecf20Sopenharmony_ci int tag = TAG_Valid; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (control_word & CW_Underflow) { 6068c2ecf20Sopenharmony_ci /* The masked response */ 6078c2ecf20Sopenharmony_ci if (exponent16(dest) <= EXP_UNDER - 63) { 6088c2ecf20Sopenharmony_ci reg_copy(&CONST_Z, dest); 6098c2ecf20Sopenharmony_ci partial_status &= ~SW_C1; /* Round down. */ 6108c2ecf20Sopenharmony_ci tag = TAG_Zero; 6118c2ecf20Sopenharmony_ci } else { 6128c2ecf20Sopenharmony_ci stdexp(dest); 6138c2ecf20Sopenharmony_ci } 6148c2ecf20Sopenharmony_ci } else { 6158c2ecf20Sopenharmony_ci /* Add the magic number to the exponent. */ 6168c2ecf20Sopenharmony_ci addexponent(dest, (3 * (1 << 13)) + EXTENDED_Ebias); 6178c2ecf20Sopenharmony_ci } 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci EXCEPTION(EX_Underflow); 6208c2ecf20Sopenharmony_ci if (control_word & CW_Underflow) { 6218c2ecf20Sopenharmony_ci /* The underflow exception is masked. */ 6228c2ecf20Sopenharmony_ci EXCEPTION(EX_Precision); 6238c2ecf20Sopenharmony_ci return tag; 6248c2ecf20Sopenharmony_ci } 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci return tag; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_civoid FPU_stack_overflow(void) 6318c2ecf20Sopenharmony_ci{ 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 6348c2ecf20Sopenharmony_ci /* The masked response */ 6358c2ecf20Sopenharmony_ci top--; 6368c2ecf20Sopenharmony_ci FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci EXCEPTION(EX_StackOver); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci} 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_civoid FPU_stack_underflow(void) 6468c2ecf20Sopenharmony_ci{ 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 6498c2ecf20Sopenharmony_ci /* The masked response */ 6508c2ecf20Sopenharmony_ci FPU_copy_to_reg0(&CONST_QNaN, TAG_Special); 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci EXCEPTION(EX_StackUnder); 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_civoid FPU_stack_underflow_i(int i) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 6638c2ecf20Sopenharmony_ci /* The masked response */ 6648c2ecf20Sopenharmony_ci FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); 6658c2ecf20Sopenharmony_ci } 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci EXCEPTION(EX_StackUnder); 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci return; 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_civoid FPU_stack_underflow_pop(int i) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci if (control_word & CW_Invalid) { 6778c2ecf20Sopenharmony_ci /* The masked response */ 6788c2ecf20Sopenharmony_ci FPU_copy_to_regi(&CONST_QNaN, TAG_Special, i); 6798c2ecf20Sopenharmony_ci FPU_pop(); 6808c2ecf20Sopenharmony_ci } 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci EXCEPTION(EX_StackUnder); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci} 687