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