summaryrefslogtreecommitdiff
path: root/sys/gnu/arch/i386
diff options
context:
space:
mode:
authorJason Downs <downsj@cvs.openbsd.org>1996-08-27 10:33:05 +0000
committerJason Downs <downsj@cvs.openbsd.org>1996-08-27 10:33:05 +0000
commitd8270b44b1f22944ea7aaaf8e11b8ddc7fbf94aa (patch)
tree1c6d66ec2f8bcf690f8a1dd1eb265b677ec778ff /sys/gnu/arch/i386
parentd21d48db18c4d62ff0fd6630fcb728ff04939183 (diff)
Everyone, say hello to a real floating point emulator!
The fpemul written for Linux by W. Metzenthen: ported to NetBSD and then to FreeBSD, and now back to OpenBSD.
Diffstat (limited to 'sys/gnu/arch/i386')
-rw-r--r--sys/gnu/arch/i386/fpemul/Changelog38
-rw-r--r--sys/gnu/arch/i386/fpemul/README278
-rw-r--r--sys/gnu/arch/i386/fpemul/README.OpenBSD23
-rw-r--r--sys/gnu/arch/i386/fpemul/control_w.h96
-rw-r--r--sys/gnu/arch/i386/fpemul/div_small.s104
-rw-r--r--sys/gnu/arch/i386/fpemul/errors.c614
-rw-r--r--sys/gnu/arch/i386/fpemul/exception.h109
-rw-r--r--sys/gnu/arch/i386/fpemul/files.fpemul33
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_arith.c236
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_asm.h83
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_aux.c233
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_emu.h189
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_entry.c554
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_etc.c176
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_proto.h115
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_system.h102
-rw-r--r--sys/gnu/arch/i386/fpemul/fpu_trig.c1370
-rw-r--r--sys/gnu/arch/i386/fpemul/get_address.c204
-rw-r--r--sys/gnu/arch/i386/fpemul/load_store.c273
-rw-r--r--sys/gnu/arch/i386/fpemul/math_emu.h48
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_2xm1.c142
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_atan.c254
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_div.s147
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_l2.c319
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_mul64.s127
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_sin.c193
-rw-r--r--sys/gnu/arch/i386/fpemul/poly_tan.c230
-rw-r--r--sys/gnu/arch/i386/fpemul/polynomial.s195
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_add_sub.c304
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_compare.c385
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_constant.c172
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_constant.h83
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_div.s298
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_ld_str.c1391
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_mul.c163
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_norm.s185
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_round.s656
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_u_add.s247
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_u_div.s509
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_u_mul.s202
-rw-r--r--sys/gnu/arch/i386/fpemul/reg_u_sub.s364
-rw-r--r--sys/gnu/arch/i386/fpemul/status_w.h107
-rw-r--r--sys/gnu/arch/i386/fpemul/version.h62
-rw-r--r--sys/gnu/arch/i386/fpemul/wm_shrx.s264
-rw-r--r--sys/gnu/arch/i386/fpemul/wm_sqrt.s499
45 files changed, 12376 insertions, 0 deletions
diff --git a/sys/gnu/arch/i386/fpemul/Changelog b/sys/gnu/arch/i386/fpemul/Changelog
new file mode 100644
index 00000000000..2585537d27f
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/Changelog
@@ -0,0 +1,38 @@
+$OpenBSD: Changelog,v 1.1 1996/08/27 10:32:38 downsj Exp $
+
+This file contains the changes made to W. Metzenthem's 387 FPU
+emulator to make it work under NetBSD.
+
+a, Changes to make it compile:
+
+ 1 - Changed the #include's to get the appropriate .h files.
+ 2 - Renamed .S to .s, to satisfy the kernel Makefile.
+ 3 - Changed the C++ style // comments to /* */
+ 4 - Changed the FPU_ORIG_EIP macro. A letter from bde included
+ in the package suggested using tf_isp for using instead
+ of the linux __orig_eip. This later turned out to interfere
+ with the user stack, so i created a separate variable, stored
+ in the i387_union.
+ 5 - Changed the get_fs_.. put_fs_.. fns to fubyte,fuword,subyte,
+ suword.
+ 6 - Removed the verify_area fns. I don't really know what they do,
+ i suppose they verify access to memory. The sufu routines
+ should do this.
+
+b, Changes to make it work:
+
+ 1 - Made math_emulate() to return 0 when successful, so trap() won't
+ try to generate a signal.
+ 2 - Changed the size of the save87 struct in /sys/arch/i387/include/
+ npx.h to accomodate the i387_union.
+
+d, Other changes:
+
+ 1 - Removed obsolate and/or linux specific stuff.
+ 2 - Changed the RE_ENTRANT_CHECK_[ON|OFF] macro to
+ REENTRANT_CHECK([ON|OFF]) so indent can grok it.
+ 3 - Re-indented to Berkeley style.
+ 4 - Limited max no of lookaheads. LOOKAHEAD_LIMIT in fpu_entry.c
+
+
+ Szabolcs Szigeti (pink@fsz.bme.hu)
diff --git a/sys/gnu/arch/i386/fpemul/README b/sys/gnu/arch/i386/fpemul/README
new file mode 100644
index 00000000000..a477cbe0ff5
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/README
@@ -0,0 +1,278 @@
+$OpenBSD: README,v 1.1 1996/08/27 10:32:39 downsj Exp $
+/*
+ * wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ */
+
+wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387
+which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was
+in turn based upon emu387 which was written by DJ Delorie for djgpp.
+The interface to the Linux kernel is based upon the original Linux
+math emulator by Linus Torvalds.
+
+My target FPU for wm-FPU-emu is that described in the Intel486
+Programmer's Reference Manual (1992 edition). Numerous facets of the
+functioning of the FPU are not well covered in the Reference Manual;
+in the absence of clear details I have made guesses about the most
+reasonable behaviour. Recently, this situation has improved because
+I now have some access to the results produced by a real 80486 FPU.
+
+wm-FPU-emu does not implement all of the behaviour of the 80486 FPU.
+See "Limitations" later in this file for a partial list of some
+differences. I believe that the missing features are never used by
+normal C or FORTRAN programs.
+
+
+Please report bugs, etc to me at:
+ apm233m@vaxc.cc.monash.edu.au
+
+
+--Bill Metzenthen
+ May 1993
+
+
+----------------------- Internals of wm-FPU-emu -----------------------
+
+Numeric algorithms:
+(1) Add, subtract, and multiply. Nothing remarkable in these.
+(2) Divide has been tuned to get reasonable performance. The algorithm
+ is not the obvious one which most people seem to use, but is designed
+ to take advantage of the characteristics of the 80386. I expect that
+ it has been invented many times before I discovered it, but I have not
+ seen it. It is based upon one of those ideas which one carries around
+ for years without ever bothering to check it out.
+(3) The sqrt function has been tuned to get good performance. It is based
+ upon Newton's classic method. Performance was improved by capitalizing
+ upon the properties of Newton's method, and the code is once again
+ structured taking account of the 80386 characteristics.
+(4) The trig, log, and exp functions are based in each case upon quasi-
+ "optimal" polynomial approximations. My definition of "optimal" was
+ based upon getting good accuracy with reasonable speed.
+
+The code of the emulator is complicated slightly by the need to
+account for a limited form of re-entrancy. Normally, the emulator will
+emulate each FPU instruction to completion without interruption.
+However, it may happen that when the emulator is accessing the user
+memory space, swapping may be needed. In this case the emulator may be
+temporarily suspended while disk i/o takes place. During this time
+another process may use the emulator, thereby changing some static
+variables (eg FPU_st0_ptr, etc). The code which accesses user memory
+is confined to five files:
+ fpu_entry.c
+ reg_ld_str.c
+ load_store.c
+ get_address.c
+ errors.c
+
+----------------------- Limitations of wm-FPU-emu -----------------------
+
+There are a number of differences between the current wm-FPU-emu
+(version beta 1.4) and the 80486 FPU (apart from bugs). Some of the
+more important differences are listed below:
+
+All internal computations are performed at 64 bit or higher precision
+and rounded etc as required by the PC bits of the FPU control word.
+Under the crt0 version for Linux current at March 1993, the FPU PC
+bits specify 53 bits precision.
+
+The precision flag (PE of the FPU status word) and the Roundup flag
+(C1 of the status word) are now partially implemented. Does anyone
+write code which uses these features?
+
+The functions which load/store the FPU state are partially implemented,
+but the implementation should be sufficient for handling FPU errors etc
+in 32 bit protected mode.
+
+The implementation of the exception mechanism is flawed for unmasked
+interrupts.
+
+Detection of certain conditions, such as denormal operands, is not yet
+complete.
+
+----------------------- Performance of wm-FPU-emu -----------------------
+
+Speed.
+-----
+
+The speed of floating point computation with the emulator will depend
+upon instruction mix. Relative performance is best for the instructions
+which require most computation. The simple instructions are adversely
+affected by the fpu instruction trap overhead.
+
+
+Timing: Some simple timing tests have been made on the emulator functions.
+The times include load/store instructions. All times are in microseconds
+measured on a 33MHz 386 with 64k cache. The Turbo C tests were under
+ms-dos, the next two columns are for emulators running with the djgpp
+ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97,
+using libm4.0 (hard).
+
+function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu
+
+ + 60.5 154.8 76.5 139.4
+ - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7
+ * 71.0 190.8 79.6 146.6
+ / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1
+
+ sin() 310.8 4692.0 319.0 398.5
+ cos() 284.4 4855.2 308.0 388.7
+ tan() 495.0 8807.1 394.9 504.7
+ atan() 328.9 4866.4 601.1 419.5-491.9
+
+ sqrt() 128.7 crashed 145.2 227.0
+ log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1
+ exp() 479.1 6619.2 469.1 850.8
+
+
+The performance under Linux is improved by the use of look-ahead code.
+The following results show the improvement which is obtained under
+Linux due to the look-ahead code. Also given are the times for the
+original Linux emulator with the 4.1 'soft' lib.
+
+ [ Linus' note: I changed look-ahead to be the default under linux, as
+ there was no reason not to use it after I had edited it to be
+ disabled during tracing ]
+
+ wm-FPU-emu w original w
+ look-ahead 'soft' lib
+ + 106.4 190.2
+ - 108.6-111.6 192.4-216.2
+ * 113.4 193.1
+ / 108.8-124.4 700.1-706.2
+
+ sin() 390.5 2642.0
+ cos() 381.5 2767.4
+ tan() 496.5 3153.3
+ atan() 367.2-435.5 2439.4-3396.8
+
+ sqrt() 195.1 4732.5
+ log() 358.0-387.5 3359.2-3390.3
+ exp() 619.3 4046.4
+
+
+These figures are now somewhat out-of-date. The emulator has become
+progressively slower for most functions as more of the 80486 features
+have been implemented.
+
+
+----------------------- Accuracy of wm-FPU-emu -----------------------
+
+
+Accuracy: The following table gives the accuracy of the sqrt(), trig
+and log functions. Each function was tested at about 400 points. Ideal
+results would be 64 bits. The reduced accuracy of cos() and tan() for
+arguments greater than pi/4 can be thought of as being due to the
+precision of the argument x; e.g. an argument of pi/2-(1e-10) which is
+accurate to 64 bits can result in a relative accuracy in cos() of about
+64 + log2(cos(x)) = 31 bits. Results for the Turbo C emulator are given
+in the last column.
+
+
+Function Tested x range Worst result (bits) Turbo C
+
+sqrt(x) 1 .. 2 64.1 63.2
+atan(x) 1e-10 .. 200 62.6 62.8
+cos(x) 0 .. pi/2-(1e-10) 63.2 (x <= pi/4) 62.4
+ 35.2 (x = pi/2-(1e-10)) 31.9
+sin(x) 1e-10 .. pi/2 63.0 62.8
+tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1
+ 35.2 (x = pi/2-(1e-10)) 31.9
+exp(x) 0 .. 1 63.1 62.9
+log(x) 1+1e-6 .. 2 62.4 62.1
+
+
+As of version 1.3 of the emulator, the accuracy of the basic
+arithmetic has been improved (by a small fraction of a bit). Care has
+been taken to ensure full accuracy of the rounding of the basic
+arithmetic functions (+,-,*,/,and fsqrt), and they all now produce
+results which are exact to the 64th bit (unless there are any bugs
+left). To ensure this, it was necessary to effectively get information
+of up to about 128 bits precision. The emulator now passes the
+"paranoia" tests (compiled with gcc 2.3.3) for 'float' variables (24
+bit precision numbers) when precision control is set to 24, 53 or 64
+bits, and for 'double' variables (53 bit precision numbers) when
+precision control is set to 53 bits (a properly performing FPU cannot
+pass the 'paranoia' tests for 'double' variables when precision
+control is set to 64 bits).
+
+------------------------- Contributors -------------------------------
+
+A number of people have contributed to the development of the
+emulator, often by just reporting bugs, sometimes with a suggested
+fix, and a few kind people have provided me with access in one way or
+another to an 80486 machine. Contributors include (to those people who
+I have forgotten, please excuse me):
+
+Linus Torvalds
+Tommy.Thorn@daimi.aau.dk
+Andrew.Tridgell@anu.edu.au
+Nick Holloway alfie@dcs.warwick.ac.uk
+Hermano Moura moura@dcs.gla.ac.uk
+Jon Jagger J.Jagger@scp.ac.uk
+Lennart Benschop
+Brian Gallew geek+@CMU.EDU
+Thomas Staniszewski ts3v+@andrew.cmu.edu
+Martin Howell mph@plasma.apana.org.au
+M Saggaf alsaggaf@athena.mit.edu
+Peter Barker PETER@socpsy.sci.fau.edu
+tom@vlsivie.tuwien.ac.at
+Dan Russel russed@rpi.edu
+Daniel Carosone danielce@ee.mu.oz.au
+cae@jpmorgan.com
+Hamish Coleman t933093@minyos.xx.rmit.oz.au
+
+...and numerous others who responded to my request for help with
+a real 80486.
+
diff --git a/sys/gnu/arch/i386/fpemul/README.OpenBSD b/sys/gnu/arch/i386/fpemul/README.OpenBSD
new file mode 100644
index 00000000000..1347ea0a16a
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/README.OpenBSD
@@ -0,0 +1,23 @@
+$OpenBSD: README.OpenBSD,v 1.1 1996/08/27 10:32:40 downsj Exp $
+
+ OpenBSD distributes this module under the terms of GNU General Public
+ License, version 2.
+
+ Copyright (C) 1992,1993,1994
+ W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ Australia. E-mail billm@vaxc.cc.monash.edu.au
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
diff --git a/sys/gnu/arch/i386/fpemul/control_w.h b/sys/gnu/arch/i386/fpemul/control_w.h
new file mode 100644
index 00000000000..a9eb8790f52
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/control_w.h
@@ -0,0 +1,96 @@
+/* $OpenBSD: control_w.h,v 1.1 1996/08/27 10:32:40 downsj Exp $ */
+/*
+ * control_w.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: control_w.h,v 1.4 1995/05/30 07:57:41 rgrimes Exp $
+ *
+ */
+
+#ifndef _CONTROLW_H_
+#define _CONTROLW_H_
+
+#ifdef _LOCORE
+#define _Const_(x) $/**/x
+#else
+#define _Const_(x) x
+#endif
+
+#define CW_RC _Const_(0x0C00) /* rounding control */
+#define CW_PC _Const_(0x0300) /* precision control */
+
+#define CW_Precision Const_(0x0020) /* loss of precision mask */
+#define CW_Underflow Const_(0x0010) /* underflow mask */
+#define CW_Overflow Const_(0x0008) /* overflow mask */
+#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */
+#define CW_Denormal Const_(0x0002) /* denormalized operand mask */
+#define CW_Invalid Const_(0x0001) /* invalid operation mask */
+
+#define CW_Exceptions _Const_(0x003f) /* all masks */
+
+#define RC_RND _Const_(0x0000)
+#define RC_DOWN _Const_(0x0400)
+#define RC_UP _Const_(0x0800)
+#define RC_CHOP _Const_(0x0C00)
+
+/* p 15-5: Precision control bits affect only the following:
+ ADD, SUB(R), MUL, DIV(R), and SQRT */
+#define PR_24_BITS _Const_(0x000)
+#define PR_53_BITS _Const_(0x200)
+#define PR_64_BITS _Const_(0x300)
+/* FULL_PRECISION simulates all exceptions masked */
+#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f)
+
+#endif /* _CONTROLW_H_ */
diff --git a/sys/gnu/arch/i386/fpemul/div_small.s b/sys/gnu/arch/i386/fpemul/div_small.s
new file mode 100644
index 00000000000..e652be839ee
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/div_small.s
@@ -0,0 +1,104 @@
+ .file "div_small.S"
+/* $OpenBSD: div_small.s,v 1.1 1996/08/27 10:32:41 downsj Exp $ */
+/*
+ * div_small.S
+ *
+ * Divide a 64 bit integer by a 32 bit integer & return remainder.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: div_small.s,v 1.3 1994/06/10 07:44:08 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | unsigned long div_small(unsigned long long *x, unsigned long y) |
+ +---------------------------------------------------------------------------*/
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+.text
+ .align 2,144
+
+.globl _div_small
+
+_div_small:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ecx /* The denominator */
+
+ movl 4(%esi),%eax /* Get the current num msw */
+ xorl %edx,%edx
+ divl %ecx
+
+ movl %eax,4(%esi)
+
+ movl (%esi),%eax /* Get the num lsw */
+ divl %ecx
+
+ movl %eax,(%esi)
+
+ movl %edx,%eax /* Return the remainder in eax */
+
+ popl %esi
+
+ leave
+ ret
+
diff --git a/sys/gnu/arch/i386/fpemul/errors.c b/sys/gnu/arch/i386/fpemul/errors.c
new file mode 100644
index 00000000000..fe84aa88824
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/errors.c
@@ -0,0 +1,614 @@
+/* $OpenBSD: errors.c,v 1.1 1996/08/27 10:32:42 downsj Exp $ */
+/*
+ * errors.c
+ *
+ * The error handling functions for wm-FPU-emu
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: errors.c,v 1.4 1995/03/16 18:11:10 bde Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+
+
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/version.h>
+
+/* */
+#undef PRINT_MESSAGES
+/* */
+
+
+void
+Un_impl(void)
+{
+ unsigned char byte1, FPU_modrm;
+
+ REENTRANT_CHECK(OFF);
+ byte1 = fubyte((unsigned char *) FPU_ORIG_EIP);
+ FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP);
+
+ printf("Unimplemented FPU Opcode at eip=%p : %02x ",
+ FPU_ORIG_EIP, byte1);
+
+ if (FPU_modrm >= 0300)
+ printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printf("/%d\n", (FPU_modrm >> 3) & 7);
+ REENTRANT_CHECK(ON);
+
+ EXCEPTION(EX_Invalid);
+
+}
+
+
+
+
+void
+emu_printall()
+{
+ int i;
+ static char *tag_desc[] = {"Valid", "Zero", "ERROR", "ERROR",
+ "DeNorm", "Inf", "NaN", "Empty"};
+ unsigned char byte1, FPU_modrm;
+
+ REENTRANT_CHECK(OFF);
+ byte1 = fubyte((unsigned char *) FPU_ORIG_EIP);
+ FPU_modrm = fubyte(1 + (unsigned char *) FPU_ORIG_EIP);
+
+#ifdef DEBUGGING
+ if (status_word & SW_Backward)
+ printf("SW: backward compatibility\n");
+ if (status_word & SW_C3)
+ printf("SW: condition bit 3\n");
+ if (status_word & SW_C2)
+ printf("SW: condition bit 2\n");
+ if (status_word & SW_C1)
+ printf("SW: condition bit 1\n");
+ if (status_word & SW_C0)
+ printf("SW: condition bit 0\n");
+ if (status_word & SW_Summary)
+ printf("SW: exception summary\n");
+ if (status_word & SW_Stack_Fault)
+ printf("SW: stack fault\n");
+ if (status_word & SW_Precision)
+ printf("SW: loss of precision\n");
+ if (status_word & SW_Underflow)
+ printf("SW: underflow\n");
+ if (status_word & SW_Overflow)
+ printf("SW: overflow\n");
+ if (status_word & SW_Zero_Div)
+ printf("SW: divide by zero\n");
+ if (status_word & SW_Denorm_Op)
+ printf("SW: denormalized operand\n");
+ if (status_word & SW_Invalid)
+ printf("SW: invalid operation\n");
+#endif /* DEBUGGING */
+
+ status_word = status_word & ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+
+ printf("At %p: %02x ", FPU_ORIG_EIP, byte1);
+ if (FPU_modrm >= 0300)
+ printf("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7);
+ else
+ printf("/%d, mod=%d rm=%d\n",
+ (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7);
+
+ printf(" SW: b=%d st=%d es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n",
+ status_word & 0x8000 ? 1 : 0, /* busy */
+ (status_word & 0x3800) >> 11, /* stack top pointer */
+ status_word & 0x80 ? 1 : 0, /* Error summary status */
+ status_word & 0x40 ? 1 : 0, /* Stack flag */
+ status_word & SW_C3 ? 1 : 0, status_word & SW_C2 ? 1 : 0, /* cc */
+ status_word & SW_C1 ? 1 : 0, status_word & SW_C0 ? 1 : 0, /* cc */
+ status_word & SW_Precision ? 1 : 0, status_word & SW_Underflow ? 1 : 0,
+ status_word & SW_Overflow ? 1 : 0, status_word & SW_Zero_Div ? 1 : 0,
+ status_word & SW_Denorm_Op ? 1 : 0, status_word & SW_Invalid ? 1 : 0);
+
+ printf(" CW: ic=%d rc=%d%d pc=%d%d iem=%d ef=%d%d%d%d%d%d\n",
+ control_word & 0x1000 ? 1 : 0,
+ (control_word & 0x800) >> 11, (control_word & 0x400) >> 10,
+ (control_word & 0x200) >> 9, (control_word & 0x100) >> 8,
+ control_word & 0x80 ? 1 : 0,
+ control_word & SW_Precision ? 1 : 0, control_word & SW_Underflow ? 1 : 0,
+ control_word & SW_Overflow ? 1 : 0, control_word & SW_Zero_Div ? 1 : 0,
+ control_word & SW_Denorm_Op ? 1 : 0, control_word & SW_Invalid ? 1 : 0);
+
+ for (i = 0; i < 8; i++) {
+ FPU_REG *r = &st(i);
+ switch (r->tag) {
+ case TW_Empty:
+ continue;
+ break;
+ case TW_Zero:
+ printf("st(%d) %c .0000 0000 0000 0000 ",
+ i, r->sign ? '-' : '+');
+ break;
+ case TW_Valid:
+ case TW_NaN:
+ case TW_Denormal:
+ case TW_Infinity:
+ printf("st(%d) %c .%04x %04x %04x %04x e%+-6d ", i,
+ r->sign ? '-' : '+',
+ (long) (r->sigh >> 16),
+ (long) (r->sigh & 0xFFFF),
+ (long) (r->sigl >> 16),
+ (long) (r->sigl & 0xFFFF),
+ r->exp - EXP_BIAS + 1);
+ break;
+ default:
+ printf("Whoops! Error in errors.c ");
+ break;
+ }
+ printf("%s\n", tag_desc[(int) (unsigned) r->tag]);
+ }
+
+ printf("[data] %c .%04x %04x %04x %04x e%+-6d ",
+ FPU_loaded_data.sign ? '-' : '+',
+ (long) (FPU_loaded_data.sigh >> 16),
+ (long) (FPU_loaded_data.sigh & 0xFFFF),
+ (long) (FPU_loaded_data.sigl >> 16),
+ (long) (FPU_loaded_data.sigl & 0xFFFF),
+ FPU_loaded_data.exp - EXP_BIAS + 1);
+ printf("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]);
+ REENTRANT_CHECK(ON);
+
+}
+
+static struct {
+ int type;
+ char *name;
+} exception_names[] = {
+ {
+ EX_StackOver, "stack overflow"
+ },
+ {
+ EX_StackUnder, "stack underflow"
+ },
+ {
+ EX_Precision, "loss of precision"
+ },
+ {
+ EX_Underflow, "underflow"
+ },
+ {
+ EX_Overflow, "overflow"
+ },
+ {
+ EX_ZeroDiv, "divide by zero"
+ },
+ {
+ EX_Denormal, "denormalized operand"
+ },
+ {
+ EX_Invalid, "invalid operation"
+ },
+ {
+ EX_INTERNAL, "INTERNAL BUG in " FPU_VERSION
+ },
+ {
+ 0, NULL
+ }
+};
+/*
+ EX_INTERNAL is always given with a code which indicates where the
+ error was detected.
+
+ Internal error types:
+ 0x14 in e14.c
+ 0x1nn in a *.c file:
+ 0x101 in reg_add_sub.c
+ 0x102 in reg_mul.c
+ 0x103 in poly_sin.c
+ 0x104 in poly_tan.c
+ 0x105 in reg_mul.c
+ 0x106 in reg_mov.c
+ 0x107 in fpu_trig.c
+ 0x108 in reg_compare.c
+ 0x109 in reg_compare.c
+ 0x110 in reg_add_sub.c
+ 0x111 in interface.c
+ 0x112 in fpu_trig.c
+ 0x113 in reg_add_sub.c
+ 0x114 in reg_ld_str.c
+ 0x115 in fpu_trig.c
+ 0x116 in fpu_trig.c
+ 0x117 in fpu_trig.c
+ 0x118 in fpu_trig.c
+ 0x119 in fpu_trig.c
+ 0x120 in poly_atan.c
+ 0x121 in reg_compare.c
+ 0x122 in reg_compare.c
+ 0x123 in reg_compare.c
+ 0x2nn in an *.s file:
+ 0x201 in reg_u_add.S
+ 0x202 in reg_u_div.S
+ 0x203 in reg_u_div.S
+ 0x204 in reg_u_div.S
+ 0x205 in reg_u_mul.S
+ 0x206 in reg_u_sub.S
+ 0x207 in wm_sqrt.S
+ 0x208 in reg_div.S
+ 0x209 in reg_u_sub.S
+ 0x210 in reg_u_sub.S
+ 0x211 in reg_u_sub.S
+ 0x212 in reg_u_sub.S
+ 0x213 in wm_sqrt.S
+ 0x214 in wm_sqrt.S
+ 0x215 in wm_sqrt.S
+ 0x216 in reg_round.S
+ 0x217 in reg_round.S
+ 0x218 in reg_round.S
+ */
+
+void
+exception(int n)
+{
+ int i, int_type;
+
+ int_type = 0; /* Needed only to stop compiler warnings */
+ if (n & EX_INTERNAL) {
+ int_type = n - EX_INTERNAL;
+ n = EX_INTERNAL;
+ /* Set lots of exception bits! */
+ status_word |= (SW_Exc_Mask | SW_Summary | FPU_BUSY);
+ } else {
+ /* Extract only the bits which we use to set the status word */
+ n &= (SW_Exc_Mask);
+ /* Set the corresponding exception bit */
+ status_word |= n;
+ if (status_word & ~control_word & CW_Exceptions)
+ status_word |= SW_Summary;
+ if (n & (SW_Stack_Fault | EX_Precision)) {
+ if (!(n & SW_C1))
+ /* This bit distinguishes over- from underflow
+ * for a stack fault, and roundup from
+ * round-down for precision loss. */
+ status_word &= ~SW_C1;
+ }
+ }
+
+ REENTRANT_CHECK(OFF);
+ if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
+#ifdef PRINT_MESSAGES
+ /* My message from the sponsor */
+ printf(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
+#endif /* PRINT_MESSAGES */
+
+ /* Get a name string for error reporting */
+ for (i = 0; exception_names[i].type; i++)
+ if ((exception_names[i].type & n) == exception_names[i].type)
+ break;
+
+ if (exception_names[i].type) {
+#ifdef PRINT_MESSAGES
+ printf("FP Exception: %s!\n", exception_names[i].name);
+#endif /* PRINT_MESSAGES */
+ } else
+ printf("FP emulator: Unknown Exception: 0x%04x!\n", n);
+
+ if (n == EX_INTERNAL) {
+ printf("FP emulator: Internal error type 0x%04x\n", int_type);
+ emu_printall();
+ }
+#ifdef PRINT_MESSAGES
+ else
+ emu_printall();
+#endif /* PRINT_MESSAGES */
+
+ /* The 80486 generates an interrupt on the next non-control
+ * FPU instruction. So we need some means of flagging it. We
+ * use the ES (Error Summary) bit for this, assuming that this
+ * is the way a real FPU does it (until I can check it out),
+ * if not, then some method such as the following kludge might
+ * be needed. */
+/* regs[0].tag |= TW_FPU_Interrupt; */
+ }
+ REENTRANT_CHECK(ON);
+
+#ifdef __DEBUG__
+ math_abort(SIGFPE);
+#endif /* __DEBUG__ */
+
+}
+
+
+/* Real operation attempted on two operands, one a NaN */
+void
+real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest)
+{
+ FPU_REG *x;
+ int signalling;
+
+ x = a;
+ if (a->tag == TW_NaN) {
+ if (b->tag == TW_NaN) {
+ signalling = !(a->sigh & b->sigh & 0x40000000);
+ /* find the "larger" */
+ if (*(long long *) &(a->sigl) < *(long long *) &(b->sigl))
+ x = b;
+ } else {
+ /* return the quiet version of the NaN in a */
+ signalling = !(a->sigh & 0x40000000);
+ }
+ } else
+#ifdef PARANOID
+ if (b->tag == TW_NaN)
+#endif /* PARANOID */
+ {
+ signalling = !(b->sigh & 0x40000000);
+ x = b;
+ }
+#ifdef PARANOID
+ else {
+ signalling = 0;
+ EXCEPTION(EX_INTERNAL | 0x113);
+ x = &CONST_QNaN;
+ }
+#endif /* PARANOID */
+
+ if (!signalling) {
+ if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+ reg_move(x, dest);
+ return;
+ }
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ if (!(x->sigh & 0x80000000)) /* pseudo-NaN ? */
+ x = &CONST_QNaN;
+ reg_move(x, dest);
+ /* ensure a Quiet NaN */
+ dest->sigh |= 0x40000000;
+ }
+ EXCEPTION(EX_Invalid);
+
+ return;
+}
+/* Invalid arith operation on Valid registers */
+void
+arith_invalid(FPU_REG * dest)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, dest);
+ }
+ EXCEPTION(EX_Invalid);
+
+ return;
+
+}
+
+
+/* Divide a finite number by zero */
+void
+divide_by_zero(int sign, FPU_REG * dest)
+{
+
+ if (control_word & CW_ZeroDiv) {
+ /* The masked response */
+ reg_move(&CONST_INF, dest);
+ dest->sign = (unsigned char) sign;
+ }
+ EXCEPTION(EX_ZeroDiv);
+
+ return;
+
+}
+
+
+/* This may be called often, so keep it lean */
+void
+set_precision_flag_up(void)
+{
+ if (control_word & CW_Precision)
+ status_word |= (SW_Precision | SW_C1); /* The masked response */
+ else
+ exception(EX_Precision | SW_C1);
+
+}
+
+
+/* This may be called often, so keep it lean */
+void
+set_precision_flag_down(void)
+{
+ if (control_word & CW_Precision) { /* The masked response */
+ status_word &= ~SW_C1;
+ status_word |= SW_Precision;
+ } else
+ exception(EX_Precision);
+}
+
+
+int
+denormal_operand(void)
+{
+ if (control_word & CW_Denormal) { /* The masked response */
+ status_word |= SW_Denorm_Op;
+ return 0;
+ } else {
+ exception(EX_Denormal);
+ return 1;
+ }
+}
+
+
+void
+arith_overflow(FPU_REG * dest)
+{
+
+ if (control_word & CW_Overflow) {
+ char sign;
+ /* The masked response */
+/* **** The response here depends upon the rounding mode */
+ sign = dest->sign;
+ reg_move(&CONST_INF, dest);
+ dest->sign = sign;
+ } else {
+ /* Subtract the magic number from the exponent */
+ dest->exp -= (3 * (1 << 13));
+ }
+
+ /* By definition, precision is lost. It appears that the roundup bit
+ * (C1) is also set by convention. */
+ EXCEPTION(EX_Overflow | EX_Precision | SW_C1);
+
+ return;
+
+}
+
+
+void
+arith_underflow(FPU_REG * dest)
+{
+
+ if (control_word & CW_Underflow) {
+ /* The masked response */
+ if (dest->exp <= EXP_UNDER - 63)
+ reg_move(&CONST_Z, dest);
+ } else {
+ /* Add the magic number to the exponent */
+ dest->exp += (3 * (1 << 13));
+ }
+
+ EXCEPTION(EX_Underflow);
+
+ return;
+}
+
+
+void
+stack_overflow(void)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ top--;
+ reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0));
+ }
+ EXCEPTION(EX_StackOver);
+
+ return;
+
+}
+
+
+void
+stack_underflow(void)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, FPU_st0_ptr);
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void
+stack_underflow_i(int i)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, &(st(i)));
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
+
+
+void
+stack_underflow_pop(int i)
+{
+
+ if (control_word & CW_Invalid) {
+ /* The masked response */
+ reg_move(&CONST_QNaN, &(st(i)));
+ pop();
+ }
+ EXCEPTION(EX_StackUnder);
+
+ return;
+
+}
diff --git a/sys/gnu/arch/i386/fpemul/exception.h b/sys/gnu/arch/i386/fpemul/exception.h
new file mode 100644
index 00000000000..d96bd7a7d17
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/exception.h
@@ -0,0 +1,109 @@
+/* $OpenBSD: exception.h,v 1.1 1996/08/27 10:32:43 downsj Exp $ */
+/*
+ * exception.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: exception.h,v 1.4 1995/12/22 16:53:48 bde Exp $
+ *
+ *
+ */
+
+#ifndef _EXCEPTION_H_
+#define _EXCEPTION_H_
+
+
+#ifdef _LOCORE
+#define Const_(x) $/**/x
+#else
+#define Const_(x) x
+#endif
+
+#ifndef SW_C1
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#endif /* SW_C1 */
+
+#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */
+#define EX_ErrorSummary Const_(0x0080) /* Error summary status */
+/* Special exceptions: */
+#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */
+#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */
+#define EX_StackUnder Const_(0x0041) /* stack underflow */
+/* Exception flags: */
+#define EX_Precision Const_(0x0020) /* loss of precision */
+#define EX_Underflow Const_(0x0010) /* underflow */
+#define EX_Overflow Const_(0x0008) /* overflow */
+#define EX_ZeroDiv Const_(0x0004) /* divide by zero */
+#define EX_Denormal Const_(0x0002) /* denormalized operand */
+#define EX_Invalid Const_(0x0001) /* invalid operation */
+
+
+#ifndef _LOCORE
+
+#ifdef DEBUG
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#define EXCEPTION(x) \
+ do { \
+ printf("exception in %s at line %d\n", __FILE__, __LINE__); \
+ exception(x); \
+ } while (0)
+#else
+#define EXCEPTION(x) exception(x)
+#endif
+
+#endif /* _LOCORE */
+
+#endif /* _EXCEPTION_H_ */
diff --git a/sys/gnu/arch/i386/fpemul/files.fpemul b/sys/gnu/arch/i386/fpemul/files.fpemul
new file mode 100644
index 00000000000..4fa58f1db00
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/files.fpemul
@@ -0,0 +1,33 @@
+# $OpenBSD: files.fpemul,v 1.1 1996/08/27 10:32:43 downsj Exp $
+
+file gnu/arch/i386/fpemul/div_small.s gpl_math_emulate
+file gnu/arch/i386/fpemul/errors.c gpl_math_emulate
+file gnu/arch/i386/fpemul/fpu_arith.c gpl_math_emulate
+file gnu/arch/i386/fpemul/fpu_aux.c gpl_math_emulate
+file gnu/arch/i386/fpemul/fpu_entry.c gpl_math_emulate
+file gnu/arch/i386/fpemul/fpu_etc.c gpl_math_emulate
+file gnu/arch/i386/fpemul/fpu_trig.c gpl_math_emulate
+file gnu/arch/i386/fpemul/get_address.c gpl_math_emulate
+file gnu/arch/i386/fpemul/load_store.c gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_2xm1.c gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_atan.c gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_div.s gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_l2.c gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_mul64.s gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_sin.c gpl_math_emulate
+file gnu/arch/i386/fpemul/poly_tan.c gpl_math_emulate
+file gnu/arch/i386/fpemul/polynomial.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_add_sub.c gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_compare.c gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_constant.c gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_div.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_ld_str.c gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_mul.c gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_norm.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_round.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_u_add.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_u_div.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_u_mul.s gpl_math_emulate
+file gnu/arch/i386/fpemul/reg_u_sub.s gpl_math_emulate
+file gnu/arch/i386/fpemul/wm_shrx.s gpl_math_emulate
+file gnu/arch/i386/fpemul/wm_sqrt.s gpl_math_emulate
diff --git a/sys/gnu/arch/i386/fpemul/fpu_arith.c b/sys/gnu/arch/i386/fpemul/fpu_arith.c
new file mode 100644
index 00000000000..2c73fa7c1f2
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_arith.c
@@ -0,0 +1,236 @@
+/* $OpenBSD: fpu_arith.c,v 1.1 1996/08/27 10:32:44 downsj Exp $ */
+/*
+ * fpu_arith.c
+ *
+ * Code to implement the FPU register/register arithmetic instructions
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_arith.c,v 1.4 1995/05/30 07:57:43 rgrimes Exp $
+ *
+ */
+
+
+
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+void
+fadd__()
+{
+ /* fadd st,st(i) */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fmul__()
+{
+ /* fmul st,st(i) */
+ reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+
+void
+fsub__()
+{
+ /* fsub st,st(i) */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fsubr_()
+{
+ /* fsubr st,st(i) */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+}
+
+
+void
+fdiv__()
+{
+ /* fdiv st,st(i) */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word);
+}
+
+
+void
+fdivr_()
+{
+ /* fdivr st,st(i) */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word);
+}
+
+
+
+void
+fadd_i()
+{
+ /* fadd st(i),st */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fmul_i()
+{
+ /* fmul st(i),st */
+ reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+void
+fsubri()
+{
+ /* fsubr st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm),
+ * FPU_st0_ptr, &st(FPU_rm), control_word); */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fsub_i()
+{
+ /* fsub st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr,
+ * &st(FPU_rm), &st(FPU_rm), control_word); */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+void
+fdivri()
+{
+ /* fdivr st(i),st */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+}
+
+
+void
+fdiv_i()
+{
+ /* fdiv st(i),st */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+}
+
+
+
+void
+faddp_()
+{
+ /* faddp st(i),st */
+ reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fmulp_()
+{
+ /* fmulp st(i),st */
+ reg_mul(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
+
+
+
+void
+fsubrp()
+{
+ /* fsubrp st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(&st(FPU_rm),
+ * FPU_st0_ptr, &st(FPU_rm), control_word); */
+ reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fsubp_()
+{
+ /* fsubp st(i),st */
+ /* This is the sense of the 80486 manual reg_sub(FPU_st0_ptr,
+ * &st(FPU_rm), &st(FPU_rm), control_word); */
+ reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fdivrp()
+{
+ /* fdivrp st(i),st */
+ reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word);
+ pop();
+}
+
+
+void
+fdivp_()
+{
+ /* fdivp st(i),st */
+ reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word);
+ pop();
+}
diff --git a/sys/gnu/arch/i386/fpemul/fpu_asm.h b/sys/gnu/arch/i386/fpemul/fpu_asm.h
new file mode 100644
index 00000000000..bec05b1e587
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_asm.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: fpu_asm.h,v 1.1 1996/08/27 10:32:45 downsj Exp $ */
+/*
+ * fpu_asm.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_asm.h,v 1.3 1994/06/10 07:44:16 rich Exp $
+ *
+ */
+
+#ifndef _FPU_ASM_H_
+#define _FPU_ASM_H_
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+
+#define EXCEPTION _exception
+
+
+#define PARAM1 8(%ebp)
+#define PARAM2 12(%ebp)
+#define PARAM3 16(%ebp)
+#define PARAM4 20(%ebp)
+
+#define SIGL_OFFSET 8
+#define SIGN(x) (x)
+#define TAG(x) 1(x)
+#define EXP(x) 4(x)
+#define SIG(x) SIGL_OFFSET/**/(x)
+#define SIGL(x) SIGL_OFFSET/**/(x)
+#define SIGH(x) 12(x)
+
+#endif /* _FPU_ASM_H_ */
diff --git a/sys/gnu/arch/i386/fpemul/fpu_aux.c b/sys/gnu/arch/i386/fpemul/fpu_aux.c
new file mode 100644
index 00000000000..ae7df9a593a
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_aux.c
@@ -0,0 +1,233 @@
+/* $OpenBSD: fpu_aux.c,v 1.1 1996/08/27 10:32:45 downsj Exp $ */
+/*
+ * fpu_aux.c
+ *
+ * Code to implement some of the FPU auxiliary instructions.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_aux.c,v 1.4 1995/12/14 09:50:21 phk Exp $
+ *
+ */
+
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+
+
+static void
+fclex(void)
+{
+ status_word &= ~(SW_Backward | SW_Summary | SW_Stack_Fault | SW_Precision |
+ SW_Underflow | SW_Overflow | SW_Zero_Div | SW_Denorm_Op |
+ SW_Invalid);
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+}
+/* Needs to be externally visible */
+void
+finit()
+{
+ int r;
+ control_word = 0x037f;
+ status_word = 0;
+ top = 0; /* We don't keep top in the status word
+ * internally. */
+ for (r = 0; r < 8; r++) {
+ regs[r].tag = TW_Empty;
+ }
+ FPU_entry_eip = ip_offset = 0;
+}
+
+static FUNC finit_table[] = {
+ Un_impl, Un_impl, fclex, finit, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+finit_()
+{
+ (finit_table[FPU_rm]) ();
+}
+
+
+static void
+fstsw_ax(void)
+{
+
+ status_word &= ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+
+ *(short *) &FPU_EAX = status_word;
+
+}
+
+static FUNC fstsw_table[] = {
+ fstsw_ax, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+fstsw_()
+{
+ (fstsw_table[FPU_rm]) ();
+}
+
+
+
+static void
+fnop(void)
+{
+}
+
+static FUNC fp_nop_table[] = {
+ fnop, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl, Un_impl
+};
+
+void
+fp_nop()
+{
+ (fp_nop_table[FPU_rm]) ();
+}
+
+
+void
+fld_i_()
+{
+ FPU_REG *st_new_ptr;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ /* fld st(i) */
+ if (NOT_EMPTY(FPU_rm)) {
+ reg_move(&st(FPU_rm), st_new_ptr);
+ push();
+ } else {
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ push();
+ stack_underflow();
+ } else
+ EXCEPTION(EX_StackUnder);
+ }
+
+}
+
+
+void
+fxch_i()
+{
+ /* fxch st(i) */
+ FPU_REG t;
+ register FPU_REG *sti_ptr = &st(FPU_rm);
+
+ if (FPU_st0_tag == TW_Empty) {
+ if (sti_ptr->tag == TW_Empty) {
+ stack_underflow();
+ stack_underflow_i(FPU_rm);
+ return;
+ }
+ reg_move(sti_ptr, FPU_st0_ptr);
+ stack_underflow_i(FPU_rm);
+ return;
+ }
+ if (sti_ptr->tag == TW_Empty) {
+ reg_move(FPU_st0_ptr, sti_ptr);
+ stack_underflow();
+ return;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ reg_move(sti_ptr, FPU_st0_ptr);
+ reg_move(&t, sti_ptr);
+}
+
+
+void
+ffree_()
+{
+ /* ffree st(i) */
+ st(FPU_rm).tag = TW_Empty;
+}
+
+
+void
+ffreep()
+{
+ /* ffree st(i) + pop - unofficial code */
+ st(FPU_rm).tag = TW_Empty;
+ pop();
+}
+
+
+void
+fst_i_()
+{
+ /* fst st(i) */
+ reg_move(FPU_st0_ptr, &st(FPU_rm));
+}
+
+
+void
+fstp_i()
+{
+ /* fstp st(i) */
+ reg_move(FPU_st0_ptr, &st(FPU_rm));
+ pop();
+}
diff --git a/sys/gnu/arch/i386/fpemul/fpu_emu.h b/sys/gnu/arch/i386/fpemul/fpu_emu.h
new file mode 100644
index 00000000000..e6e0890a99d
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_emu.h
@@ -0,0 +1,189 @@
+/* $OpenBSD: fpu_emu.h,v 1.1 1996/08/27 10:32:46 downsj Exp $ */
+/*
+ * fpu_emu.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_emu.h,v 1.3 1994/06/10 07:44:19 rich Exp $
+ *
+ */
+
+
+#ifndef _FPU_EMU_H_
+#define _FPU_EMU_H_
+
+/*
+ * Define DENORM_OPERAND to make the emulator detect denormals
+ * and use the denormal flag of the status word. Note: this only
+ * affects the flag and corresponding interrupt, the emulator
+ * will always generate denormals and operate upon them as required.
+ */
+#define DENORM_OPERAND
+
+/*
+ * Define PECULIAR_486 to get a closer approximation to 80486 behaviour,
+ * rather than behaviour which appears to be cleaner.
+ * This is a matter of opinion: for all I know, the 80486 may simply
+ * be complying with the IEEE spec. Maybe one day I'll get to see the
+ * spec...
+ */
+#define PECULIAR_486
+
+#ifdef _LOCORE
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#define Const(x) $/**/x
+#else
+#define Const(x) x
+#endif
+
+#define EXP_BIAS Const(0)
+#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */
+#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */
+
+#define SIGN_POS Const(0)
+#define SIGN_NEG Const(1)
+
+/* Keep the order TW_Valid, TW_Zero, TW_Denormal */
+#define TW_Valid Const(0)/* valid */
+#define TW_Zero Const(1)/* zero */
+/* The following fold to 2 (Special) in the Tag Word */
+#define TW_Denormal Const(4)/* De-normal */
+#define TW_Infinity Const(5)/* + or - infinity */
+#define TW_NaN Const(6)/* Not a Number */
+
+#define TW_Empty Const(7)/* empty */
+
+ /* #define TW_FPU_Interrupt Const(0x80) *//* Signals an interrupt */
+
+
+#ifndef _LOCORE
+
+#include <sys/types.h>
+#include <gnu/arch/i386/fpemul/math_emu.h>
+
+#ifdef PARANOID
+extern char emulating;
+#define REENTRANT_CHECK(state) emulating = (state)
+#define ON 1
+#define OFF 0
+#else
+#define REENTRANT_CHECK(state)
+#endif /* PARANOID */
+
+typedef void (*FUNC) (void);
+typedef struct fpu_reg FPU_REG;
+
+#define st(x) ( regs[((top+x) &7 )] )
+
+#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty)
+#define NOT_EMPTY(i) (st(i).tag != TW_Empty)
+#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty)
+
+extern unsigned char FPU_rm;
+
+extern char FPU_st0_tag;
+extern FPU_REG *FPU_st0_ptr;
+
+extern void *FPU_data_address;
+
+extern FPU_REG FPU_loaded_data;
+
+#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; }
+
+/* push() does not affect the tags */
+#define push() { top--; FPU_st0_ptr = st_new_ptr; }
+
+
+#define reg_move(x, y) { \
+ *(short *)&((y)->sign) = *(short *)&((x)->sign); \
+ *(long *)&((y)->exp) = *(long *)&((x)->exp); \
+ *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); }
+
+
+/*----- Prototypes for functions written in assembler -----*/
+/* extern void reg_move(FPU_REG *a, FPU_REG *b); */
+
+extern void mul64(long long *a, long long *b, long long *result);
+extern void poly_div2(long long *x);
+extern void poly_div4(long long *x);
+extern void poly_div16(long long *x);
+extern void
+polynomial(unsigned accum[], unsigned x[],
+ unsigned short terms[][4], int n);
+ extern void normalize(FPU_REG * x);
+ extern void normalize_nuo(FPU_REG * x);
+ extern void reg_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_sub(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_mul(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_div(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void reg_u_add(FPU_REG * arg1, FPU_REG * arg2, FPU_REG * answ,
+ unsigned int control_w);
+ extern void wm_sqrt(FPU_REG * n, unsigned int control_w);
+ extern unsigned shrx(void *l, unsigned x);
+ extern unsigned shrxs(void *v, unsigned x);
+ extern unsigned long div_small(unsigned long long *x, unsigned long y);
+ extern void round_reg(FPU_REG * arg, unsigned int extent,
+ unsigned int control_w);
+
+#ifndef MAKING_PROTO
+#include <gnu/arch/i386/fpemul/fpu_proto.h>
+#endif
+
+#endif /* _LOCORE */
+
+#endif /* _FPU_EMU_H_ */
diff --git a/sys/gnu/arch/i386/fpemul/fpu_entry.c b/sys/gnu/arch/i386/fpemul/fpu_entry.c
new file mode 100644
index 00000000000..20b784b56d4
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_entry.c
@@ -0,0 +1,554 @@
+/* $OpenBSD: fpu_entry.c,v 1.1 1996/08/27 10:32:47 downsj Exp $ */
+/*
+ * fpu_entry.c
+ *
+ * The entry function for wm-FPU-emu
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ * $FreeBSD: fpu_entry.c,v 1.8 1995/12/14 20:21:49 bde Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | math_emulate() is the sole entry point for wm-FPU-emu |
+ +---------------------------------------------------------------------------*/
+
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/kernel.h>
+
+#if defined(LKM) && defined(__FreeBSD__)
+#include <sys/lkm.h>
+#endif
+
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+
+
+#define __BAD__ Un_impl /* Not implemented */
+
+#define FPU_LOOKAHEAD 1 /* For performance boost */
+
+#if FPU_LOOKAHEAD != 0 /* I think thet we have to limit the */
+#define LOOKAHEAD_LIMIT 7 /* Max number of lookahead instructions*/
+#endif /* Or else a prog consisting of a million */
+ /* fnops will spend all its time in kernel*/
+
+#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by
+ * default. */
+
+/* WARNING: These codes are not documented by Intel in their 80486 manual
+ and may not work on FPU clones or later Intel FPUs. */
+
+/* Changes to support the un-doc codes provided by Linus Torvalds. */
+
+#define _d9_d8_ fstp_i /* unofficial code (19) */
+#define _dc_d0_ fcom_st /* unofficial code (14) */
+#define _dc_d8_ fcompst /* unofficial code (1c) */
+#define _dd_c8_ fxch_i /* unofficial code (0d) */
+#define _de_d0_ fcompst /* unofficial code (16) */
+#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */
+#define _df_c8_ fxch_i /* unofficial code (0f) */
+#define _df_d0_ fstp_i /* unofficial code (17) */
+#define _df_d8_ fstp_i /* unofficial code (1f) */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_,
+ fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_,
+ fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+#else /* Support only documented FPU op-codes */
+
+static FUNC st_instr_table[64] = {
+ fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__,
+ fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__,
+ fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__,
+ fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__,
+ fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_,
+ fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__,
+ fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__,
+ fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__,
+};
+#endif /* NO_UNDOC_CODE */
+
+
+#define _NONE_ 0 /* Take no special action */
+#define _REG0_ 1 /* Need to check for not empty st(0) */
+#define _REGI_ 2 /* Need to check for not empty st(0) and
+ * st(rm) */
+#define _REGi_ 0 /* Uses st(rm) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */
+#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm)
+ * then pop */
+#define _REGIc 0 /* Compare st(0) and st(rm) */
+#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks
+ * later */
+
+#ifndef NO_UNDOC_CODE
+
+/* Un-documented FPU op-codes supported by default. (see above) */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_,
+ _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+#else /* Support only documented FPU op-codes */
+
+static unsigned char type_table[64] = {
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_,
+ _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_,
+ _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_,
+ _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_,
+ _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_,
+ _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_
+};
+#endif /* NO_UNDOC_CODE */
+
+/* Be careful when using any of these global variables...
+ they might change if swapping is triggered */
+unsigned char FPU_rm;
+char FPU_st0_tag;
+FPU_REG *FPU_st0_ptr;
+
+#ifdef PARANOID
+char emulating = 0;
+#endif /* PARANOID */
+
+#define bswapw(x) __asm__("xchgb %%al,%%ah":"=a" (x):"0" ((short)x))
+#define math_abort(signo) \
+ FPU_EIP = FPU_ORIG_EIP;REENTRANT_CHECK(OFF);return(signo);
+
+#if defined(__FreeBSD__)
+static int
+#else
+int
+#endif
+math_emulate(struct trapframe * tframe)
+{
+
+ unsigned char FPU_modrm;
+ unsigned short code;
+#ifdef LOOKAHEAD_LIMIT
+ int lookahead_limit = LOOKAHEAD_LIMIT;
+#endif
+#ifdef PARANOID
+ if (emulating) {
+ printf("ERROR: wm-FPU-emu is not RE-ENTRANT!\n");
+ }
+ REENTRANT_CHECK(ON);
+#endif /* PARANOID */
+
+#if defined(__FreeBSD__)
+ if ((((struct pcb *) curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
+ finit();
+ control_word = __INITIAL_NPXCW__;
+ ((struct pcb *) curproc->p_addr)->pcb_flags |= FP_SOFTFP;
+ }
+#else
+ if (!USERMODE(tframe->tf_cs, tframe->tf_eflags))
+ panic("math emulator called from supervisor mode");
+
+ /* ever used fp? */
+ if ((curproc->p_md.md_flags & MDP_USEDFPU) == 0) {
+ curproc->p_md.md_flags |= MDP_USEDFPU;
+ finit();
+ control_word = __INITIAL_NPXCW__;
+ }
+#endif
+ FPU_info = tframe;
+ FPU_ORIG_EIP = FPU_EIP; /* --pink-- */
+
+#if defined(__FreeBSD__)
+ if (FPU_CS != 0x001f) {
+ printf("math_emulate: %x : %x\n", FPU_CS, FPU_EIP);
+ panic("FPU emulation in kernel");
+ }
+#endif
+#ifdef notyet
+ /* We cannot handle emulation in v86-mode */
+ if (FPU_EFLAGS & 0x00020000) {
+ FPU_ORIG_EIP = FPU_EIP;
+ math_abort(FPU_info, SIGILL);
+ }
+#endif
+
+ FPU_lookahead = FPU_LOOKAHEAD;
+ if (curproc->p_flag & P_TRACED)
+ FPU_lookahead = 0;
+
+do_another_FPU_instruction:
+
+ REENTRANT_CHECK(OFF);
+ code = fuword((u_int *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ if ((code & 0xff) == 0x9b) { /* fwait */
+ if (status_word & SW_Summary)
+ goto do_the_FPU_interrupt;
+ else {
+ FPU_EIP++;
+ goto FPU_instruction_done;
+ }
+ }
+ if (status_word & SW_Summary) {
+ /* Ignore the error for now if the current instruction is a
+ * no-wait control instruction */
+ /* The 80486 manual contradicts itself on this topic, so I use
+ * the following list of such instructions until I can check
+ * on a real 80486: fninit, fnstenv, fnsave, fnstsw, fnstenv,
+ * fnclex. */
+ if (!((((code & 0xf803) == 0xe003) || /* fnclex, fninit,
+ * fnstsw */
+ (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw,
+ * fnstenv, fnstsw */
+ ((code & 0xc000) != 0xc000))))) {
+ /* This is a guess about what a real FPU might do to
+ * this bit: */
+/* status_word &= ~SW_Summary; ****/
+
+ /* We need to simulate the action of the kernel to FPU
+ * interrupts here. Currently, the "real FPU" part of
+ * the kernel (0.99.10) clears the exception flags,
+ * sets the registers to empty, and passes information
+ * back to the interrupted process via the cs selector
+ * and operand selector, so we do the same. */
+ do_the_FPU_interrupt:
+ cs_selector &= 0xffff0000;
+ cs_selector |= (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift);
+ operand_selector = tag_word();
+ status_word = 0;
+ top = 0;
+ {
+ int r;
+ for (r = 0; r < 8; r++) {
+ regs[r].tag = TW_Empty;
+ }
+ }
+ REENTRANT_CHECK(OFF);
+ math_abort(SIGFPE);
+ }
+ }
+ FPU_entry_eip = FPU_ORIG_EIP = FPU_EIP;
+
+ if ((code & 0xff) == 0x66) { /* size prefix */
+ FPU_EIP++;
+ REENTRANT_CHECK(OFF);
+ code = fuword((u_int *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ }
+ FPU_EIP += 2;
+
+ FPU_modrm = code >> 8;
+ FPU_rm = FPU_modrm & 7;
+
+ if (FPU_modrm < 0300) {
+ /* All of these instructions use the mod/rm byte to get a data
+ * address */
+ get_address(FPU_modrm);
+ if (!(code & 1)) {
+ unsigned short status1 = status_word;
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+
+ /* Stack underflow has priority */
+ if (NOT_EMPTY_0) {
+ switch ((code >> 1) & 3) {
+ case 0:
+ reg_load_single();
+ break;
+ case 1:
+ reg_load_int32();
+ break;
+ case 2:
+ reg_load_double();
+ break;
+ case 3:
+ reg_load_int16();
+ break;
+ }
+
+ /* No more access to user memory, it is safe
+ * to use static data now */
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+
+ /* NaN operands have the next priority. */
+ /* We have to delay looking at st(0) until
+ * after loading the data, because that data
+ * might contain an SNaN */
+ if ((FPU_st0_tag == TW_NaN) ||
+ (FPU_loaded_data.tag == TW_NaN)) {
+ /* Restore the status word; we might
+ * have loaded a denormal. */
+ status_word = status1;
+ if ((FPU_modrm & 0x30) == 0x10) {
+ /* fcom or fcomp */
+ EXCEPTION(EX_Invalid);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (FPU_modrm & 0x08)
+ pop(); /* fcomp, so we pop. */
+ } else
+ real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr);
+ goto reg_mem_instr_done;
+ }
+ switch ((FPU_modrm >> 3) & 7) {
+ case 0: /* fadd */
+ reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 1: /* fmul */
+ reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 2: /* fcom */
+ compare_st_data();
+ break;
+ case 3: /* fcomp */
+ compare_st_data();
+ pop();
+ break;
+ case 4: /* fsub */
+ reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 5: /* fsubr */
+ reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word);
+ break;
+ case 6: /* fdiv */
+ reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, control_word);
+ break;
+ case 7: /* fdivr */
+ if (FPU_st0_tag == TW_Zero)
+ status_word = status1; /* Undo any denorm tag,
+ * zero-divide has
+ * priority. */
+ reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, control_word);
+ break;
+ }
+ } else {
+ if ((FPU_modrm & 0x30) == 0x10) {
+ /* The instruction is fcom or fcomp */
+ EXCEPTION(EX_StackUnder);
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (FPU_modrm & 0x08)
+ pop(); /* fcomp, Empty or not,
+ * we pop. */
+ } else
+ stack_underflow();
+ }
+ } else {
+ load_store_instr(((FPU_modrm & 0x38) | (code & 6)) >> 1);
+ }
+
+reg_mem_instr_done:
+
+ data_operand_offset = (unsigned long) FPU_data_address;
+ } else {
+ /* None of these instructions access user memory */
+ unsigned char instr_index = (FPU_modrm & 0x38) | (code & 7);
+
+ FPU_st0_ptr = &st(0);
+ FPU_st0_tag = FPU_st0_ptr->tag;
+ switch (type_table[(int) instr_index]) {
+ case _NONE_: /* also _REGIc: _REGIn */
+ break;
+ case _REG0_:
+ if (!NOT_EMPTY_0) {
+ stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIi:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow_i(FPU_rm);
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGIp:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow_i(FPU_rm);
+ pop();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _REGI_:
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm)) {
+ stack_underflow();
+ goto FPU_instruction_done;
+ }
+ break;
+ case _PUSH_: /* Only used by the fld st(i) instruction */
+ break;
+ case _null_:
+ Un_impl();
+ goto FPU_instruction_done;
+ default:
+ EXCEPTION(EX_INTERNAL | 0x111);
+ goto FPU_instruction_done;
+ }
+ (*st_instr_table[(int) instr_index]) ();
+ }
+
+FPU_instruction_done:
+
+ ip_offset = FPU_entry_eip;
+ bswapw(code);
+ *(1 + (unsigned short *) &cs_selector) = code & 0x7ff;
+
+#ifdef DEBUG
+ REENTRANT_CHECK(OFF);
+ emu_printall();
+ REENTRANT_CHECK(ON);
+#endif /* DEBUG */
+#ifdef LOOKAHEAD_LIMIT
+if (--lookahead_limit)
+#endif
+ if (FPU_lookahead) {
+ unsigned char next;
+
+ /* (This test should generate no machine code) */
+ while (1) {
+ REENTRANT_CHECK(OFF);
+ next = fubyte((u_char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ if (((next & 0xf8) == 0xd8) || (next == 0x9b)) { /* fwait */
+ goto do_another_FPU_instruction;
+ } else
+ if (next == 0x66) { /* size prefix */
+ REENTRANT_CHECK(OFF);
+ next = fubyte((u_char *) (FPU_EIP + 1));
+ REENTRANT_CHECK(ON);
+ if ((next & 0xf8) == 0xd8) {
+ FPU_EIP++;
+ goto do_another_FPU_instruction;
+ }
+ }
+ break;
+ }
+ }
+ REENTRANT_CHECK(OFF);
+ return (0); /* --pink-- */
+}
+
+#if defined(__FreeBSD__)
+#ifdef LKM
+MOD_MISC(gnufpu);
+static int
+gnufpu_load(struct lkm_table *lkmtp, int cmd)
+{
+ if (pmath_emulate) {
+ printf("Math emulator already present\n");
+ return EBUSY;
+ }
+ pmath_emulate = math_emulate;
+ return 0;
+}
+
+static int
+gnufpu_unload(struct lkm_table *lkmtp, int cmd)
+{
+ if (pmath_emulate != math_emulate) {
+ printf("Cannot unload another math emulator\n");
+ return EACCES;
+ }
+ pmath_emulate = 0;
+ return 0;
+}
+
+int
+gnufpu(struct lkm_table *lkmtp, int cmd, int ver)
+{
+ DISPATCH(lkmtp, cmd, ver, gnufpu_load, gnufpu_unload, lkm_nullcmd);
+}
+#else /* !LKM */
+
+static void
+gnufpu_init(void *unused)
+{
+ if (pmath_emulate)
+ printf("Another Math emulator already present\n");
+ else
+ pmath_emulate = math_emulate;
+}
+
+SYSINIT(gnufpu, SI_SUB_CPU, SI_ORDER_ANY, gnufpu_init, NULL);
+
+#endif /* LKM */
+#endif /* __FreeBSD__ */
diff --git a/sys/gnu/arch/i386/fpemul/fpu_etc.c b/sys/gnu/arch/i386/fpemul/fpu_etc.c
new file mode 100644
index 00000000000..8f7dce0b469
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_etc.c
@@ -0,0 +1,176 @@
+/* $OpenBSD: fpu_etc.c,v 1.1 1996/08/27 10:32:48 downsj Exp $ */
+/*
+ * fpu_etc.c
+ *
+ * Implement a few FPU instructions.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_etc.c,v 1.3 1994/06/10 07:44:24 rich Exp $
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+
+
+static void
+fchs(void)
+{
+ if (NOT_EMPTY_0) {
+ FPU_st0_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ status_word &= ~SW_C1;
+ } else
+ stack_underflow();
+}
+
+static void
+fabs(void)
+{
+ if (FPU_st0_tag ^ TW_Empty) {
+ FPU_st0_ptr->sign = SIGN_POS;
+ status_word &= ~SW_C1;
+ } else
+ stack_underflow();
+}
+
+
+static void
+ftst_(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_Zero:
+ setcc(SW_C3);
+ break;
+ case TW_Valid:
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ break;
+ case TW_NaN:
+ setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Infinity:
+ if (FPU_st0_ptr->sign == SIGN_POS)
+ setcc(0);
+ else
+ setcc(SW_C0);
+ EXCEPTION(EX_Invalid);
+ break;
+ case TW_Empty:
+ setcc(SW_C0 | SW_C2 | SW_C3);
+ EXCEPTION(EX_StackUnder);
+ break;
+ default:
+ setcc(SW_C0 | SW_C2 | SW_C3); /* Operand is not comparable */
+ EXCEPTION(EX_INTERNAL | 0x14);
+ break;
+ }
+}
+
+static void
+fxam(void)
+{
+ int c = 0;
+ switch (FPU_st0_tag) {
+ case TW_Empty:
+ c = SW_C3 | SW_C0;
+ break;
+ case TW_Zero:
+ c = SW_C3;
+ break;
+ case TW_Valid:
+ /* This will need to be changed if TW_Denormal is ever used. */
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ c = SW_C2 | SW_C3; /* Denormal */
+ else
+ c = SW_C3;
+ break;
+ case TW_NaN:
+ c = SW_C0;
+ break;
+ case TW_Infinity:
+ c = SW_C2 | SW_C0;
+ break;
+ }
+ if (FPU_st0_ptr->sign == SIGN_NEG)
+ c |= SW_C1;
+ setcc(c);
+}
+
+static FUNC fp_etc_table[] = {
+ fchs, fabs, Un_impl, Un_impl, ftst_, fxam, Un_impl, Un_impl
+};
+
+void
+fp_etc()
+{
+ (fp_etc_table[FPU_rm]) ();
+}
diff --git a/sys/gnu/arch/i386/fpemul/fpu_proto.h b/sys/gnu/arch/i386/fpemul/fpu_proto.h
new file mode 100644
index 00000000000..3109271debc
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_proto.h
@@ -0,0 +1,115 @@
+/* $OpenBSD: fpu_proto.h,v 1.1 1996/08/27 10:32:49 downsj Exp $ */
+/*
+ *
+ * $FreeBSD: fpu_proto.h,v 1.5 1995/12/17 21:13:51 phk Exp $
+ *
+ */
+
+
+/* errors.c */
+extern void Un_impl(void);
+extern void emu_printall(void);
+extern void exception(int n);
+extern void real_2op_NaN(FPU_REG * a, FPU_REG * b, FPU_REG * dest);
+extern void arith_invalid(FPU_REG * dest);
+extern void divide_by_zero(int sign, FPU_REG * dest);
+extern void set_precision_flag_up(void);
+extern void set_precision_flag_down(void);
+extern int denormal_operand(void);
+extern void arith_overflow(FPU_REG * dest);
+extern void arith_underflow(FPU_REG * dest);
+extern void stack_overflow(void);
+extern void stack_underflow(void);
+extern void stack_underflow_i(int i);
+extern void stack_underflow_pop(int i);
+/* fpu_arith.c */
+extern void fadd__(void);
+extern void fmul__(void);
+extern void fsub__(void);
+extern void fsubr_(void);
+extern void fdiv__(void);
+extern void fdivr_(void);
+extern void fadd_i(void);
+extern void fmul_i(void);
+extern void fsubri(void);
+extern void fsub_i(void);
+extern void fdivri(void);
+extern void fdiv_i(void);
+extern void faddp_(void);
+extern void fmulp_(void);
+extern void fsubrp(void);
+extern void fsubp_(void);
+extern void fdivrp(void);
+extern void fdivp_(void);
+/* fpu_aux.c */
+extern void finit(void);
+extern void finit_(void);
+extern void fstsw_(void);
+extern void fp_nop(void);
+extern void fld_i_(void);
+extern void fxch_i(void);
+extern void ffree_(void);
+extern void ffreep(void);
+extern void fst_i_(void);
+extern void fstp_i(void);
+/* fpu_entry.c */
+#if 0
+extern int math_emulate(struct trapframe * info);
+#endif
+/* fpu_etc.c */
+extern void fp_etc(void);
+/* fpu_trig.c */
+extern void trig_a(void);
+extern void trig_b(void);
+/* get_address.c */
+extern void get_address(unsigned char FPU_modrm);
+/* load_store.c */
+extern void load_store_instr(char type);
+/* poly_2xm1.c */
+extern int poly_2xm1(FPU_REG * arg, FPU_REG * result);
+/* poly_atan.c */
+extern void poly_atan(FPU_REG * arg);
+/* poly_l2.c */
+extern void poly_l2(FPU_REG * arg, FPU_REG * result);
+extern int poly_l2p1(FPU_REG * arg, FPU_REG * result);
+/* poly_sin.c */
+extern void poly_sine(FPU_REG * arg, FPU_REG * result);
+/* poly_tan.c */
+extern void poly_tan(FPU_REG * arg, FPU_REG * y_reg);
+/* reg_add_sub.c */
+extern void reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w);
+extern void reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w);
+/* reg_compare.c */
+extern int compare(FPU_REG * b);
+extern int compare_st_data(void);
+extern void fcom_st(void);
+extern void fcompst(void);
+extern void fcompp(void);
+extern void fucom_(void);
+extern void fucomp(void);
+extern void fucompp(void);
+/* reg_constant.c */
+extern void fconst(void);
+/* reg_ld_str.c */
+extern void reg_load_extended(void);
+extern void reg_load_double(void);
+extern void reg_load_single(void);
+extern void reg_load_int64(void);
+extern void reg_load_int32(void);
+extern void reg_load_int16(void);
+extern void reg_load_bcd(void);
+extern int reg_store_extended(void);
+extern int reg_store_double(void);
+extern int reg_store_single(void);
+extern int reg_store_int64(void);
+extern int reg_store_int32(void);
+extern int reg_store_int16(void);
+extern int reg_store_bcd(void);
+extern int round_to_int(FPU_REG * r);
+extern char *fldenv(void);
+extern void frstor(void);
+extern unsigned short tag_word(void);
+extern char *fstenv(void);
+extern void fsave(void);
+/* reg_mul.c */
+extern void reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w);
diff --git a/sys/gnu/arch/i386/fpemul/fpu_system.h b/sys/gnu/arch/i386/fpemul/fpu_system.h
new file mode 100644
index 00000000000..5d3a3cebb5c
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_system.h
@@ -0,0 +1,102 @@
+/* $OpenBSD: fpu_system.h,v 1.1 1996/08/27 10:32:49 downsj Exp $ */
+/*
+ * fpu_system.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_system.h,v 1.4 1995/05/30 07:57:51 rgrimes Exp $
+ *
+ */
+
+
+#ifndef _FPU_SYSTEM_H
+#define _FPU_SYSTEM_H
+
+/* system dependent definitions */
+
+/*
+#include <linux/sched.h>
+#include <linux/kernel.h>
+*/
+
+#if defined(__FreeBSD__)
+#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu))
+#else
+#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu.gplemu))
+#endif
+#define FPU_info (I387.soft.frame)
+
+#define FPU_CS (*(unsigned short *) &(FPU_info->tf_cs))
+#define FPU_DS (*(unsigned short *) &(FPU_info->tf_ds))
+#define FPU_EAX (FPU_info->tf_eax)
+#define FPU_EFLAGS (FPU_info->tf_eflags)
+#define FPU_EIP (FPU_info->tf_eip)
+/*#define FPU_ORIG_EIP (FPU_info->___orig_eip) */
+/*#define FPU_ORIG_EIP (FPU_info->tf_isp)*/
+#define FPU_ORIG_EIP (I387.soft.orig_eip)
+
+#define FPU_lookahead (I387.soft.lookahead)
+#define FPU_entry_eip (I387.soft.entry_eip)
+
+#define status_word (I387.soft.swd)
+#define control_word (I387.soft.cwd)
+#define regs (I387.soft.regs)
+#define top (I387.soft.top)
+
+#define ip_offset (I387.soft.fip)
+#define cs_selector (I387.soft.fcs)
+#define data_operand_offset (I387.soft.foo)
+#define operand_selector (I387.soft.fos)
+
+#endif
diff --git a/sys/gnu/arch/i386/fpemul/fpu_trig.c b/sys/gnu/arch/i386/fpemul/fpu_trig.c
new file mode 100644
index 00000000000..8867cb61849
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/fpu_trig.c
@@ -0,0 +1,1370 @@
+/* $OpenBSD: fpu_trig.c,v 1.1 1996/08/27 10:32:50 downsj Exp $ */
+/*
+ * fpu_trig.c
+ *
+ * Implementation of the FPU "transcendental" functions.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: fpu_trig.c,v 1.5 1995/12/17 21:13:58 phk Exp $
+ *
+ */
+
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+static void convert_l2reg(long *arg, FPU_REG * dest);
+
+static int
+trig_arg(FPU_REG * X)
+{
+ FPU_REG tmp, quot;
+ int rv;
+ long long q;
+ int old_cw = control_word;
+
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+
+ reg_move(X, &quot);
+ reg_div(&quot, &CONST_PI2, &quot, FULL_PRECISION);
+
+ reg_move(&quot, &tmp);
+ round_to_int(&tmp);
+ if (tmp.sigh & 0x80000000)
+ return -1; /* |Arg| is >= 2^63 */
+ tmp.exp = EXP_BIAS + 63;
+ q = *(long long *) &(tmp.sigl);
+ normalize(&tmp);
+
+ reg_sub(&quot, &tmp, X, FULL_PRECISION);
+ rv = q & 7;
+
+ control_word = old_cw;
+ return rv;;
+}
+
+
+/* Convert a long to register */
+static void
+convert_l2reg(long *arg, FPU_REG * dest)
+{
+ long num = *arg;
+
+ if (num == 0) {
+ reg_move(&CONST_Z, dest);
+ return;
+ }
+ if (num > 0)
+ dest->sign = SIGN_POS;
+ else {
+ num = -num;
+ dest->sign = SIGN_NEG;
+ }
+
+ dest->sigh = num;
+ dest->sigl = 0;
+ dest->exp = EXP_BIAS + 31;
+ dest->tag = TW_Valid;
+ normalize(dest);
+}
+
+
+static void
+single_arg_error(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_NaN:
+ if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
+ EXCEPTION(EX_Invalid);
+ /* Convert to a QNaN */
+ FPU_st0_ptr->sigh |= 0x40000000;
+ }
+ break; /* return with a NaN in st(0) */
+ case TW_Empty:
+ stack_underflow(); /* Puts a QNaN in st(0) */
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x0112);
+#endif /* PARANOID */
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static void
+f2xm1(void)
+{
+ switch (FPU_st0_tag) {
+ case TW_Valid:
+ {
+ FPU_REG rv, tmp;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ /* poly_2xm1(x) requires 0 < x < 1. */
+ if (poly_2xm1(FPU_st0_ptr, &rv))
+ return; /* error */
+ reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+ } else {
+/* **** Should change poly_2xm1() to at least handle numbers near 0 */
+ /* poly_2xm1(x) doesn't handle negative
+ * numbers. */
+ /* So we compute (poly_2xm1(x+1)-1)/2, for -1
+ * < x < 0 */
+ reg_add(FPU_st0_ptr, &CONST_1, &tmp, FULL_PRECISION);
+ poly_2xm1(&tmp, &rv);
+ reg_mul(&rv, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(&tmp, &CONST_1, FPU_st0_ptr, FULL_PRECISION);
+ FPU_st0_ptr->exp--;
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+ }
+ return;
+ }
+ case TW_Zero:
+ return;
+ case TW_Infinity:
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ /* -infinity gives -1 (p16-10) */
+ reg_move(&CONST_1, FPU_st0_ptr);
+ FPU_st0_ptr->sign = SIGN_NEG;
+ }
+ return;
+ default:
+ single_arg_error();
+ }
+}
+
+static void
+fptan(void)
+{
+ FPU_REG *st_new_ptr;
+ int q;
+ char arg_sign = FPU_st0_ptr->sign;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ switch (FPU_st0_tag) {
+ case TW_Valid:
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ FPU_st0_ptr->sign = SIGN_POS;
+ if ((q = trig_arg(FPU_st0_ptr)) != -1) {
+ if (q & 1)
+ reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+
+ poly_tan(FPU_st0_ptr, FPU_st0_ptr);
+
+ FPU_st0_ptr->sign = (q & 1) ^ arg_sign;
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+
+ push();
+ reg_move(&CONST_1, FPU_st0_ptr);
+ setcc(0);
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ }
+ break;
+ case TW_Infinity:
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ case TW_Zero:
+ push();
+ reg_move(&CONST_1, FPU_st0_ptr);
+ setcc(0);
+ break;
+ default:
+ single_arg_error();
+ break;
+ }
+}
+
+
+static void
+fxtract(void)
+{
+ FPU_REG *st_new_ptr;
+ register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ long e;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ push();
+ reg_move(st1_ptr, FPU_st0_ptr);
+ FPU_st0_ptr->exp = EXP_BIAS;
+ e = st1_ptr->exp - EXP_BIAS;
+ convert_l2reg(&e, st1_ptr);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ char sign = FPU_st0_ptr->sign;
+ divide_by_zero(SIGN_NEG, FPU_st0_ptr);
+ push();
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ char sign = FPU_st0_ptr->sign;
+ FPU_st0_ptr->sign = SIGN_POS;
+ push();
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ if (!(FPU_st0_ptr->sigh & 0x40000000)) { /* Signaling ? */
+ EXCEPTION(EX_Invalid);
+ /* Convert to a QNaN */
+ FPU_st0_ptr->sigh |= 0x40000000;
+ }
+ push();
+ reg_move(st1_ptr, FPU_st0_ptr);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Is this the correct
+ * behaviour? */
+ if (control_word & EX_Invalid) {
+ stack_underflow();
+ push();
+ stack_underflow();
+ } else
+ EXCEPTION(EX_StackUnder);
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x119);
+#endif /* PARANOID */
+}
+
+
+static void
+fdecstp(void)
+{
+ top--; /* FPU_st0_ptr will be fixed in math_emulate()
+ * before the next instr */
+}
+
+static void
+fincstp(void)
+{
+ top++; /* FPU_st0_ptr will be fixed in math_emulate()
+ * before the next instr */
+}
+
+
+static void
+fsqrt_(void)
+{
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ int expon;
+
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ arith_invalid(FPU_st0_ptr); /* sqrt(negative) is
+ * invalid */
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ expon = FPU_st0_ptr->exp - EXP_BIAS;
+ FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0
+ * .. 4.0) */
+
+ wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */
+
+ FPU_st0_ptr->exp += expon >> 1;
+ FPU_st0_ptr->sign = SIGN_POS;
+ } else
+ if (FPU_st0_tag == TW_Zero)
+ return;
+ else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_NEG)
+ arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is
+ * invalid */
+ return;
+ } else {
+ single_arg_error();
+ return;
+ }
+
+}
+
+
+static void
+frndint_(void)
+{
+ if (!(FPU_st0_tag ^ TW_Valid)) {
+ if (FPU_st0_ptr->exp > EXP_BIAS + 63)
+ return;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ round_to_int(FPU_st0_ptr); /* Fortunately, this can't
+ * overflow to 2^64 */
+ FPU_st0_ptr->exp = EXP_BIAS + 63;
+ normalize(FPU_st0_ptr);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity))
+ return;
+ else
+ single_arg_error();
+}
+
+
+static void
+fsin(void)
+{
+ char arg_sign = FPU_st0_ptr->sign;
+
+ if (FPU_st0_tag == TW_Valid) {
+ int q;
+ FPU_st0_ptr->sign = SIGN_POS;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if ((q = trig_arg(FPU_st0_ptr)) != -1) {
+ FPU_REG rv;
+
+ if (q & 1)
+ reg_sub(&CONST_1, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION);
+
+ poly_sine(FPU_st0_ptr, &rv);
+
+ setcc(0);
+ if (q & 2)
+ rv.sign ^= SIGN_POS ^ SIGN_NEG;
+ rv.sign ^= arg_sign;
+ reg_move(&rv, FPU_st0_ptr);
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+
+ set_precision_flag_up(); /* We do not really know
+ * if up or down */
+
+ return;
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ setcc(0);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ FPU_st0_ptr->sign = arg_sign; /* restore st(0) */
+ return;
+ } else
+ single_arg_error();
+}
+
+
+static int
+f_cos(FPU_REG * arg)
+{
+ char arg_sign = arg->sign;
+
+ if (arg->tag == TW_Valid) {
+ int q;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return 1;
+#endif /* DENORM_OPERAND */
+
+ arg->sign = SIGN_POS;
+ if ((q = trig_arg(arg)) != -1) {
+ FPU_REG rv;
+
+ if (!(q & 1))
+ reg_sub(&CONST_1, arg, arg, FULL_PRECISION);
+
+ poly_sine(arg, &rv);
+
+ setcc(0);
+ if ((q + 1) & 2)
+ rv.sign ^= SIGN_POS ^ SIGN_NEG;
+ reg_move(&rv, arg);
+
+ set_precision_flag_up(); /* We do not really know
+ * if up or down */
+
+ return 0;
+ } else {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ arg->sign = arg_sign; /* restore st(0) */
+ return 1;
+ }
+ } else
+ if (arg->tag == TW_Zero) {
+ reg_move(&CONST_1, arg);
+ setcc(0);
+ return 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ /* Operand is out of range */
+ setcc(SW_C2);
+ arg->sign = arg_sign; /* restore st(0) */
+ return 1;
+ } else {
+ single_arg_error(); /* requires arg ==
+ * &st(0) */
+ return 1;
+ }
+}
+
+
+static void
+fcos(void)
+{
+ f_cos(FPU_st0_ptr);
+}
+
+
+static void
+fsincos(void)
+{
+ FPU_REG *st_new_ptr;
+ FPU_REG arg;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ reg_move(FPU_st0_ptr, &arg);
+ if (!f_cos(&arg)) {
+ fsin();
+ push();
+ reg_move(&arg, FPU_st0_ptr);
+ }
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* The following all require two arguments: st(0) and st(1) */
+
+/* remainder of st(0) / st(1) */
+/* Assumes that st(0) and st(1) are both TW_Valid */
+static void
+fprem_kernel(int round)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ FPU_REG tmp;
+ int old_cw = control_word;
+ int expdif = FPU_st0_ptr->exp - (st1_ptr)->exp;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ control_word &= ~CW_RC;
+ control_word |= round;
+
+ if (expdif < 64) {
+ /* This should be the most common case */
+ long long q;
+ int c = 0;
+
+ reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
+
+ round_to_int(&tmp); /* Fortunately, this can't
+ * overflow to 2^64 */
+ tmp.exp = EXP_BIAS + 63;
+ q = *(long long *) &(tmp.sigl);
+ normalize(&tmp);
+
+ reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
+
+ if (q & 4)
+ c |= SW_C3;
+ if (q & 2)
+ c |= SW_C1;
+ if (q & 1)
+ c |= SW_C0;
+
+ setcc(c);
+ } else {
+ /* There is a large exponent difference ( >= 64 ) */
+ int N_exp;
+
+ reg_div(FPU_st0_ptr, st1_ptr, &tmp, FULL_PRECISION);
+ /* N is 'a number between 32 and 63' (p26-113) */
+ N_exp = (tmp.exp & 31) + 32;
+ tmp.exp = EXP_BIAS + N_exp;
+
+ round_to_int(&tmp); /* Fortunately, this can't
+ * overflow to 2^64 */
+ tmp.exp = EXP_BIAS + 63;
+ normalize(&tmp);
+
+ tmp.exp = EXP_BIAS + expdif - N_exp;
+
+ reg_mul(st1_ptr, &tmp, &tmp, FULL_PRECISION);
+ reg_sub(FPU_st0_ptr, &tmp, FPU_st0_ptr, FULL_PRECISION);
+
+ setcc(SW_C2);
+ }
+ control_word = old_cw;
+
+ if (FPU_st0_ptr->exp <= EXP_UNDER)
+ arith_underflow(FPU_st0_ptr);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
+ stack_underflow();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ setcc(0);
+ return;
+ } else
+ if (st1_tag == TW_Zero) {
+ arith_invalid(FPU_st0_ptr);
+ return;
+ }
+ /* fprem(?,0) always invalid */
+ else
+ if (st1_tag == TW_Infinity) {
+ setcc(0);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+ arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is
+ * invalid */
+ return;
+ } else
+ if (st1_tag != TW_NaN) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (st1_tag == TW_Infinity) {
+ /* fprem(Valid,
+ * Infinity)
+ * is o.k. */
+ setcc(0);
+ return;
+ }
+ }
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag != TW_NaN) {
+ arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is
+ * invalid */
+ return;
+ }
+ }
+ /* One of the registers must contain a NaN is we got here. */
+
+#ifdef PARANOID
+ if ((FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN))
+ EXCEPTION(EX_INTERNAL | 0x118);
+#endif /* PARANOID */
+
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+
+}
+
+
+/* ST(1) <- ST(1) * log ST; pop ST */
+static void
+fyl2x(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ int saved_control, saved_status;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic, so we need
+ * to save these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ poly_l2(FPU_st0_ptr, FPU_st0_ptr);
+
+ /* Enough of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ /* Let the multiply set the flags */
+ reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+
+ pop();
+ FPU_st0_ptr = &st(0);
+ } else {
+ /* negative */
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* st(0) cannot be
+ * negative */
+ return;
+ }
+ } else
+ if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero)) {
+ /* one of the args is zero, the other
+ * valid, or both zero */
+ if (FPU_st0_tag == TW_Zero) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ if (FPU_st0_ptr->tag == TW_Zero)
+ arith_invalid(FPU_st0_ptr); /* Both args zero is
+ * invalid */
+#ifdef PECULIAR_486
+ /* This case is not
+ * specifically covered in the
+ * manual, but divide-by-zero
+ * would seem to be the best
+ * response. However, a real
+ * 80486 does it this way... */
+ else
+ if (FPU_st0_ptr->tag == TW_Infinity) {
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ return;
+ }
+#endif /* PECULIAR_486 */
+ else
+ divide_by_zero(st1_ptr->sign ^ SIGN_NEG ^ SIGN_POS, FPU_st0_ptr);
+ return;
+ } else {
+ /* st(1) contains zero, st(0)
+ * valid <> 0 */
+ /* Zero is the valid answer */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* log(negative) */
+ return;
+ }
+ if (FPU_st0_ptr->exp < EXP_BIAS)
+ sign ^= SIGN_NEG ^ SIGN_POS;
+ pop();
+ FPU_st0_ptr = &st(0);
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ }
+ /* One or both arg must be an infinity */
+ else
+ if (FPU_st0_tag == TW_Infinity) {
+ if ((FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* log(-infinity) or
+ * 0*log(infinity) */
+ return;
+ } else {
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ pop();
+ FPU_st0_ptr = &st(0);
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ }
+ /* st(1) must be infinity here */
+ else
+ if ((FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS)) {
+ if (FPU_st0_ptr->exp >= EXP_BIAS) {
+ if ((FPU_st0_ptr->exp == EXP_BIAS) &&
+ (FPU_st0_ptr->sigh == 0x80000000) &&
+ (FPU_st0_ptr->sigl == 0)) {
+ /* st(0
+ * )
+ * hold
+ * s
+ * 1.0 */
+ pop();
+ FPU_st0_ptr = &st(0);
+ arith_invalid(FPU_st0_ptr); /* infinity*log(1) */
+ return;
+ }
+ /* st(0) is
+ * positive
+ * and > 1.0 */
+ pop();
+ } else {
+ /* st(0) is
+ * positive
+ * and < 1.0 */
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ st1_ptr->sign ^= SIGN_NEG;
+ pop();
+ }
+ return;
+ } else {
+ /* st(0) must be zero
+ * or negative */
+ if (FPU_st0_ptr->tag == TW_Zero) {
+ pop();
+ FPU_st0_ptr = st1_ptr;
+ st1_ptr->sign ^= SIGN_NEG ^ SIGN_POS;
+ /* This should
+ * be invalid,
+ * but a real
+ * 80486 is
+ * happy with
+ * it. */
+#ifndef PECULIAR_486
+ divide_by_zero(st1_ptr->sign, FPU_st0_ptr);
+#endif /* PECULIAR_486 */
+ } else {
+ pop();
+ FPU_st0_ptr = st1_ptr;
+ arith_invalid(FPU_st0_ptr); /* log(negative) */
+ }
+ return;
+ }
+}
+
+
+static void
+fpatan(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ int saved_control, saved_status;
+ FPU_REG sum;
+ int quadrant = st1_ptr->sign | ((FPU_st0_ptr->sign) << 1);
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic so we need to save
+ * these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS;
+ if (compare(st1_ptr) == COMP_A_lt_B) {
+ quadrant |= 4;
+ reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION);
+ } else
+ reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION);
+
+ poly_atan(&sum);
+
+ if (quadrant & 4) {
+ reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION);
+ }
+ if (quadrant & 2) {
+ reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION);
+ }
+ if (quadrant & 1)
+ sum.sign ^= SIGN_POS ^ SIGN_NEG;
+
+ /* All of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ reg_move(&sum, st1_ptr);
+ } else
+ if ((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if ((FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN)) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity)) {
+ char sign = st1_ptr->sign;
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_PI4, st1_ptr);
+ } else
+ reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION);
+ } else {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_Z, st1_ptr);
+ pop();
+ return;
+ } else
+ reg_move(&CONST_PI, st1_ptr);
+ }
+ } else {
+ /* st(1) is infinity, st(0)
+ * not infinity */
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ reg_move(&CONST_PI2, st1_ptr);
+ }
+ st1_ptr->sign = sign;
+ } else
+ if (st1_tag == TW_Zero) {
+ /* st(0) must be valid or zero */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign == SIGN_POS) {
+ reg_move(&CONST_Z, st1_ptr);
+ pop();
+ return;
+ } else
+ reg_move(&CONST_PI, st1_ptr);
+ st1_ptr->sign = sign;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ /* st(1) must be
+ * TW_Valid here */
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ reg_move(&CONST_PI2, st1_ptr);
+ st1_ptr->sign = sign;
+ }
+#ifdef PARANOID
+ else
+ EXCEPTION(EX_INTERNAL | 0x220);
+#endif /* PARANOID */
+
+ pop();
+ set_precision_flag_up();/* We do not really know if up or down */
+}
+
+
+static void
+fprem(void)
+{
+ fprem_kernel(RC_CHOP);
+}
+
+
+static void
+fprem1(void)
+{
+ fprem_kernel(RC_RND);
+}
+
+
+static void
+fyl2xp1(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ int saved_control, saved_status;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* We use the general purpose arithmetic so we need to save
+ * these. */
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = FULL_PRECISION;
+
+ if (poly_l2p1(FPU_st0_ptr, FPU_st0_ptr)) {
+ arith_invalid(st1_ptr); /* poly_l2p1() returned
+ * invalid */
+ pop();
+ return;
+ }
+ /* Enough of the basic arithmetic is done now */
+ control_word = saved_control;
+ status_word = saved_status;
+
+ /* Let the multiply set the flags */
+ reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION);
+
+ pop();
+ } else
+ if ((FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty)) {
+ stack_underflow_pop(1);
+ return;
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag <= TW_Zero) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) &&
+ (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ st1_ptr->sign ^= FPU_st0_ptr->sign;
+ reg_move(FPU_st0_ptr, st1_ptr);
+ } else
+ if (st1_tag == TW_Infinity) {
+ arith_invalid(st1_ptr); /* Infinity*log(1) */
+ pop();
+ return;
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x116);
+ return;
+ }
+#endif /* PARANOID */
+ pop();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ if (FPU_st0_ptr->exp >= EXP_BIAS) {
+ /* st(0) holds
+ * <= -1.0 */
+ arith_invalid(st1_ptr); /* infinity*log(1) */
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ pop();
+ return;
+ }
+ if (st1_tag == TW_Infinity) {
+ if (FPU_st0_ptr->sign == SIGN_NEG) {
+ if ((FPU_st0_ptr->exp >= EXP_BIAS) &&
+ !((FPU_st0_ptr->sigh == 0x80000000) &&
+ (FPU_st0_ptr->sigl == 0))) {
+ /* st(0) holds
+ * < -1.0 */
+ arith_invalid(st1_ptr);
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ st1_ptr->sign ^= SIGN_POS ^ SIGN_NEG;
+ pop();
+ return;
+ }
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+ pop();
+ return;
+ }
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr);
+ pop();
+ return;
+ } else
+ if ((FPU_st0_ptr->sign == SIGN_NEG) ||
+ (st1_tag == TW_Zero)) {
+ arith_invalid(st1_ptr); /* log(infinity) */
+ pop();
+ return;
+ }
+ /* st(1) must be valid
+ * here. */
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ /* The Manual says
+ * that log(Infinity)
+ * is invalid, but a
+ * real 80486 sensibly
+ * says that it is
+ * o.k. */
+ {
+ char sign = st1_ptr->sign;
+ reg_move(&CONST_INF, st1_ptr);
+ st1_ptr->sign = sign;
+ }
+ pop();
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x117);
+ }
+#endif /* PARANOID */
+}
+
+
+static void
+emu_fscale(void)
+{
+ FPU_REG *st1_ptr = &st(1);
+ char st1_tag = st1_ptr->tag;
+ int old_cw = control_word;
+
+ if (!((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid))) {
+ long scale;
+ FPU_REG tmp;
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (st1_ptr->exp > EXP_BIAS + 30) {
+ /* 2^31 is far too large, would require 2^(2^30) or
+ * 2^(-2^30) */
+ char sign;
+
+ if (st1_ptr->sign == SIGN_POS) {
+ EXCEPTION(EX_Overflow);
+ sign = FPU_st0_ptr->sign;
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ } else {
+ EXCEPTION(EX_Underflow);
+ sign = FPU_st0_ptr->sign;
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ }
+ return;
+ }
+ control_word &= ~CW_RC;
+ control_word |= RC_CHOP;
+ reg_move(st1_ptr, &tmp);
+ round_to_int(&tmp); /* This can never overflow here */
+ control_word = old_cw;
+ scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl;
+ scale += FPU_st0_ptr->exp;
+ FPU_st0_ptr->exp = scale;
+
+ /* Use round_reg() to properly detect under/overflow etc */
+ round_reg(FPU_st0_ptr, 0, control_word);
+
+ return;
+ } else
+ if (FPU_st0_tag == TW_Valid) {
+ if (st1_tag == TW_Zero) {
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ }
+ if (st1_tag == TW_Infinity) {
+ char sign = st1_ptr->sign;
+
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ if (sign == SIGN_POS) {
+ reg_move(&CONST_INF, FPU_st0_ptr);
+ } else
+ reg_move(&CONST_Z, FPU_st0_ptr);
+ FPU_st0_ptr->sign = sign;
+ return;
+ }
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ } else
+ if (st1_tag == TW_Zero) {
+ return;
+ } else
+ if (st1_tag == TW_Infinity) {
+ if (st1_ptr->sign == SIGN_NEG)
+ return;
+ else {
+ arith_invalid(FPU_st0_ptr); /* Zero scaled by
+ * +Infinity */
+ return;
+ }
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ if (st1_tag == TW_Valid) {
+
+#ifdef DENORM_OPERAND
+ if ((st1_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return;
+#endif /* DENORM_OPERAND */
+
+ return;
+ }
+ if (((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS))
+ || (st1_tag == TW_Zero))
+ return;
+ else
+ if (st1_tag == TW_Infinity) {
+ arith_invalid(FPU_st0_ptr); /* Infinity scaled by
+ * -Infinity */
+ return;
+ } else
+ if (st1_tag == TW_NaN) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ if (st1_tag != TW_Empty) {
+ real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr);
+ return;
+ }
+ }
+#ifdef PARANOID
+ if (!((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty))) {
+ EXCEPTION(EX_INTERNAL | 0x115);
+ return;
+ }
+#endif
+
+ /* At least one of st(0), st(1) must be empty */
+ stack_underflow();
+
+}
+
+
+/*---------------------------------------------------------------------------*/
+
+static FUNC trig_table_a[] = {
+ f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp
+};
+
+void
+trig_a(void)
+{
+ (trig_table_a[FPU_rm]) ();
+}
+
+
+static FUNC trig_table_b[] =
+{
+ fprem, fyl2xp1, fsqrt_, fsincos, frndint_, emu_fscale, fsin, fcos
+};
+
+void
+trig_b(void)
+{
+ (trig_table_b[FPU_rm]) ();
+}
diff --git a/sys/gnu/arch/i386/fpemul/get_address.c b/sys/gnu/arch/i386/fpemul/get_address.c
new file mode 100644
index 00000000000..3232e685c68
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/get_address.c
@@ -0,0 +1,204 @@
+/* $OpenBSD: get_address.c,v 1.1 1996/08/27 10:32:51 downsj Exp $ */
+/*
+ * get_address.c
+ *
+ * Get the effective address from an FPU instruction.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: get_address.c,v 1.3 1994/06/10 07:44:29 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+#include <machine/reg.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+
+static int reg_offset[] = {
+tEAX, tECX, tEDX, tEBX, tESP, tEBP, tESI, tEDI};
+#define REG_(x) (*(((int*)FPU_info) + reg_offset[(x)]))
+
+void *FPU_data_address;
+
+
+/* Decode the SIB byte. This function assumes mod != 0 */
+static void *
+sib(int mod)
+{
+ unsigned char ss, index, base;
+ long offset;
+
+ REENTRANT_CHECK(OFF);
+ base = fubyte((char *) FPU_EIP); /* The SIB byte */
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ ss = base >> 6;
+ index = (base >> 3) & 7;
+ base &= 7;
+
+ if ((mod == 0) && (base == 5))
+ offset = 0; /* No base register */
+ else
+ offset = REG_(base);
+
+ if (index == 4) {
+ /* No index register */
+ /* A non-zero ss is illegal */
+ if (ss)
+ EXCEPTION(EX_Invalid);
+ } else {
+ offset += (REG_(index)) << ss;
+ }
+
+ if (mod == 1) {
+ /* 8 bit signed displacement */
+ REENTRANT_CHECK(OFF);
+ offset += (signed char) fubyte((char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ } else
+ if (mod == 2 || base == 5) { /* The second condition also
+ * has mod==0 */
+ /* 32 bit displacment */
+ REENTRANT_CHECK(OFF);
+ offset += (signed) fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ }
+ return (void *) offset;
+}
+
+
+/*
+ MOD R/M byte: MOD == 3 has a special use for the FPU
+ SIB byte used iff R/M = 100b
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ MOD OPCODE(2) R/M
+
+
+ SIB byte
+
+ 7 6 5 4 3 2 1 0
+ ..... ......... .........
+ SS INDEX BASE
+
+*/
+
+void
+get_address(unsigned char FPU_modrm)
+{
+ unsigned char mod;
+ long *cpu_reg_ptr;
+ int offset = 0; /* Initialized just to stop compiler warnings. */
+
+ mod = (FPU_modrm >> 6) & 3;
+
+ if (FPU_rm == 4 && mod != 3) {
+ FPU_data_address = sib(mod);
+ return;
+ }
+ cpu_reg_ptr = (long *) &REG_(FPU_rm);
+ switch (mod) {
+ case 0:
+ if (FPU_rm == 5) {
+ /* Special case: disp32 */
+ REENTRANT_CHECK(OFF);
+ offset = fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ FPU_data_address = (void *) offset;
+ return;
+ } else {
+ FPU_data_address = (void *) *cpu_reg_ptr; /* Just return the
+ * contents of the cpu
+ * register */
+ return;
+ }
+ case 1:
+ /* 8 bit signed displacement */
+ REENTRANT_CHECK(OFF);
+ offset = (signed char) fubyte((char *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP++;
+ break;
+ case 2:
+ /* 32 bit displacement */
+ REENTRANT_CHECK(OFF);
+ offset = (signed) fuword((unsigned long *) FPU_EIP);
+ REENTRANT_CHECK(ON);
+ FPU_EIP += 4;
+ break;
+ case 3:
+ /* Not legal for the FPU */
+ EXCEPTION(EX_Invalid);
+ }
+
+ FPU_data_address = offset + (char *) *cpu_reg_ptr;
+}
diff --git a/sys/gnu/arch/i386/fpemul/load_store.c b/sys/gnu/arch/i386/fpemul/load_store.c
new file mode 100644
index 00000000000..9b3ffd9a13a
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/load_store.c
@@ -0,0 +1,273 @@
+/* $OpenBSD: load_store.c,v 1.1 1996/08/27 10:32:52 downsj Exp $ */
+/*
+ * load_store.c
+ *
+ * This file contains most of the code to interpret the FPU instructions
+ * which load and store from user memory.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: load_store.c,v 1.5 1996/06/25 20:29:21 bde Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#if defined(__FreeBSD__)
+#include <machine/md_var.h>
+#endif
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+
+
+#define _NONE_ 0 /* FPU_st0_ptr etc not needed */
+#define _REG0_ 1 /* Will be storing st(0) */
+#define _PUSH_ 3 /* Need to check for space to push onto stack */
+#define _null_ 4 /* Function illegal or not implemented */
+
+#define pop_0() { pop_ptr->tag = TW_Empty; top++; }
+
+
+static unsigned char type_table[32] = {
+ _PUSH_, _PUSH_, _PUSH_, _PUSH_,
+ _null_, _null_, _null_, _null_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _REG0_, _REG0_, _REG0_, _REG0_,
+ _NONE_, _null_, _NONE_, _PUSH_,
+ _NONE_, _PUSH_, _null_, _PUSH_,
+ _NONE_, _null_, _NONE_, _REG0_,
+ _NONE_, _REG0_, _NONE_, _REG0_
+};
+
+void
+load_store_instr(char type)
+{
+ FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which
+ * won't change. */
+
+ pop_ptr = NULL; /* Initialized just to stop compiler warnings. */
+
+
+ switch (type_table[(int) (unsigned) type]) {
+ case _NONE_:
+ break;
+ case _REG0_:
+ pop_ptr = &st(0); /* Some of these instructions pop
+ * after storing */
+
+ FPU_st0_ptr = pop_ptr; /* Set the global variables. */
+ FPU_st0_tag = FPU_st0_ptr->tag;
+ break;
+ case _PUSH_:
+ {
+ pop_ptr = &st(-1);
+ if (pop_ptr->tag != TW_Empty) {
+ stack_overflow();
+ return;
+ }
+ top--;
+ }
+ break;
+ case _null_:
+ return Un_impl();
+#ifdef PARANOID
+ default:
+ return EXCEPTION(EX_INTERNAL);
+#endif /* PARANOID */
+ }
+
+ switch (type) {
+ case 000: /* fld m32real */
+ reg_load_single();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 001: /* fild m32int */
+ reg_load_int32();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 002: /* fld m64real */
+ reg_load_double();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 003: /* fild m16int */
+ reg_load_int16();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 010: /* fst m32real */
+ reg_store_single();
+ break;
+ case 011: /* fist m32int */
+ reg_store_int32();
+ break;
+ case 012: /* fst m64real */
+ reg_store_double();
+ break;
+ case 013: /* fist m16int */
+ reg_store_int16();
+ break;
+ case 014: /* fstp m32real */
+ if (reg_store_single())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 015: /* fistp m32int */
+ if (reg_store_int32())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 016: /* fstp m64real */
+ if (reg_store_double())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 017: /* fistp m16int */
+ if (reg_store_int16())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 020: /* fldenv m14/28byte */
+ fldenv();
+ break;
+ case 022: /* frstor m94/108byte */
+ frstor();
+ break;
+ case 023: /* fbld m80dec */
+ reg_load_bcd();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 024: /* fldcw */
+ REENTRANT_CHECK(OFF);
+ control_word = fusword((unsigned short *) FPU_data_address);
+ REENTRANT_CHECK(ON);
+#ifdef NO_UNDERFLOW_TRAP
+ if (!(control_word & EX_Underflow)) {
+ control_word |= EX_Underflow;
+ }
+#endif
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 025: /* fld m80real */
+ reg_load_extended();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 027: /* fild m64int */
+ reg_load_int64();
+ setcc(0); /* Clear the SW_C1 bit, "other bits undefined" */
+ reg_move(&FPU_loaded_data, pop_ptr);
+ break;
+ case 030: /* fstenv m14/28byte */
+ fstenv();
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 032: /* fsave */
+ fsave();
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 033: /* fbstp m80dec */
+ if (reg_store_bcd())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 034: /* fstcw m16int */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
+ susword( (short *) FPU_data_address,control_word);
+ REENTRANT_CHECK(ON);
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 035: /* fstp m80real */
+ if (reg_store_extended())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ case 036: /* fstsw m2byte */
+ status_word &= ~SW_Top;
+ status_word |= (top & 7) << SW_Top_Shift;
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, FPU_data_address, 2);*/
+ susword( (short *) FPU_data_address,status_word);
+ REENTRANT_CHECK(ON);
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+ break;
+ case 037: /* fistp m64int */
+ if (reg_store_int64())
+ pop_0();/* pop only if the number was actually stored
+ * (see the 80486 manual p16-28) */
+ break;
+ }
+}
diff --git a/sys/gnu/arch/i386/fpemul/math_emu.h b/sys/gnu/arch/i386/fpemul/math_emu.h
new file mode 100644
index 00000000000..9709e3aa270
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/math_emu.h
@@ -0,0 +1,48 @@
+/* $OpenBSD: math_emu.h,v 1.1 1996/08/27 10:32:52 downsj Exp $ */
+/*
+ *
+ * $FreeBSD: math_emu.h,v 1.2 1994/04/29 21:23:24 gclarkii Exp $
+ *
+ */
+
+#ifndef _MATH_EMU_H
+#define _MATH_EMU_H
+
+struct fpu_reg {
+ char sign;
+ char tag;
+ long exp;
+ u_long sigl;
+ u_long sigh;
+};
+
+union i387_union {
+ struct i387_hard_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long st_space[20]; /* 8*10 bytes for each FP-reg = 80
+ * bytes */
+ } hard;
+ struct i387_soft_struct {
+ long cwd;
+ long swd;
+ long twd;
+ long fip;
+ long fcs;
+ long foo;
+ long fos;
+ long top;
+ struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128
+ * bytes */
+ unsigned char lookahead;
+ struct trapframe *frame;
+ unsigned long entry_eip;
+ int orig_eip;
+ } soft;
+};
+#endif
diff --git a/sys/gnu/arch/i386/fpemul/poly_2xm1.c b/sys/gnu/arch/i386/fpemul/poly_2xm1.c
new file mode 100644
index 00000000000..7a668ac4a9e
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_2xm1.c
@@ -0,0 +1,142 @@
+/* $OpenBSD: poly_2xm1.c,v 1.1 1996/08/27 10:32:52 downsj Exp $ */
+/*
+ * poly_2xm1.c
+ *
+ * Function to compute 2^x-1 by a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_2xm1.c,v 1.3 1994/06/10 07:44:32 rich Exp $
+ *
+ */
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+
+
+
+#define HIPOWER 13
+static unsigned short lterms[HIPOWER][4] =
+{
+ {0x79b5, 0xd1cf, 0x17f7, 0xb172},
+ {0x1b56, 0x058b, 0x7bff, 0x3d7f},
+ {0x8bb0, 0x8250, 0x846b, 0x0e35},
+ {0xbc65, 0xf747, 0x556d, 0x0276},
+ {0x17cb, 0x9e39, 0x61ff, 0x0057},
+ {0xe018, 0x9776, 0x1848, 0x000a},
+ {0x66f2, 0xff30, 0xffe5, 0x0000},
+ {0x682f, 0xffb6, 0x162b, 0x0000},
+ {0xb7ca, 0x2956, 0x01b5, 0x0000},
+ {0xcd3e, 0x4817, 0x001e, 0x0000},
+ {0xb7e2, 0xecbe, 0x0001, 0x0000},
+ {0x0ed5, 0x1a27, 0x0000, 0x0000},
+ {0x101d, 0x0222, 0x0000, 0x0000},
+};
+
+
+/*--- poly_2xm1() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+int
+poly_2xm1(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ long long Xll;
+ FPU_REG accum;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, result);
+ return 0;
+ }
+ if (exponent >= 0) { /* Can't hack a number >= 1.0 */
+ arith_invalid(result); /* Number too large */
+ return 1;
+ }
+ if (arg->sign != SIGN_POS) { /* Can't hack a number < 0.0 */
+ arith_invalid(result); /* Number negative */
+ return 1;
+ }
+ if (exponent < -64) {
+ reg_move(&CONST_LN2, result);
+ return 0;
+ }
+ *(unsigned *) &Xll = arg->sigl;
+ *(((unsigned *) &Xll) + 1) = arg->sigh;
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&Xll, -1 - exponent) >= (unsigned)0x80000000)
+ Xll++; /* round up */
+ }
+ *(short *) &(accum.sign) = 0; /* will be a valid positive nr with
+ * expon = 0 */
+ accum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((unsigned *) &accum.sigl, (unsigned *) &Xll, lterms, HIPOWER - 1);
+
+ /* Convert to 64 bit signed-compatible */
+ accum.exp += EXP_BIAS - 1;
+
+ reg_move(&accum, result);
+
+ normalize(result);
+
+ return 0;
+
+}
diff --git a/sys/gnu/arch/i386/fpemul/poly_atan.c b/sys/gnu/arch/i386/fpemul/poly_atan.c
new file mode 100644
index 00000000000..5d8fc2d8ff5
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_atan.c
@@ -0,0 +1,254 @@
+/* $OpenBSD: poly_atan.c,v 1.1 1996/08/27 10:32:53 downsj Exp $ */
+/*
+ * p_atan.c
+ *
+ * Compute the tan of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_atan.c,v 1.5 1995/12/14 09:50:24 phk Exp $
+ *
+ */
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+#define HIPOWERon 6 /* odd poly, negative terms */
+static unsigned oddnegterms[HIPOWERon][2] =
+{
+ {0x00000000, 0x00000000}, /* for + 1.0 */
+ {0x763b6f3d, 0x1adc4428},
+ {0x20f0630b, 0x0502909d},
+ {0x4e825578, 0x0198ce38},
+ {0x22b7cb87, 0x008da6e3},
+ {0x9b30ca03, 0x00239c79}
+};
+#define HIPOWERop 6 /* odd poly, positive terms */
+static unsigned oddplterms[HIPOWERop][2] =
+{
+ {0xa6f67cb8, 0x94d910bd},
+ {0xa02ffab4, 0x0a43cb45},
+ {0x04265e6b, 0x02bf5655},
+ {0x0a728914, 0x00f280f7},
+ {0x6d640e01, 0x004d6556},
+ {0xf1dd2dbf, 0x000a530a}
+};
+
+
+static unsigned denomterm[2] =
+{0xfc4bd208, 0xea2e6612};
+
+
+static void poly_add_1(FPU_REG * src);
+
+/*--- poly_atan() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_atan(FPU_REG * arg)
+{
+ char recursions = 0;
+ short exponent;
+ FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
+ FPU_REG argSq;
+ long long arg_signif, argSqSq;
+
+
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ arith_invalid(arg);
+ return;
+ } /* Need a positive number */
+#endif /* PARANOID */
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, arg);
+ return;
+ }
+ if (exponent >= -2) {
+ /* argument is in the range [0.25 .. 1.0] */
+ if (exponent >= 0) {
+#ifdef PARANOID
+ if ((exponent == 0) &&
+ (arg->sigl == 0) && (arg->sigh == 0x80000000))
+#endif /* PARANOID */
+ {
+ reg_move(&CONST_PI4, arg);
+ return;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic
+ * error */
+#endif /* PARANOID */
+ }
+ /* If the argument is greater than sqrt(2)-1 (=0.414213562...) */
+ /* convert the argument by an identity for atan */
+ if ((exponent >= -1) || (arg->sigh > 0xd413ccd0)) {
+ FPU_REG numerator, denom;
+
+ recursions++;
+
+ arg_signif = *(long long *) &(arg->sigl);
+ if (exponent < -1) {
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ }
+ *(long long *) &(numerator.sigl) = -arg_signif;
+ numerator.exp = EXP_BIAS - 1;
+ normalize(&numerator); /* 1 - arg */
+
+ arg_signif = *(long long *) &(arg->sigl);
+ if (shrx(&arg_signif, -exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ *(long long *) &(denom.sigl) = arg_signif;
+ denom.sigh |= 0x80000000; /* 1 + arg */
+
+ arg->exp = numerator.exp;
+ reg_u_div(&numerator, &denom, arg, FULL_PRECISION);
+
+ exponent = arg->exp - EXP_BIAS;
+ }
+ }
+ *(long long *) &arg_signif = *(long long *) &(arg->sigl);
+
+#ifdef PARANOID
+ /* This must always be true */
+ if (exponent >= -1) {
+ EXCEPTION(EX_INTERNAL | 0x120); /* There must be a logic error */
+ }
+#endif /* PARANOID */
+
+ /* shift the argument right by the required places */
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+
+ /* Now have arg_signif with binary point at the left .1xxxxxxxx */
+ mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
+ mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq,
+ (unsigned short (*)[4]) oddplterms, HIPOWERop - 1);
+ mul64((long long *) (&argSq.sigl), (long long *) (&pos_poly.sigl),
+ (long long *) (&pos_poly.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq,
+ (unsigned short (*)[4]) oddnegterms, HIPOWERon - 1);
+
+ /* Subtract the mantissas */
+ *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));
+
+ reg_move(&pos_poly, &odd_poly);
+ poly_add_1(&odd_poly);
+
+ /* The complete odd polynomial */
+ reg_u_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(even_poly.sign) = 0;
+
+ mul64((long long *) (&argSq.sigl),
+ (long long *) (&denomterm), (long long *) (&even_poly.sigl));
+
+ poly_add_1(&even_poly);
+
+ reg_div(&odd_poly, &even_poly, arg, FULL_PRECISION);
+
+ if (recursions)
+ reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION);
+}
+
+
+/* The argument to this function must be polynomial() compatible,
+ i.e. have an exponent (not checked) of EXP_BIAS-1 but need not
+ be normalized.
+ This function adds 1.0 to the (assumed positive) argument. */
+static void
+poly_add_1(FPU_REG * src)
+{
+/* Rounding in a consistent direction produces better results
+ for the use of this function in poly_atan. Simple truncation
+ is used here instead of round-to-nearest. */
+
+#ifdef OBSOLETE
+ char round = (src->sigl & 3) == 3;
+#endif /* OBSOLETE */
+
+ shrx(&src->sigl, 1);
+
+#ifdef OBSOLETE
+ if (round)
+ (*(long long *) &src->sigl)++; /* Round to even */
+#endif /* OBSOLETE */
+
+ src->sigh |= 0x80000000;
+
+ src->exp = EXP_BIAS;
+
+}
diff --git a/sys/gnu/arch/i386/fpemul/poly_div.s b/sys/gnu/arch/i386/fpemul/poly_div.s
new file mode 100644
index 00000000000..9b94c96a5b4
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_div.s
@@ -0,0 +1,147 @@
+ .file "poly_div.S"
+/* $OpenBSD: poly_div.s,v 1.1 1996/08/27 10:32:53 downsj Exp $ */
+/*
+ * poly_div.S
+ *
+ * A set of functions to divide 64 bit integers by fixed numbers.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_div.s,v 1.3 1994/06/10 07:44:36 rich Exp $
+ *
+ */
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+.text
+
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div2
+_poly_div2:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ shrl $1,4(%ecx)
+ rcrl $1,(%ecx)
+
+ testw $1,%ax
+ je poly_div2_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div2_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div4
+_poly_div4:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ movl 4(%ecx),%edx
+ shll $30,%edx
+
+ shrl $2,4(%ecx)
+ shrl $2,(%ecx)
+
+ orl %edx,(%ecx)
+
+ testw $2,%ax
+ je poly_div4_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div4_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
+ .align 2,144
+.globl _poly_div16
+_poly_div16:
+ pushl %ebp
+ movl %esp,%ebp
+
+ movl PARAM1,%ecx
+ movw (%ecx),%ax
+
+ movl 4(%ecx),%edx
+ shll $28,%edx
+
+ shrl $4,4(%ecx)
+ shrl $4,(%ecx)
+
+ orl %edx,(%ecx)
+
+ testw $8,%ax
+ je poly_div16_exit
+
+ addl $1,(%ecx)
+ adcl $0,4(%ecx)
+poly_div16_exit:
+
+ leave
+ ret
+/*---------------------------------------------------------------------------*/
diff --git a/sys/gnu/arch/i386/fpemul/poly_l2.c b/sys/gnu/arch/i386/fpemul/poly_l2.c
new file mode 100644
index 00000000000..e50a9e59df3
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_l2.c
@@ -0,0 +1,319 @@
+/* $OpenBSD: poly_l2.c,v 1.1 1996/08/27 10:32:54 downsj Exp $ */
+/*
+ * poly_l2.c
+ *
+ * Compute the base 2 log of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_l2.c,v 1.5 1994/06/10 07:44:38 rich Exp $
+ *
+ */
+
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+
+#define HIPOWER 9
+static unsigned short lterms[HIPOWER][4] =
+{
+ /* Ideal computation with these coeffs gives about 64.6 bit rel
+ * accuracy. */
+ {0xe177, 0xb82f, 0x7652, 0x7154},
+ {0xee0f, 0xe80f, 0x2770, 0x7b1c},
+ {0x0fc0, 0xbe87, 0xb143, 0x49dd},
+ {0x78b9, 0xdadd, 0xec54, 0x34c2},
+ {0x003a, 0x5de9, 0x628b, 0x2909},
+ {0x5588, 0xed16, 0x4abf, 0x2193},
+ {0xb461, 0x85f7, 0x347a, 0x1c6a},
+ {0x0975, 0x87b3, 0xd5bf, 0x1876},
+ {0xe85c, 0xcec9, 0x84e7, 0x187d}
+};
+
+
+
+
+/*--- poly_l2() -------------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ +---------------------------------------------------------------------------*/
+void
+poly_l2(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ char zero; /* flag for an Xx == 0 */
+ unsigned short bits, shift;
+ long long Xsq;
+ FPU_REG accum, denom, num, Xx;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ accum.tag = TW_Valid; /* set the tags to Valid */
+
+ if (arg->sigh > (unsigned) 0xb504f334) {
+ /* This is good enough for the computation of the polynomial
+ * sum, but actually results in a loss of precision for the
+ * computation of Xx. This will matter only if exponent
+ * becomes zero. */
+ exponent++;
+ accum.sign = 1; /* sign to negative */
+ num.exp = EXP_BIAS; /* needed to prevent errors in div
+ * routine */
+ reg_u_div(&CONST_1, arg, &num, FULL_PRECISION);
+ } else {
+ accum.sign = 0; /* set the sign to positive */
+ num.sigl = arg->sigl; /* copy the mantissa */
+ num.sigh = arg->sigh;
+ }
+
+
+ /* shift num left, lose the ms bit */
+ num.sigh <<= 1;
+ if (num.sigl & 0x80000000)
+ num.sigh |= 1;
+ num.sigl <<= 1;
+
+ denom.sigl = num.sigl;
+ denom.sigh = num.sigh;
+ poly_div4((long long *) &(denom.sigl));
+ denom.sigh += 0x80000000; /* set the msb */
+ Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */
+ reg_u_div(&num, &denom, &Xx, FULL_PRECISION);
+
+ zero = !(Xx.sigh | Xx.sigl);
+
+ mul64((long long *) &Xx.sigl, (long long *) &Xx.sigl, &Xsq);
+ poly_div16(&Xsq);
+
+ accum.exp = -1; /* exponent of accum */
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((unsigned *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1);
+
+ if (!exponent) {
+ /* If the exponent is zero, then we would lose precision by
+ * sticking to fixed point computation here */
+ /* We need to re-compute Xx because of loss of precision. */
+ FPU_REG lXx;
+ char sign;
+
+ sign = accum.sign;
+ accum.sign = 0;
+
+ /* make accum compatible and normalize */
+ accum.exp = EXP_BIAS + accum.exp;
+ normalize(&accum);
+
+ if (zero) {
+ reg_move(&CONST_Z, result);
+ } else {
+ /* we need to re-compute lXx to better accuracy */
+ num.tag = TW_Valid; /* set the tags to Vaild */
+ num.sign = 0; /* set the sign to positive */
+ num.exp = EXP_BIAS - 1;
+ if (sign) {
+ /* The argument is of the form 1-x */
+ /* Use 1-1/(1-x) = x/(1-x) */
+ *((long long *) &num.sigl) = -*((long long *) &(arg->sigl));
+ normalize(&num);
+ reg_div(&num, arg, &num, FULL_PRECISION);
+ } else {
+ normalize(&num);
+ }
+
+ denom.tag = TW_Valid; /* set the tags to Valid */
+ denom.sign = SIGN_POS; /* set the sign to positive */
+ denom.exp = EXP_BIAS;
+
+ reg_div(&num, &denom, &lXx, FULL_PRECISION);
+
+ reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION);
+
+ reg_u_add(&lXx, &accum, result, FULL_PRECISION);
+
+ normalize(result);
+ }
+
+ result->sign = sign;
+ return;
+ }
+ mul64((long long *) &accum.sigl,
+ (long long *) &Xx.sigl, (long long *) &accum.sigl);
+
+ *((long long *) (&accum.sigl)) += *((long long *) (&Xx.sigl));
+
+ if (Xx.sigh > accum.sigh) {
+ /* There was an overflow */
+
+ poly_div2((long long *) &accum.sigl);
+ accum.sigh |= 0x80000000;
+ accum.exp++;
+ }
+ /* When we add the exponent to the accum result later, we will require
+ * that their signs are the same. Here we ensure that this is so. */
+ if (exponent && ((exponent < 0) ^ (accum.sign))) {
+ /* signs are different */
+
+ accum.sign = !accum.sign;
+
+ /* An exceptional case is when accum is zero */
+ if (accum.sigl | accum.sigh) {
+ /* find 1-accum */
+ /* Shift to get exponent == 0 */
+ if (accum.exp < 0) {
+ poly_div2((long long *) &accum.sigl);
+ accum.exp++;
+ }
+ /* Just negate, but throw away the sign */
+ *((long long *) &(accum.sigl)) = -*((long long *) &(accum.sigl));
+ if (exponent < 0)
+ exponent++;
+ else
+ exponent--;
+ }
+ }
+ shift = exponent >= 0 ? exponent : -exponent;
+ bits = 0;
+ if (shift) {
+ if (accum.exp) {
+ accum.exp++;
+ poly_div2((long long *) &accum.sigl);
+ }
+ while (shift) {
+ poly_div2((long long *) &accum.sigl);
+ if (shift & 1)
+ accum.sigh |= 0x80000000;
+ shift >>= 1;
+ bits++;
+ }
+ }
+ /* Convert to 64 bit signed-compatible */
+ accum.exp += bits + EXP_BIAS - 1;
+
+ reg_move(&accum, result);
+ normalize(result);
+
+ return;
+}
+
+
+/*--- poly_l2p1() -----------------------------------------------------------+
+ | Base 2 logarithm by a polynomial approximation. |
+ | log2(x+1) |
+ +---------------------------------------------------------------------------*/
+int
+poly_l2p1(FPU_REG * arg, FPU_REG * result)
+{
+ char sign = 0;
+ long long Xsq;
+ FPU_REG arg_pl1, denom, accum, local_arg, poly_arg;
+
+
+ sign = arg->sign;
+
+ reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION);
+
+ if ((arg_pl1.sign) | (arg_pl1.tag)) { /* We need a valid positive
+ * number! */
+ return 1;
+ }
+ reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION);
+ reg_div(arg, &denom, &local_arg, FULL_PRECISION);
+ local_arg.sign = 0; /* Make the sign positive */
+
+ /* Now we need to check that |local_arg| is less than 3-2*sqrt(2) =
+ * 0.17157.. = .0xafb0ccc0 * 2^-2 */
+
+ if (local_arg.exp >= EXP_BIAS - 3) {
+ if ((local_arg.exp > EXP_BIAS - 3) ||
+ (local_arg.sigh > (unsigned) 0xafb0ccc0)) {
+ /* The argument is large */
+ poly_l2(&arg_pl1, result);
+ return 0;
+ }
+ }
+ /* Make a copy of local_arg */
+ reg_move(&local_arg, &poly_arg);
+
+ /* Get poly_arg bits aligned as required */
+ shrx((unsigned *) &(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3));
+
+ mul64((long long *) &(poly_arg.sigl), (long long *) &(poly_arg.sigl), &Xsq);
+ poly_div16(&Xsq);
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &accum.sigl, (unsigned *) &Xsq, lterms, HIPOWER - 1);
+
+ accum.tag = TW_Valid; /* set the tags to Valid */
+ accum.sign = SIGN_POS; /* and make accum positive */
+
+ /* make accum compatible and normalize */
+ accum.exp = EXP_BIAS - 1;
+ normalize(&accum);
+
+ reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION);
+
+ reg_u_add(&local_arg, &accum, result, FULL_PRECISION);
+
+ /* Multiply the result by 2 */
+ result->exp++;
+
+ result->sign = sign;
+
+ return 0;
+}
diff --git a/sys/gnu/arch/i386/fpemul/poly_mul64.s b/sys/gnu/arch/i386/fpemul/poly_mul64.s
new file mode 100644
index 00000000000..0bf3e1ff3d5
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_mul64.s
@@ -0,0 +1,127 @@
+/* $OpenBSD: poly_mul64.s,v 1.1 1996/08/27 10:32:54 downsj Exp $ */
+/*
+ * poly_mul64.S
+ *
+ * Multiply two 64 bit integers.
+ *
+ * Call from C as:
+ * void mul64(long long *a, long long *b, long long *result)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_mul64.s,v 1.3 1994/06/10 07:44:39 rich Exp $
+ *
+ */
+
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+.text
+ .align 2,144
+.globl _mul64
+_mul64:
+ pushl %ebp
+ movl %esp,%ebp
+ subl $16,%esp
+ pushl %esi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ecx
+ movl PARAM3,%ebx
+
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+ movl (%esi),%eax
+ mull (%ecx)
+ movl %eax,-16(%ebp) /* Not used */
+ movl %edx,-12(%ebp)
+
+ movl (%esi),%eax
+ mull 4(%ecx)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax
+ mull (%ecx)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl 4(%esi),%eax
+ mull 4(%ecx)
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+ testb $128,-9(%ebp)
+ je L_no_round
+
+ addl $1,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+L_no_round:
+ movl -8(%ebp),%esi
+ movl %esi,(%ebx)
+ movl -4(%ebp),%esi
+ movl %esi,4(%ebx)
+
+ popl %ebx
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/arch/i386/fpemul/poly_sin.c b/sys/gnu/arch/i386/fpemul/poly_sin.c
new file mode 100644
index 00000000000..1d52b1b1e46
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_sin.c
@@ -0,0 +1,193 @@
+/* $OpenBSD: poly_sin.c,v 1.1 1996/08/27 10:32:55 downsj Exp $ */
+/*
+ * poly_sin.c
+ *
+ * Computation of an approximation of the sin function by a polynomial
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_sin.c,v 1.5 1994/08/31 04:45:22 davidg Exp $
+ *
+ */
+
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+#define HIPOWER 5
+static unsigned short lterms[HIPOWER][4] =
+{
+ {0x846a, 0x42d1, 0xb544, 0x921f},
+ {0xe110, 0x75aa, 0xbc67, 0x1466},
+ {0x503d, 0xa43f, 0x83c1, 0x000a},
+ {0x8f9d, 0x7a19, 0x00f4, 0x0000},
+ {0xda03, 0x06aa, 0x0000, 0x0000},
+};
+
+static unsigned short negterms[HIPOWER][4] =
+{
+ {0x95ed, 0x2df2, 0xe731, 0xa55d},
+ {0xd159, 0xe62b, 0xd2cc, 0x0132},
+ {0x6342, 0xe9fb, 0x3c60, 0x0000},
+ {0x6256, 0xdf5a, 0x0002, 0x0000},
+ {0xf279, 0x000b, 0x0000, 0x0000},
+};
+
+
+/*--- poly_sine() -----------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_sine(FPU_REG * arg, FPU_REG * result)
+{
+ short exponent;
+ FPU_REG Xx, Xx2, Xx4, accum, negaccum;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, result);
+ return;
+ }
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ EXCEPTION(EX_Invalid);
+ reg_move(&CONST_QNaN, result);
+ return;
+ }
+ if (exponent >= 0) { /* Can't hack a number > 1.0 */
+ if ((exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000)) {
+ reg_move(&CONST_1, result);
+ return;
+ }
+ EXCEPTION(EX_Invalid);
+ reg_move(&CONST_QNaN, result);
+ return;
+ }
+#endif /* PARANOID */
+
+ Xx.sigl = arg->sigl;
+ Xx.sigh = arg->sigh;
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&(Xx.sigl), -1 - exponent) >= (unsigned)0x80000000)
+ (*((long long *) (&(Xx.sigl))))++; /* round up */
+ }
+ mul64((long long *) &(Xx.sigl), (long long *) &(Xx.sigl),
+ (long long *) &(Xx2.sigl));
+ mul64((long long *) &(Xx2.sigl), (long long *) &(Xx2.sigl),
+ (long long *) &(Xx4.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(accum.sign) = 0;
+ accum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &(accum.sigl), (u_int *)&(Xx4.sigl), lterms, HIPOWER - 1);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(negaccum.sign) = 0;
+ negaccum.exp = 0;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &(negaccum.sigl), (u_int *)&(Xx4.sigl), negterms, HIPOWER - 1);
+ mul64((long long *) &(Xx2.sigl), (long long *) &(negaccum.sigl),
+ (long long *) &(negaccum.sigl));
+
+ /* Subtract the mantissas */
+ *((long long *) (&(accum.sigl))) -= *((long long *) (&(negaccum.sigl)));
+
+ /* Convert to 64 bit signed-compatible */
+ accum.exp = EXP_BIAS - 1 + accum.exp;
+
+ *(short *) &(result->sign) = *(short *) &(accum.sign);
+ result->exp = accum.exp;
+ result->sigl = accum.sigl;
+ result->sigh = accum.sigh;
+
+ normalize(result);
+
+ reg_mul(result, arg, result, FULL_PRECISION);
+ reg_u_add(result, arg, result, FULL_PRECISION);
+
+ /* A small overflow may be possible... but an illegal result. */
+ if (result->exp >= EXP_BIAS) {
+ if ((result->exp > EXP_BIAS) /* Larger or equal 2.0 */
+ ||(result->sigl > 1) /* Larger than 1.0+msb */
+ ||(result->sigh != 0x80000000) /* Much > 1.0 */
+ ) {
+#ifdef DEBUGGING
+ RE_ENTRANT_CHECK_OFF
+ printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp,
+ result->sigh, result->sigl);
+ RE_ENTRANT_CHECK_ON
+#endif /* DEBUGGING */
+ EXCEPTION(EX_INTERNAL | 0x103);
+ }
+#ifdef DEBUGGING
+ RE_ENTRANT_CHECK_OFF
+ printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n");
+ printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp,
+ result->sigh, result->sigl);
+ RE_ENTRANT_CHECK_ON
+#endif /* DEBUGGING */
+
+ result->sigl = 0; /* Truncate the result to 1.00 */
+ }
+}
diff --git a/sys/gnu/arch/i386/fpemul/poly_tan.c b/sys/gnu/arch/i386/fpemul/poly_tan.c
new file mode 100644
index 00000000000..038dc04535f
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/poly_tan.c
@@ -0,0 +1,230 @@
+/* $OpenBSD: poly_tan.c,v 1.1 1996/08/27 10:32:55 downsj Exp $ */
+/*
+ * poly_tan.c
+ *
+ * Compute the tan of a FPU_REG, using a polynomial approximation.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: poly_tan.c,v 1.5 1995/05/30 07:57:52 rgrimes Exp $
+ *
+ */
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+#define HIPOWERop 3 /* odd poly, positive terms */
+static unsigned short oddplterms[HIPOWERop][4] =
+{
+ {0x846a, 0x42d1, 0xb544, 0x921f},
+ {0x6fb2, 0x0215, 0x95c0, 0x099c},
+ {0xfce6, 0x0cc8, 0x1c9a, 0x0000}
+};
+#define HIPOWERon 2 /* odd poly, negative terms */
+static unsigned short oddnegterms[HIPOWERon][4] =
+{
+ {0x6906, 0xe205, 0x25c8, 0x8838},
+ {0x1dd7, 0x3fe3, 0x944e, 0x002c}
+};
+#define HIPOWERep 2 /* even poly, positive terms */
+static unsigned short evenplterms[HIPOWERep][4] =
+{
+ {0xdb8f, 0x3761, 0x1432, 0x2acf},
+ {0x16eb, 0x13c1, 0x3099, 0x0003}
+};
+#define HIPOWERen 2 /* even poly, negative terms */
+static unsigned short evennegterms[HIPOWERen][4] =
+{
+ {0x3a7c, 0xe4c5, 0x7f87, 0x2945},
+ {0x572b, 0x664c, 0xc543, 0x018c}
+};
+
+
+/*--- poly_tan() ------------------------------------------------------------+
+ | |
+ +---------------------------------------------------------------------------*/
+void
+poly_tan(FPU_REG * arg, FPU_REG * y_reg)
+{
+ char invert = 0;
+ short exponent;
+ FPU_REG odd_poly, even_poly, pos_poly, neg_poly;
+ FPU_REG argSq;
+ long long arg_signif, argSqSq;
+
+
+ exponent = arg->exp - EXP_BIAS;
+
+ if (arg->tag == TW_Zero) {
+ /* Return 0.0 */
+ reg_move(&CONST_Z, y_reg);
+ return;
+ }
+ if (exponent >= -1) {
+ /* argument is in the range [0.5 .. 1.0] */
+ if (exponent >= 0) {
+#ifdef PARANOID
+ if ((exponent == 0) &&
+ (arg->sigl == 0) && (arg->sigh == 0x80000000))
+#endif /* PARANOID */
+ {
+ arith_overflow(y_reg);
+ return;
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x104); /* There must be a logic
+ * error */
+ return;
+#endif /* PARANOID */
+ }
+ /* The argument is in the range [0.5 .. 1.0) */
+ /* Convert the argument to a number in the range (0.0 .. 0.5] */
+ *((long long *) (&arg->sigl)) = -*((long long *) (&arg->sigl));
+ normalize(arg); /* Needed later */
+ exponent = arg->exp - EXP_BIAS;
+ invert = 1;
+ }
+#ifdef PARANOID
+ if (arg->sign != 0) { /* Can't hack a number < 0.0 */
+ arith_invalid(y_reg);
+ return;
+ } /* Need a positive number */
+#endif /* PARANOID */
+
+ *(long long *) &arg_signif = *(long long *) &(arg->sigl);
+ if (exponent < -1) {
+ /* shift the argument right by the required places */
+ if (shrx(&arg_signif, -1 - exponent) >= (unsigned)0x80000000)
+ arg_signif++; /* round up */
+ }
+ mul64(&arg_signif, &arg_signif, (long long *) (&argSq.sigl));
+ mul64((long long *) (&argSq.sigl), (long long *) (&argSq.sigl), &argSqSq);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, oddplterms, HIPOWERop - 1);
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, oddnegterms, HIPOWERon - 1);
+ mul64((long long *) (&argSq.sigl), (long long *) (&neg_poly.sigl),
+ (long long *) (&neg_poly.sigl));
+
+ /* Subtract the mantissas */
+ *((long long *) (&pos_poly.sigl)) -= *((long long *) (&neg_poly.sigl));
+
+ /* Convert to 64 bit signed-compatible */
+ pos_poly.exp -= 1;
+
+ reg_move(&pos_poly, &odd_poly);
+ normalize(&odd_poly);
+
+ reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION);
+ reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION); /* This is just the odd
+ * polynomial */
+
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(pos_poly.sign) = 0;
+ pos_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &pos_poly.sigl, (unsigned *) &argSqSq, evenplterms, HIPOWERep - 1);
+ mul64((long long *) (&argSq.sigl),
+ (long long *) (&pos_poly.sigl), (long long *) (&pos_poly.sigl));
+
+ /* will be a valid positive nr with expon = 0 */
+ *(short *) &(neg_poly.sign) = 0;
+ neg_poly.exp = EXP_BIAS;
+
+ /* Do the basic fixed point polynomial evaluation */
+ polynomial((u_int *) &neg_poly.sigl, (unsigned *) &argSqSq, evennegterms, HIPOWERen - 1);
+
+ /* Subtract the mantissas */
+ *((long long *) (&neg_poly.sigl)) -= *((long long *) (&pos_poly.sigl));
+ /* and multiply by argSq */
+
+ /* Convert argSq to a valid reg number */
+ *(short *) &(argSq.sign) = 0;
+ argSq.exp = EXP_BIAS - 1;
+ normalize(&argSq);
+
+ /* Convert to 64 bit signed-compatible */
+ neg_poly.exp -= 1;
+
+ reg_move(&neg_poly, &even_poly);
+ normalize(&even_poly);
+
+ reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION);
+ reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION);
+ reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION); /* This is just the even
+ * polynomial */
+
+ /* Now ready to copy the results */
+ if (invert) {
+ reg_div(&even_poly, &odd_poly, y_reg, FULL_PRECISION);
+ } else {
+ reg_div(&odd_poly, &even_poly, y_reg, FULL_PRECISION);
+ }
+
+}
diff --git a/sys/gnu/arch/i386/fpemul/polynomial.s b/sys/gnu/arch/i386/fpemul/polynomial.s
new file mode 100644
index 00000000000..f963e0fa828
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/polynomial.s
@@ -0,0 +1,195 @@
+/* $OpenBSD: polynomial.s,v 1.1 1996/08/27 10:32:56 downsj Exp $ */
+/*
+ * polynomial.S
+ *
+ * Fixed point arithmetic polynomial evaluation.
+ *
+ * Call from C as:
+ * void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2],
+ * int n)
+ *
+ * Computes:
+ * terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x
+ * The result is returned in accum.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: polynomial.s,v 1.3 1994/06/10 07:44:43 rich Exp $
+ *
+ */
+
+ .file "fpolynom.s"
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+
+/* #define EXTRA_PRECISE*/
+
+#define TERM_SIZE $8
+
+
+.text
+ .align 2,144
+.globl _polynomial
+_polynomial:
+ pushl %ebp
+ movl %esp,%ebp
+ subl $32,%esp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* accum */
+ movl PARAM2,%edi /* x */
+ movl PARAM3,%ebx /* terms */
+ movl PARAM4,%ecx /* n */
+
+ movl TERM_SIZE,%eax
+ mull %ecx
+ movl %eax,%ecx
+
+ movl 4(%ebx,%ecx,1),%edx /* terms[n] */
+ movl %edx,-20(%ebp)
+ movl (%ebx,%ecx,1),%edx /* terms[n] */
+ movl %edx,-24(%ebp)
+ xor %eax,%eax
+ movl %eax,-28(%ebp)
+
+ subl TERM_SIZE,%ecx
+ js L_accum_done
+
+L_accum_loop:
+ xor %eax,%eax
+ movl %eax,-4(%ebp)
+ movl %eax,-8(%ebp)
+
+#ifdef EXTRA_PRECISE
+ movl -28(%ebp),%eax
+ mull 4(%edi) /* x ms long */
+ movl %edx,-12(%ebp)
+#endif EXTRA_PRECISE
+
+ movl -24(%ebp),%eax
+ mull (%edi) /* x ls long */
+/* movl %eax,-16(%ebp) */ /* Not needed */
+ addl %edx,-12(%ebp)
+ adcl $0,-8(%ebp)
+
+ movl -24(%ebp),%eax
+ mull 4(%edi) /* x ms long */
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl -20(%ebp),%eax
+ mull (%edi)
+ addl %eax,-12(%ebp)
+ adcl %edx,-8(%ebp)
+ adcl $0,-4(%ebp)
+
+ movl -20(%ebp),%eax
+ mull 4(%edi)
+ addl %eax,-8(%ebp)
+ adcl %edx,-4(%ebp)
+
+/* Now add the next term */
+ movl (%ebx,%ecx,1),%eax
+ addl %eax,-8(%ebp)
+ movl 4(%ebx,%ecx,1),%eax
+ adcl %eax,-4(%ebp)
+
+/* And put into the second register */
+ movl -4(%ebp),%eax
+ movl %eax,-20(%ebp)
+ movl -8(%ebp),%eax
+ movl %eax,-24(%ebp)
+
+#ifdef EXTRA_PRECISE
+ movl -12(%ebp),%eax
+ movl %eax,-28(%ebp)
+#else
+ testb $128,-25(%ebp)
+ je L_no_poly_round
+
+ addl $1,-24(%ebp)
+ adcl $0,-20(%ebp)
+L_no_poly_round:
+#endif EXTRA_PRECISE
+
+ subl TERM_SIZE,%ecx
+ jns L_accum_loop
+
+L_accum_done:
+#ifdef EXTRA_PRECISE
+/* And round the result */
+ testb $128,-25(%ebp)
+ je L_poly_done
+
+ addl $1,-24(%ebp)
+ adcl $0,-20(%ebp)
+#endif EXTRA_PRECISE
+
+L_poly_done:
+ movl -24(%ebp),%eax
+ movl %eax,(%esi)
+ movl -20(%ebp),%eax
+ movl %eax,4(%esi)
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/arch/i386/fpemul/reg_add_sub.c b/sys/gnu/arch/i386/fpemul/reg_add_sub.c
new file mode 100644
index 00000000000..fce16348be6
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_add_sub.c
@@ -0,0 +1,304 @@
+/* $OpenBSD: reg_add_sub.c,v 1.1 1996/08/27 10:32:56 downsj Exp $ */
+/*
+ * reg_add_sub.c
+ *
+ * Functions to add or subtract two registers and put the result in a third.
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_add_sub.c,v 1.3 1994/06/10 07:44:44 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | For each function, the destination may be any FPU_REG, including one of |
+ | the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+
+
+void
+reg_add(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
+{
+ int diff;
+
+ if (!(a->tag | b->tag)) {
+ /* Both registers are valid */
+ if (!(a->sign ^ b->sign)) {
+ /* signs are the same */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = a->sign;
+ return;
+ }
+ /* The signs are different, so do a subtraction */
+ diff = a->exp - b->exp;
+ if (!diff) {
+ diff = a->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (!diff) {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+ if (diff > 0) {
+ reg_u_sub(a, b, dest, control_w);
+ dest->sign = a->sign;
+ } else
+ if (diff == 0) {
+ reg_move(&CONST_Z, dest);
+ /* sign depends upon rounding mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ } else {
+ reg_u_sub(b, a, dest, control_w);
+ dest->sign = b->sign;
+ }
+ return;
+ } else {
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (a->tag == TW_Zero) {
+ if (b->tag == TW_Zero) {
+ char different_signs = a->sign ^ b->sign;
+ /* Both are zero, result will be zero. */
+ reg_move(a, dest);
+ if (different_signs) {
+ /* Signs are different. */
+ /* Sign of answer depends upon
+ * rounding mode. */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ }
+ } else {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ }
+ return;
+ } else
+ if (b->tag == TW_Zero) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag != TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ }
+ if (a->sign == b->sign) {
+ /* They are both + or
+ * - infinity */
+ reg_move(a, dest);
+ return;
+ }
+ arith_invalid(dest); /* Infinity-Infinity is
+ * undefined. */
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ return;
+ }
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x101);
+#endif
+}
+
+
+/* Subtract b from a. (a-b) -> dest */
+void
+reg_sub(FPU_REG * a, FPU_REG * b, FPU_REG * dest, int control_w)
+{
+ int diff;
+
+ if (!(a->tag | b->tag)) {
+ /* Both registers are valid */
+ diff = a->exp - b->exp;
+ if (!diff) {
+ diff = a->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (!diff) {
+ diff = a->sigl > b->sigl;
+ if (!diff)
+ diff = -(a->sigl < b->sigl);
+ }
+ }
+ switch (a->sign * 2 + b->sign) {
+ case 0: /* P - P */
+ case 3: /* N - N */
+ if (diff > 0) {
+ reg_u_sub(a, b, dest, control_w);
+ dest->sign = a->sign;
+ } else
+ if (diff == 0) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(&CONST_Z, dest);
+ /* sign depends upon rounding mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ } else {
+ reg_u_sub(b, a, dest, control_w);
+ dest->sign = a->sign ^ SIGN_POS ^ SIGN_NEG;
+ }
+ return;
+ case 1: /* P - N */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = SIGN_POS;
+ return;
+ case 2: /* N - P */
+ reg_u_add(a, b, dest, control_w);
+ dest->sign = SIGN_NEG;
+ return;
+ }
+ } else {
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (b->tag == TW_Zero) {
+ if (a->tag == TW_Zero) {
+ char same_signs = !(a->sign ^ b->sign);
+ /* Both are zero, result will be zero. */
+ reg_move(a, dest); /* Answer for different
+ * signs. */
+ if (same_signs) {
+ /* Sign depends upon rounding
+ * mode */
+ dest->sign = ((control_w & CW_RC) != RC_DOWN)
+ ? SIGN_POS : SIGN_NEG;
+ }
+ } else {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ }
+ return;
+ } else
+ if (a->tag == TW_Zero) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign ^= SIGN_POS ^ SIGN_NEG;
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag != TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ return;
+ }
+ /* Both args are Infinity */
+ if (a->sign == b->sign) {
+ arith_invalid(dest); /* Infinity-Infinity is
+ * undefined. */
+ return;
+ }
+ reg_move(a, dest);
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign ^= SIGN_POS ^ SIGN_NEG;
+ return;
+ }
+ }
+#ifdef PARANOID
+ EXCEPTION(EX_INTERNAL | 0x110);
+#endif
+}
diff --git a/sys/gnu/arch/i386/fpemul/reg_compare.c b/sys/gnu/arch/i386/fpemul/reg_compare.c
new file mode 100644
index 00000000000..3da56eb9007
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_compare.c
@@ -0,0 +1,385 @@
+/* $OpenBSD: reg_compare.c,v 1.1 1996/08/27 10:32:57 downsj Exp $ */
+/*
+ * reg_compare.c
+ *
+ * Compare two floating point registers
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_compare.c,v 1.5 1995/05/30 07:57:54 rgrimes Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | compare() is the core FPU_REG comparison function |
+ +---------------------------------------------------------------------------*/
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+
+
+int
+compare(FPU_REG * b)
+{
+ int diff;
+
+ if (FPU_st0_ptr->tag | b->tag) {
+ if (FPU_st0_ptr->tag == TW_Zero) {
+ if (b->tag == TW_Zero)
+ return COMP_A_eq_B;
+ if (b->tag == TW_Valid) {
+#ifdef DENORM_OPERAND
+ if ((b->exp <= EXP_UNDER) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ }
+ } else
+ if (b->tag == TW_Zero) {
+ if (FPU_st0_ptr->tag == TW_Valid) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ }
+ }
+ if (FPU_st0_ptr->tag == TW_Infinity) {
+ if ((b->tag == TW_Valid) || (b->tag == TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)
+ && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ } else
+ if (b->tag == TW_Infinity) {
+ /* The 80486 book says that infinities
+ * can be equal! */
+ return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B :
+ ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B);
+ }
+ /* Fall through to the NaN code */
+ } else
+ if (b->tag == TW_Infinity) {
+ if ((FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if ((FPU_st0_ptr->tag == TW_Valid)
+ && (FPU_st0_ptr->exp <= EXP_UNDER)
+ && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+ return (b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ }
+ /* Fall through to the NaN code */
+ }
+ /* The only possibility now should be that one of the
+ * arguments is a NaN */
+ if ((FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ if (((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000))
+ || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)))
+ /* At least one arg is a signaling NaN */
+ return COMP_No_Comp | COMP_SNaN | COMP_NaN;
+ else
+ /* Neither is a signaling NaN */
+ return COMP_No_Comp | COMP_NaN;
+ }
+ EXCEPTION(EX_Invalid);
+ }
+#ifdef PARANOID
+ if (!(FPU_st0_ptr->sigh & 0x80000000))
+ EXCEPTION(EX_Invalid);
+ if (!(b->sigh & 0x80000000))
+ EXCEPTION(EX_Invalid);
+#endif /* PARANOID */
+
+#ifdef DENORM_OPERAND
+ if (((FPU_st0_ptr->exp <= EXP_UNDER) ||
+ (b->exp <= EXP_UNDER)) && (denormal_operand()))
+ return COMP_Denormal;
+#endif /* DENORM_OPERAND */
+
+ if (FPU_st0_ptr->sign != b->sign)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+
+ diff = FPU_st0_ptr->exp - b->exp;
+ if (diff == 0) {
+ diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits
+ * are identical */
+ if (diff == 0) {
+ diff = FPU_st0_ptr->sigl > b->sigl;
+ if (diff == 0)
+ diff = -(FPU_st0_ptr->sigl < b->sigl);
+ }
+ }
+ if (diff > 0)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B;
+ if (diff < 0)
+ return (FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B;
+ return COMP_A_eq_B;
+
+}
+
+
+/* This function requires that st(0) is not empty */
+int
+compare_st_data(void)
+{
+ int f = 0, c;
+
+ c = compare(&FPU_loaded_data);
+
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ EXCEPTION(EX_Invalid);
+ f = SW_C3 | SW_C2 | SW_C0;
+ } else {
+ /* One of the operands is a de-normal */
+ return 0;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x121);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+
+
+static int
+compare_st_st(int nr)
+{
+ int f = 0, c;
+
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return control_word & CW_Invalid;
+ }
+ c = compare(&st(nr));
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ EXCEPTION(EX_Invalid);
+ return control_word & CW_Invalid;
+ } else {
+ /* One of the operands is a de-normal */
+ return control_word & CW_Denormal;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x122);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+
+
+static int
+compare_u_st_st(int nr)
+{
+ int f = 0, c;
+
+ if (!NOT_EMPTY_0 || !NOT_EMPTY(nr)) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ /* Stack fault */
+ EXCEPTION(EX_StackUnder);
+ return control_word & CW_Invalid;
+ }
+ c = compare(&st(nr));
+ if (c & (COMP_NaN | COMP_Denormal)) {
+ if (c & COMP_NaN) {
+ setcc(SW_C3 | SW_C2 | SW_C0);
+ if (c & COMP_SNaN) { /* This is the only difference
+ * between un-ordered and
+ * ordinary comparisons */
+ EXCEPTION(EX_Invalid);
+ return control_word & CW_Invalid;
+ }
+ return 1;
+ } else {
+ /* One of the operands is a de-normal */
+ return control_word & CW_Denormal;
+ }
+ } else
+ switch (c) {
+ case COMP_A_lt_B:
+ f = SW_C0;
+ break;
+ case COMP_A_eq_B:
+ f = SW_C3;
+ break;
+ case COMP_A_gt_B:
+ f = 0;
+ break;
+ case COMP_No_Comp:
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#ifdef PARANOID
+ default:
+ EXCEPTION(EX_INTERNAL | 0x123);
+ f = SW_C3 | SW_C2 | SW_C0;
+ break;
+#endif /* PARANOID */
+ }
+ setcc(f);
+ return 1;
+}
+/*---------------------------------------------------------------------------*/
+
+void
+fcom_st()
+{
+ /* fcom st(i) */
+ compare_st_st(FPU_rm);
+}
+
+
+void
+fcompst()
+{
+ /* fcomp st(i) */
+ if (compare_st_st(FPU_rm))
+ pop();
+}
+
+
+void
+fcompp()
+{
+ /* fcompp */
+ if (FPU_rm != 1)
+ return Un_impl();
+ if (compare_st_st(1)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ pop();
+ }
+}
+
+
+void
+fucom_()
+{
+ /* fucom st(i) */
+ compare_u_st_st(FPU_rm);
+
+}
+
+
+void
+fucomp()
+{
+ /* fucomp st(i) */
+ if (compare_u_st_st(FPU_rm))
+ pop();
+}
+
+
+void
+fucompp()
+{
+ /* fucompp */
+ if (FPU_rm == 1) {
+ if (compare_u_st_st(1)) {
+ pop();
+ FPU_st0_ptr = &st(0);
+ pop();
+ }
+ } else
+ Un_impl();
+}
diff --git a/sys/gnu/arch/i386/fpemul/reg_constant.c b/sys/gnu/arch/i386/fpemul/reg_constant.c
new file mode 100644
index 00000000000..a7c76d45298
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_constant.c
@@ -0,0 +1,172 @@
+/* $OpenBSD: reg_constant.c,v 1.1 1996/08/27 10:32:57 downsj Exp $ */
+/*
+ * reg_constant.c
+ *
+ * All of the constant FPU_REGs
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $id:$
+ *
+ */
+
+
+
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+
+
+FPU_REG CONST_1 = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x00000000, 0x80000000};
+static FPU_REG CONST_L2T = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0xcd1b8afe, 0xd49a784b};
+static FPU_REG CONST_L2E = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x5c17f0bc, 0xb8aa3b29};
+FPU_REG CONST_PI = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_PI2 = {SIGN_POS, TW_Valid, EXP_BIAS,
+0x2168c235, 0xc90fdaa2};
+FPU_REG CONST_PI4 = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0x2168c235, 0xc90fdaa2};
+static FPU_REG CONST_LG2 = {SIGN_POS, TW_Valid, EXP_BIAS - 2,
+0xfbcff799, 0x9a209a84};
+FPU_REG CONST_LN2 = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
+0xd1cf79ac, 0xb17217f7};
+/* Only the sign (and tag) is used in internal zeroes */
+FPU_REG CONST_Z = {SIGN_POS, TW_Zero, 0, 0x0, 0x0};
+/* Only the sign and significand (and tag) are used in internal NaNs */
+/* The 80486 never generates one of these
+FPU_REG CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 };
+ */
+/* This is the real indefinite QNaN */
+FPU_REG CONST_QNaN = {SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000};
+/* Only the sign (and tag) is used in internal infinities */
+FPU_REG CONST_INF = {SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000};
+
+
+
+static void
+fld_const(FPU_REG * c)
+{
+ FPU_REG *st_new_ptr;
+
+ if (STACK_OVERFLOW) {
+ stack_overflow();
+ return;
+ }
+ push();
+ reg_move(c, FPU_st0_ptr);
+ status_word &= ~SW_C1;
+}
+
+
+static void
+fld1(void)
+{
+ fld_const(&CONST_1);
+}
+
+static void
+fldl2t(void)
+{
+ fld_const(&CONST_L2T);
+}
+
+static void
+fldl2e(void)
+{
+ fld_const(&CONST_L2E);
+}
+
+static void
+fldpi(void)
+{
+ fld_const(&CONST_PI);
+}
+
+static void
+fldlg2(void)
+{
+ fld_const(&CONST_LG2);
+}
+
+static void
+fldln2(void)
+{
+ fld_const(&CONST_LN2);
+}
+
+static void
+fldz(void)
+{
+ fld_const(&CONST_Z);
+}
+
+static FUNC constants_table[] = {
+ fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, Un_impl
+};
+
+void
+fconst(void)
+{
+ (constants_table[FPU_rm]) ();
+}
diff --git a/sys/gnu/arch/i386/fpemul/reg_constant.h b/sys/gnu/arch/i386/fpemul/reg_constant.h
new file mode 100644
index 00000000000..bf0a155df99
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_constant.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: reg_constant.h,v 1.1 1996/08/27 10:32:58 downsj Exp $ */
+/*
+ * reg_constant.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_constant.h,v 1.3 1994/06/10 07:44:49 rich Exp $
+ *
+ */
+
+#ifndef _REG_CONSTANT_H_
+#define _REG_CONSTANT_H_
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+
+extern FPU_REG CONST_1;
+extern FPU_REG CONST_2;
+extern FPU_REG CONST_HALF;
+extern FPU_REG CONST_L2T;
+extern FPU_REG CONST_L2E;
+extern FPU_REG CONST_PI;
+extern FPU_REG CONST_PI2;
+extern FPU_REG CONST_PI4;
+extern FPU_REG CONST_LG2;
+extern FPU_REG CONST_LN2;
+extern FPU_REG CONST_Z;
+extern FPU_REG CONST_PINF;
+extern FPU_REG CONST_INF;
+extern FPU_REG CONST_MINF;
+extern FPU_REG CONST_QNaN;
+
+#endif /* _REG_CONSTANT_H_ */
diff --git a/sys/gnu/arch/i386/fpemul/reg_div.s b/sys/gnu/arch/i386/fpemul/reg_div.s
new file mode 100644
index 00000000000..c6970d236d8
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_div.s
@@ -0,0 +1,298 @@
+ .file "reg_div.S"
+/* $OpenBSD: reg_div.s,v 1.1 1996/08/27 10:32:58 downsj Exp $ */
+/*
+ * reg_div.S
+ *
+ * Divide one FPU_REG by another and put the result in a destination FPU_REG.
+ *
+ * Call from C as:
+ * void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_div.s,v 1.3 1994/06/10 07:44:50 rich Exp $
+ *
+ */
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+.text
+ .align 2
+
+.globl _reg_div
+_reg_div:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ebx
+ movl PARAM3,%edi
+
+ movb TAG(%esi),%al
+ orb TAG(%ebx),%al
+
+ jne L_div_special /* Not (both numbers TW_Valid) */
+
+#ifdef DENORM_OPERAND
+/* Check for denormals */
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xL_arg1_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xL_arg1_not_denormal:
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg xL_arg2_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xL_arg2_not_denormal:
+#endif DENORM_OPERAND
+
+/* Both arguments are TW_Valid */
+ movb TW_Valid,TAG(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
+
+ movl EXP(%esi),%edx
+ movl EXP(%ebx),%eax
+ subl %eax,%edx
+ addl EXP_BIAS,%edx
+ movl %edx,EXP(%edi)
+
+ jmp _divide_kernel
+
+
+/*-----------------------------------------------------------------------*/
+L_div_special:
+ cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
+ je L_arg1_NaN
+
+ cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
+ jne L_no_NaN_arg
+
+/* Operations on NaNs */
+L_arg1_NaN:
+L_arg2_NaN:
+ pushl %edi /* Destination */
+ pushl %ebx
+ pushl %esi
+ call _real_2op_NaN
+ jmp LDiv_exit
+
+/* Invalid operations */
+L_zero_zero:
+L_inf_inf:
+ pushl %edi /* Destination */
+ call _arith_invalid /* 0/0 or Infinity/Infinity */
+ jmp LDiv_exit
+
+L_no_NaN_arg:
+ cmpb TW_Infinity,TAG(%esi)
+ jne L_arg1_not_inf
+
+ cmpb TW_Infinity,TAG(%ebx)
+ je L_inf_inf /* invalid operation */
+
+ cmpb TW_Valid,TAG(%ebx)
+ je L_inf_valid
+
+#ifdef PARANOID
+ /* arg2 must be zero or valid */
+ cmpb TW_Zero,TAG(%ebx)
+ ja L_unknown_tags
+#endif PARANOID
+
+ /* Note that p16-9 says that infinity/0 returns infinity */
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_inf_valid:
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is Inf */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_arg1_not_inf:
+ cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
+ jne L_arg2_not_zero
+
+ cmpb TW_Zero,TAG(%esi)
+ je L_zero_zero /* invalid operation */
+
+#ifdef PARANOID
+ /* arg1 must be valid */
+ cmpb TW_Valid,TAG(%esi)
+ ja L_unknown_tags
+#endif PARANOID
+
+/* Division by zero error */
+ pushl %edi /* destination */
+ movb SIGN(%esi),%al
+ xorb SIGN(%ebx),%al
+ pushl %eax /* lower 8 bits have the sign */
+ call _divide_by_zero
+ jmp LDiv_exit
+
+L_arg2_not_zero:
+ cmpb TW_Infinity,TAG(%ebx)
+ jne L_arg2_not_inf
+
+#ifdef DENORM_OPERAND
+ cmpb TW_Valid,TAG(%esi)
+ jne L_return_zero
+
+ cmpl EXP_UNDER,EXP(%esi)
+ jg L_return_zero /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_return_zero /* Answer is zero */
+
+L_arg2_not_inf:
+
+#ifdef PARANOID
+ cmpb TW_Zero,TAG(%esi)
+ jne L_unknown_tags
+#endif PARANOID
+
+ /* arg1 is zero, arg2 is not Infinity or a NaN */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+#endif DENORM_OPERAND
+
+L_copy_arg1:
+ movb TAG(%esi),%ax
+ movb %ax,TAG(%edi)
+ movl EXP(%esi),%eax
+ movl %eax,EXP(%edi)
+ movl SIGL(%esi),%eax
+ movl %eax,SIGL(%edi)
+ movl SIGH(%esi),%eax
+ movl %eax,SIGH(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%edi)
+ jmp LDiv_exit
+
+LDiv_set_result_sign:
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%edi)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%ebx)
+ jmp LDiv_exit
+
+LDiv_negative_result:
+ movb SIGN_NEG,SIGN(%edi)
+
+LDiv_exit:
+ leal -12(%ebp),%esp
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_return_zero:
+ movb TW_Zero,TAG(%edi)
+ jmp LDiv_set_result_sign
+
+#ifdef PARANOID
+L_unknown_tags:
+ push EX_INTERNAL | 0x208
+ call EXCEPTION
+
+ /* Generate a NaN for unknown tags */
+ movl _CONST_QNaN,%eax
+ movl %eax,(%edi)
+ movl _CONST_QNaN+4,%eax
+ movl %eax,SIGL(%edi)
+ movl _CONST_QNaN+8,%eax
+ movl %eax,SIGH(%edi)
+ jmp LDiv_exit
+#endif PARANOID
diff --git a/sys/gnu/arch/i386/fpemul/reg_ld_str.c b/sys/gnu/arch/i386/fpemul/reg_ld_str.c
new file mode 100644
index 00000000000..89b296d7bef
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_ld_str.c
@@ -0,0 +1,1391 @@
+/* $OpenBSD: reg_ld_str.c,v 1.1 1996/08/27 10:32:59 downsj Exp $ */
+/*
+ * reg_ld_str.c
+ *
+ * All of the functions which transfer data between user memory and FPU_REGs.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_ld_str.c,v 1.6 1996/06/25 20:29:26 bde Exp $
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | Note: |
+ | The file contains code which accesses user memory. |
+ | Emulator static data may change when user memory is accessed, due to |
+ | other processes using the emulator while swapping is in progress. |
+ +---------------------------------------------------------------------------*/
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/systm.h>
+#include <machine/cpu.h>
+#if defined(__FreeBSD__)
+#include <machine/md_var.h>
+#endif
+#include <machine/pcb.h>
+
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+#include <gnu/arch/i386/fpemul/status_w.h>
+
+
+#define EXTENDED_Emax 0x3fff /* largest valid exponent */
+#define EXTENDED_Ebias 0x3fff
+#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */
+
+#define DOUBLE_Emax 1023 /* largest valid exponent */
+#define DOUBLE_Ebias 1023
+#define DOUBLE_Emin (-1022) /* smallest valid exponent */
+
+#define SINGLE_Emax 127 /* largest valid exponent */
+#define SINGLE_Ebias 127
+#define SINGLE_Emin (-126) /* smallest valid exponent */
+
+#define LOST_UP (EX_Precision | SW_C1)
+#define LOST_DOWN EX_Precision
+
+FPU_REG FPU_loaded_data;
+
+
+/* Get a long double from user memory */
+void
+reg_load_extended(void)
+{
+ long double *s = (long double *) FPU_data_address;
+ unsigned long sigl, sigh, exp;
+
+ REENTRANT_CHECK(OFF);
+ /* Use temporary variables here because FPU_loaded data is static and
+ * hence re-entrancy problems can arise */
+ sigl = fuword((unsigned long *) s);
+ sigh = fuword(1 + (unsigned long *) s);
+ exp = fusword(4 + (unsigned short *) s);
+ REENTRANT_CHECK(ON);
+
+ FPU_loaded_data.sigl = sigl;
+ FPU_loaded_data.sigh = sigh;
+ FPU_loaded_data.exp = exp;
+
+ if (FPU_loaded_data.exp & 0x8000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ if ((FPU_loaded_data.exp &= 0x7fff) == 0) {
+ if (!(FPU_loaded_data.sigl | FPU_loaded_data.sigh)) {
+ FPU_loaded_data.tag = TW_Zero;
+ return;
+ }
+ /* The number is a de-normal or pseudodenormal. */
+ /* The 80486 doesn't regard pseudodenormals as denormals here. */
+ if (!(FPU_loaded_data.sigh & 0x80000000))
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp++;
+
+ /* The default behaviour will now take care of it. */
+ } else
+ if (FPU_loaded_data.exp == 0x7fff) {
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ if ((FPU_loaded_data.sigh == 0x80000000)
+ && (FPU_loaded_data.sigl == 0)) {
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else
+ if (!(FPU_loaded_data.sigh & 0x80000000)) {
+ /* Unsupported NaN data type */
+ EXCEPTION(EX_Invalid);
+ FPU_loaded_data.tag = TW_NaN;
+ return;
+ }
+ FPU_loaded_data.tag = TW_NaN;
+ return;
+ }
+ FPU_loaded_data.exp = (FPU_loaded_data.exp & 0x7fff) - EXTENDED_Ebias
+ + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+
+ if (!(sigh & 0x80000000)) {
+ /* Unsupported data type */
+ EXCEPTION(EX_Invalid);
+ normalize_nuo(&FPU_loaded_data);
+ }
+}
+
+
+/* Get a double from user memory */
+void
+reg_load_double(void)
+{
+ double *dfloat = (double *) FPU_data_address;
+ int exp;
+ unsigned m64, l64;
+
+ REENTRANT_CHECK(OFF);
+ m64 = fuword(1 + (unsigned long *) dfloat);
+ l64 = fuword((unsigned long *) dfloat);
+ REENTRANT_CHECK(ON);
+
+ if (m64 & 0x80000000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
+ m64 &= 0xfffff;
+ if (exp > DOUBLE_Emax) {
+ /* Infinity or NaN */
+ if ((m64 == 0) && (l64 == 0)) {
+ /* +- infinity */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else {
+ /* Must be a signaling or quiet NaN */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_NaN;
+ FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+ return;
+ }
+ } else
+ if (exp < DOUBLE_Emin) {
+ /* Zero or de-normal */
+ if ((m64 == 0) && (l64 == 0)) {
+ /* Zero */
+ int c = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = c;
+ return;
+ } else {
+ /* De-normal */
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = m64 << 11;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+ normalize_nuo(&FPU_loaded_data);
+ return;
+ }
+ } else {
+ FPU_loaded_data.exp = exp + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
+ FPU_loaded_data.sigh |= l64 >> 21;
+ FPU_loaded_data.sigl = l64 << 11;
+
+ return;
+ }
+}
+
+
+/* Get a float from user memory */
+void
+reg_load_single(void)
+{
+ float *single = (float *) FPU_data_address;
+ unsigned m32;
+ int exp;
+
+ REENTRANT_CHECK(OFF);
+ m32 = fuword((unsigned long *) single);
+ REENTRANT_CHECK(ON);
+
+ if (m32 & 0x80000000)
+ FPU_loaded_data.sign = SIGN_NEG;
+ else
+ FPU_loaded_data.sign = SIGN_POS;
+ if (!(m32 & 0x7fffffff)) {
+ /* Zero */
+ int c = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = c;
+ return;
+ }
+ exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
+ m32 = (m32 & 0x7fffff) << 8;
+ if (exp < SINGLE_Emin) {
+ /* De-normals */
+ EXCEPTION(EX_Denormal);
+ FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
+ FPU_loaded_data.tag = TW_Valid;
+ FPU_loaded_data.sigh = m32;
+ FPU_loaded_data.sigl = 0;
+ normalize_nuo(&FPU_loaded_data);
+ return;
+ } else
+ if (exp > SINGLE_Emax) {
+ /* Infinity or NaN */
+ if (m32 == 0) {
+ /* +- infinity */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_Infinity;
+ return;
+ } else {
+ /* Must be a signaling or quiet NaN */
+ FPU_loaded_data.exp = EXTENDED_Emax;
+ FPU_loaded_data.tag = TW_NaN;
+ FPU_loaded_data.sigh = m32 | 0x80000000;
+ FPU_loaded_data.sigl = 0;
+ return;
+ }
+ } else {
+ FPU_loaded_data.exp = exp + EXP_BIAS;
+ FPU_loaded_data.sigh = m32 | 0x80000000;
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.tag = TW_Valid;
+ }
+}
+
+
+/* Get a long long from user memory */
+void
+reg_load_int64(void)
+{
+ long long *_s = (long long *) FPU_data_address;
+ int e;
+ long long s;
+
+ REENTRANT_CHECK(OFF);
+ ((unsigned long *) &s)[0] = fuword((unsigned long *) _s);
+ ((unsigned long *) &s)[1] = fuword(1 + (unsigned long *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 63;
+ *((long long *) &FPU_loaded_data.sigl) = s;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a long from user memory */
+void
+reg_load_int32(void)
+{
+ long *_s = (long *) FPU_data_address;
+ long s;
+ int e;
+
+ REENTRANT_CHECK(OFF);
+ s = (long) fuword((unsigned long *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 31;
+ FPU_loaded_data.sigh = s;
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a short from user memory */
+void
+reg_load_int16(void)
+{
+ short *_s = (short *) FPU_data_address;
+ int s, e;
+
+ REENTRANT_CHECK(OFF);
+ /* Cast as short to get the sign extended. */
+ s = (short) fusword((unsigned short *) _s);
+ REENTRANT_CHECK(ON);
+
+ if (s == 0) {
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ return;
+ }
+ if (s > 0)
+ FPU_loaded_data.sign = SIGN_POS;
+ else {
+ s = -s;
+ FPU_loaded_data.sign = SIGN_NEG;
+ }
+
+ e = EXP_BIAS + 15;
+ FPU_loaded_data.sigh = s << 16;
+
+ FPU_loaded_data.sigl = 0;
+ FPU_loaded_data.exp = e;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+}
+
+
+/* Get a packed bcd array from user memory */
+void
+reg_load_bcd(void)
+{
+ char *s = (char *) FPU_data_address;
+ int pos;
+ unsigned char bcd;
+ long long l = 0;
+
+ for (pos = 8; pos >= 0; pos--) {
+ l *= 10;
+ REENTRANT_CHECK(OFF);
+ bcd = (unsigned char) fubyte((unsigned char *) s + pos);
+ REENTRANT_CHECK(ON);
+ l += bcd >> 4;
+ l *= 10;
+ l += bcd & 0x0f;
+ }
+
+ /* Finish all access to user memory before putting stuff into the
+ * static FPU_loaded_data */
+ REENTRANT_CHECK(OFF);
+ FPU_loaded_data.sign =
+ ((unsigned char) fubyte((unsigned char *) s + 9)) & 0x80 ?
+ SIGN_NEG : SIGN_POS;
+ REENTRANT_CHECK(ON);
+
+ if (l == 0) {
+ char sign = FPU_loaded_data.sign;
+ reg_move(&CONST_Z, &FPU_loaded_data);
+ FPU_loaded_data.sign = sign;
+ } else {
+ *((long long *) &FPU_loaded_data.sigl) = l;
+ FPU_loaded_data.exp = EXP_BIAS + 63;
+ FPU_loaded_data.tag = TW_Valid;
+ normalize_nuo(&FPU_loaded_data);
+ }
+}
+/*===========================================================================*/
+
+/* Put a long double into user memory */
+int
+reg_store_extended(void)
+{
+ long double *d = (long double *) FPU_data_address;
+ long e = FPU_st0_ptr->exp - EXP_BIAS + EXTENDED_Ebias;
+ unsigned short sign = FPU_st0_ptr->sign * 0x8000;
+ unsigned long ls, ms;
+
+
+ if (FPU_st0_tag == TW_Valid) {
+ if (e >= 0x7fff) {
+ EXCEPTION(EX_Overflow); /* Overflow */
+ /* This is a special case: see sec 16.2.5.1 of the
+ * 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ ls = 0;
+ ms = 0x80000000;
+ e = 0x7fff;
+ } else
+ return 0;
+ } else
+ if (e <= 0) {
+ if (e > -63) {
+ /* Correctly format the de-normal */
+ int precision_loss;
+ FPU_REG tmp;
+
+ EXCEPTION(EX_Denormal);
+ reg_move(FPU_st0_ptr, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
+ if ((precision_loss = round_to_int(&tmp))) {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see
+ * sec 16.2.5.1 of the 80486
+ * book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ e = 0;
+ ls = tmp.sigl;
+ ms = tmp.sigh;
+ } else {
+ /* ****** ??? This should not be
+ * possible */
+ EXCEPTION(EX_Underflow); /* Underflow */
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Underflow) {
+ /* Underflow to zero */
+ ls = 0;
+ ms = 0;
+ e = FPU_st0_ptr->sign == SIGN_POS ? 0x7fff : 0xffff;
+ } else
+ return 0;
+ }
+ } else {
+ ls = FPU_st0_ptr->sigl;
+ ms = FPU_st0_ptr->sigh;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ ls = ms = 0;
+ e = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ ls = 0;
+ ms = 0x80000000;
+ e = 0x7fff;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ ls = FPU_st0_ptr->sigl;
+ ms = FPU_st0_ptr->sigh;
+ e = 0x7fff;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ ls = 0;
+ ms = 0xc0000000;
+ e = 0xffff;
+ } else
+ return 0;
+ } else {
+ /* We don't use TW_Denormal
+ * yet ... perhaps never! */
+ EXCEPTION(EX_Invalid);
+ /* Store a NaN */
+ e = 0x7fff;
+ ls = 1;
+ ms = 0x80000000;
+ }
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 10); */
+ suword((unsigned long *) d, ls);
+ suword(1 + (unsigned long *) d, ms);
+ susword(4 + (short *) d, (unsigned short) e | sign);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+
+}
+
+
+/* Put a double into user memory */
+int
+reg_store_double(void)
+{
+ double *dfloat = (double *) FPU_data_address;
+ unsigned long l[2];
+ if (FPU_st0_tag == TW_Valid) {
+ int exp;
+ FPU_REG tmp;
+
+ reg_move(FPU_st0_ptr, &tmp);
+ exp = tmp.exp - EXP_BIAS;
+
+ if (exp < DOUBLE_Emin) { /* It may be a denormal */
+ /* Make a de-normal */
+ int precision_loss;
+
+ if (exp <= -EXTENDED_Ebias)
+ EXCEPTION(EX_Denormal);
+
+ tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */
+
+ if ((precision_loss = round_to_int(&tmp))) {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as
+ * peculiar, it appears that the 80486 rounds
+ * to the dest precision, then converts to
+ * decide underflow. */
+ if ((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
+ (FPU_st0_ptr->sigl & 0x000007ff))
+ EXCEPTION(precision_loss);
+ else
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ }
+ l[0] = tmp.sigl;
+ l[1] = tmp.sigh;
+ } else {
+ if (tmp.sigl & 0x000007ff) {
+ unsigned long increment = 0; /* avoid gcc warnings */
+
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ /* Rounding can get a little messy.. */
+ increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */
+ ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate the mantissa */
+ tmp.sigl &= 0xfffff800;
+
+ if (increment) {
+ set_precision_flag_up();
+
+ if (tmp.sigl >= 0xfffff800) {
+ /* the sigl part overflows */
+ if (tmp.sigh == 0xffffffff) {
+ /* The sigh part
+ * overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ } else {
+ tmp.sigh++;
+ }
+ tmp.sigl = 0x00000000;
+ } else {
+ /* We only need to increment
+ * sigl */
+ tmp.sigl += 0x00000800;
+ }
+ } else
+ set_precision_flag_down();
+ }
+ l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
+ l[1] = ((tmp.sigh >> 11) & 0xfffff);
+
+ if (exp > DOUBLE_Emax) {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ * the 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ l[0] = 0x00000000; /* Set to */
+ l[1] = 0x7ff00000; /* + INF */
+ } else
+ return 0;
+ } else {
+ /* Add the exponent */
+ l[1] |= (((exp + DOUBLE_Ebias) & 0x7ff) << 20);
+ }
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ /* Number is zero */
+ l[0] = 0;
+ l[1] = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ l[0] = 0;
+ l[1] = 0x7ff00000;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ /* See if we can get a valid NaN from
+ * the FPU_REG */
+ l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
+ l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
+ if (!(l[0] | l[1])) {
+ /* This case does not seem to
+ * be handled by the 80486
+ * specs */
+ EXCEPTION(EX_Invalid);
+ /* Make the quiet NaN "real
+ * indefinite" */
+ goto put_indefinite;
+ }
+ l[1] |= 0x7ff00000;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ put_indefinite:
+ REENTRANT_CHECK(OFF);
+ /* verify_area(VERIFY_W
+ * RITE, (void *)
+ * dfloat, 8); */
+ suword((unsigned long *) dfloat, 0);
+ suword(1 + (unsigned long *) dfloat, 0xfff80000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ else
+ if (FPU_st0_tag == TW_Denormal) {
+ /* Extended real ->
+ * double real will
+ * always underflow */
+ l[0] = l[1] = 0;
+ EXCEPTION(EX_Underflow);
+ }
+#endif
+ if (FPU_st0_ptr->sign)
+ l[1] |= 0x80000000;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) dfloat, 8);*/
+ suword((u_long *) dfloat, l[0]);
+ suword((u_long *) dfloat + 1, l[1]);
+/*
+ suword(l[0], (unsigned long *) dfloat);
+ suword(l[1], 1 + (unsigned long *) dfloat);*/
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a float into user memory */
+int
+reg_store_single(void)
+{
+ float *single = (float *) FPU_data_address;
+ long templ = 0;
+
+ if (FPU_st0_tag == TW_Valid) {
+ int exp;
+ FPU_REG tmp;
+
+ reg_move(FPU_st0_ptr, &tmp);
+ exp = tmp.exp - EXP_BIAS;
+
+ if (exp < SINGLE_Emin) {
+ /* Make a de-normal */
+ int precision_loss;
+
+ if (exp <= -EXTENDED_Ebias)
+ EXCEPTION(EX_Denormal);
+
+ tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */
+
+ if ((precision_loss = round_to_int(&tmp))) {
+#ifdef PECULIAR_486
+ /* Did it round to a non-denormal ? */
+ /* This behaviour might be regarded as
+ * peculiar, it appears that the 80486 rounds
+ * to the dest precision, then converts to
+ * decide underflow. */
+ if ((tmp.sigl == 0x00800000) &&
+ ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl))
+ EXCEPTION(precision_loss);
+ else
+#endif /* PECULIAR_486 */
+ {
+ EXCEPTION(EX_Underflow | precision_loss);
+ /* This is a special case: see sec
+ * 16.2.5.1 of the 80486 book */
+ if (!(control_word & EX_Underflow))
+ return 0;
+ }
+ }
+ templ = tmp.sigl;
+ } else {
+ if (tmp.sigl | (tmp.sigh & 0x000000ff)) {
+ unsigned long increment = 0; /* avoid gcc warnings */
+ unsigned long sigh = tmp.sigh;
+ unsigned long sigl = tmp.sigl;
+
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ increment = ((sigh & 0xff) > 0x80) /* more than half */
+ ||(((sigh & 0xff) == 0x80) && sigl) /* more than half */
+ ||((sigh & 0x180) == 0x180); /* round to even */
+ break;
+ case RC_DOWN: /* towards -infinity */
+ increment = (tmp.sign == SIGN_POS)
+ ? 0 : (sigl | (sigh & 0xff));
+ break;
+ case RC_UP: /* towards +infinity */
+ increment = (tmp.sign == SIGN_POS)
+ ? (sigl | (sigh & 0xff)) : 0;
+ break;
+ case RC_CHOP:
+ increment = 0;
+ break;
+ }
+
+ /* Truncate part of the mantissa */
+ tmp.sigl = 0;
+
+ if (increment) {
+ set_precision_flag_up();
+
+ if (sigh >= 0xffffff00) {
+ /* The sigh part overflows */
+ tmp.sigh = 0x80000000;
+ exp++;
+ if (exp >= EXP_OVER)
+ goto overflow;
+ } else {
+ tmp.sigh &= 0xffffff00;
+ tmp.sigh += 0x100;
+ }
+ } else {
+ set_precision_flag_down();
+ tmp.sigh &= 0xffffff00; /* Finish the truncation */
+ }
+ }
+ templ = (tmp.sigh >> 8) & 0x007fffff;
+
+ if (exp > SINGLE_Emax) {
+ overflow:
+ EXCEPTION(EX_Overflow);
+ /* This is a special case: see sec 16.2.5.1 of
+ * the 80486 book */
+ if (control_word & EX_Overflow) {
+ /* Overflow to infinity */
+ templ = 0x7f800000;
+ } else
+ return 0;
+ } else
+ templ |= ((exp + SINGLE_Ebias) & 0xff) << 23;
+ }
+ } else
+ if (FPU_st0_tag == TW_Zero) {
+ templ = 0;
+ } else
+ if (FPU_st0_tag == TW_Infinity) {
+ templ = 0x7f800000;
+ } else
+ if (FPU_st0_tag == TW_NaN) {
+ /* See if we can get a valid NaN from
+ * the FPU_REG */
+ templ = FPU_st0_ptr->sigh >> 8;
+ if (!(templ & 0x3fffff)) {
+ /* This case does not seem to
+ * be handled by the 80486
+ * specs */
+ EXCEPTION(EX_Invalid);
+ /* Make the quiet NaN "real
+ * indefinite" */
+ goto put_indefinite;
+ }
+ templ |= 0x7f800000;
+ } else
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack
+ * underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN
+ * indefinite */
+ put_indefinite:
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) single, 4); */
+ suword((unsigned long *) single, 0xffc00000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ else
+ if (FPU_st0_tag == TW_Denormal) {
+ /* Extended real ->
+ * real will always
+ * underflow */
+ templ = 0;
+ EXCEPTION(EX_Underflow);
+ }
+#endif
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x106);
+ return 0;
+ }
+#endif
+ if (FPU_st0_ptr->sign)
+ templ |= 0x80000000;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) single, 4); */
+ suword((unsigned long *) single, templ);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a long long into user memory */
+int
+reg_store_int64(void)
+{
+ long long *d = (long long *) FPU_data_address;
+ FPU_REG t;
+ long long tll;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ goto put_indefinite;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ ((long *) &tll)[0] = t.sigl;
+ ((long *) &tll)[1] = t.sigh;
+ if ((t.sigh & 0x80000000) &&
+ !((t.sigh == 0x80000000) && (t.sigl == 0) && (t.sign == SIGN_NEG))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ put_indefinite:
+ ((long *) &tll)[1] = 0x80000000;
+ ((long *) &tll)[0] = 0;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ tll = -tll;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, (void *) d, 8); */
+ suword((unsigned long *) d, ((long *) &tll)[0]);
+ suword(1 + (unsigned long *) d, ((long *) &tll)[1]);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a long into user memory */
+int
+reg_store_int32(void)
+{
+ long *d = (long *) FPU_data_address;
+ FPU_REG t;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 4);*/
+ suword((unsigned long *) d, 0x80000000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ if (t.sigh ||
+ ((t.sigl & 0x80000000) &&
+ !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG)))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ t.sigl = 0x80000000;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ t.sigl = -(long) t.sigl;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 4); */
+ suword((unsigned long *) d, t.sigl);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a short into user memory */
+int
+reg_store_int16(void)
+{
+ short *d = (short *) FPU_data_address;
+ FPU_REG t;
+ short ts;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 2);*/
+ susword((unsigned short *) d, 0x8000);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ if (t.sigh ||
+ ((t.sigl & 0xffff8000) &&
+ !((t.sigl == 0x8000) && (t.sign == SIGN_NEG)))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ /* Produce "indefinite" */
+ ts = 0x8000;
+ } else
+ return 0;
+ } else
+ if (t.sign)
+ t.sigl = -t.sigl;
+
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 2); */
+ susword((short *) d, (short) t.sigl);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+
+
+/* Put a packed bcd array into user memory */
+int
+reg_store_bcd(void)
+{
+ char *d = (char *) FPU_data_address;
+ FPU_REG t;
+ long long ll;
+ unsigned char b;
+ int i;
+ unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
+
+ if (FPU_st0_tag == TW_Empty) {
+ /* Empty register (stack underflow) */
+ EXCEPTION(EX_StackUnder);
+ if (control_word & EX_Invalid) {
+ /* The masked response */
+ /* Put out the QNaN indefinite */
+ goto put_indefinite;
+ } else
+ return 0;
+ }
+ reg_move(FPU_st0_ptr, &t);
+ round_to_int(&t);
+ ll = *(long long *) (&t.sigl);
+
+ /* Check for overflow, by comparing with 999999999999999999 decimal. */
+ if ((t.sigh > 0x0de0b6b3) ||
+ ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff))) {
+ EXCEPTION(EX_Invalid);
+ /* This is a special case: see sec 16.2.5.1 of the 80486 book */
+ if (control_word & EX_Invalid) {
+ put_indefinite:
+ /* Produce "indefinite" */
+ REENTRANT_CHECK(OFF);
+/* verify_area(VERIFY_WRITE, d, 10);*/
+ subyte((unsigned char *) d + 7, 0xff);
+ subyte((unsigned char *) d + 8, 0xff);
+ subyte((unsigned char *) d + 9, 0xff);
+ REENTRANT_CHECK(ON);
+ return 1;
+ } else
+ return 0;
+ }
+/* verify_area(VERIFY_WRITE, d, 10);*/
+ for (i = 0; i < 9; i++) {
+ b = div_small(&ll, 10);
+ b |= (div_small(&ll, 10)) << 4;
+ REENTRANT_CHECK(OFF);
+ subyte((unsigned char *) d + i, b);
+ REENTRANT_CHECK(ON);
+ }
+ REENTRANT_CHECK(OFF);
+ subyte((unsigned char *) d + 9, sign);
+ REENTRANT_CHECK(ON);
+
+ return 1;
+}
+/*===========================================================================*/
+
+/* r gets mangled such that sig is int, sign:
+ it is NOT normalized */
+/* The return value (in eax) is zero if the result is exact,
+ if bits are changed due to rounding, truncation, etc, then
+ a non-zero value is returned */
+/* Overflow is signalled by a non-zero return value (in eax).
+ In the case of overflow, the returned significand always has the
+ the largest possible value */
+/* The value returned in eax is never actually needed :-) */
+int
+round_to_int(FPU_REG * r)
+{
+ char very_big;
+ unsigned eax;
+
+ if (r->tag == TW_Zero) {
+ /* Make sure that zero is returned */
+ *(long long *) &r->sigl = 0;
+ return 0; /* o.k. */
+ }
+ if (r->exp > EXP_BIAS + 63) {
+ r->sigl = r->sigh = ~0; /* The largest representable number */
+ return 1; /* overflow */
+ }
+ eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
+ very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */
+#define half_or_more (eax & 0x80000000)
+#define frac_part (eax)
+#define more_than_half ((eax & 0x80000001) == 0x80000001)
+ switch (control_word & CW_RC) {
+ case RC_RND:
+ if (more_than_half /* nearest */
+ || (half_or_more && (r->sigl & 1))) { /* odd -> even */
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_DOWN:
+ if (frac_part && r->sign) {
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_UP:
+ if (frac_part && !r->sign) {
+ if (very_big)
+ return 1; /* overflow */
+ (*(long long *) (&r->sigl))++;
+ return LOST_UP;
+ }
+ break;
+ case RC_CHOP:
+ break;
+ }
+
+ return eax ? LOST_DOWN : 0;
+
+}
+/*===========================================================================*/
+
+char *
+fldenv(void)
+{
+ char *s = (char *) FPU_data_address;
+ unsigned short tag_word = 0;
+ unsigned char tag;
+ int i;
+
+ REENTRANT_CHECK(OFF);
+ control_word = fusword((unsigned short *) s);
+ status_word = fusword((unsigned short *) (s + 4));
+ tag_word = fusword((unsigned short *) (s + 8));
+ ip_offset = fuword((unsigned long *) (s + 0x0c));
+ cs_selector = fuword((unsigned long *) (s + 0x10));
+ data_operand_offset = fuword((unsigned long *) (s + 0x14));
+ operand_selector = fuword((unsigned long *) (s + 0x18));
+ REENTRANT_CHECK(ON);
+
+ top = (status_word >> SW_Top_Shift) & 7;
+
+ for (i = 0; i < 8; i++) {
+ tag = tag_word & 3;
+ tag_word >>= 2;
+
+ switch (tag) {
+ case 0:
+ regs[i].tag = TW_Valid;
+ break;
+ case 1:
+ regs[i].tag = TW_Zero;
+ break;
+ case 2:
+ regs[i].tag = TW_NaN;
+ break;
+ case 3:
+ regs[i].tag = TW_Empty;
+ break;
+ }
+ }
+
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+ FPU_entry_eip = ip_offset; /* We want no net effect */
+
+ return s + 0x1c;
+}
+
+
+void
+frstor(void)
+{
+ int i, stnr;
+ unsigned char tag;
+ unsigned short saved_status, saved_control;
+ char *s = (char *) fldenv();
+
+ saved_status = status_word;
+ saved_control = control_word;
+ control_word = 0x037f; /* Mask all interrupts while we load. */
+ for (i = 0; i < 8; i++) {
+ /* load each register */
+ FPU_data_address = (void *) (s + i * 10);
+ reg_load_extended();
+ stnr = (i + top) & 7;
+ tag = regs[stnr].tag; /* derived from the loaded tag word */
+ reg_move(&FPU_loaded_data, &regs[stnr]);
+ if (tag == TW_NaN) {
+ /* The current data is a special, i.e. NaN,
+ * unsupported, infinity, or denormal */
+ unsigned char t = regs[stnr].tag; /* derived from the new
+ * data */
+ if ( /* (t == TW_Valid) || *** */ (t == TW_Zero))
+ regs[stnr].tag = TW_NaN;
+ } else
+ regs[stnr].tag = tag;
+ }
+ control_word = saved_control;
+ status_word = saved_status;
+
+ FPU_data_address = (void *) data_operand_offset; /* We want no net effect */
+}
+
+
+unsigned short
+tag_word(void)
+{
+ unsigned short word = 0;
+ unsigned char tag;
+ int i;
+
+ for (i = 7; i >= 0; i--) {
+ switch (tag = regs[i].tag) {
+#if 0 /* TW_Denormal is not used yet, and probably
+ * won't be */
+ case TW_Denormal:
+#endif
+ case TW_Valid:
+ if (regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias))
+ tag = 2;
+ break;
+ case TW_Infinity:
+ case TW_NaN:
+ tag = 2;
+ break;
+ case TW_Empty:
+ tag = 3;
+ break;
+ /* TW_Valid and TW_Zero already have the correct value */
+ }
+ word <<= 2;
+ word |= tag;
+ }
+ return word;
+}
+
+
+char *
+fstenv(void)
+{
+ char *d = (char *) FPU_data_address;
+
+/* verify_area(VERIFY_WRITE, d, 28);*/
+
+#if 0 /****/
+ *(unsigned short *) &cs_selector = fpu_cs;
+ *(unsigned short *) &operand_selector = fpu_os;
+#endif /****/
+
+ REENTRANT_CHECK(OFF);
+ susword((unsigned short *) d, control_word);
+ susword((unsigned short *) (d + 4), (status_word & ~SW_Top) | ((top & 7) << SW_Top_Shift));
+ susword((unsigned short *) (d + 8), tag_word());
+ suword((unsigned long *) (d + 0x0c), ip_offset);
+ suword((unsigned long *) (d + 0x10), cs_selector);
+ suword((unsigned long *) (d + 0x14), data_operand_offset);
+ suword((unsigned long *) (d + 0x18), operand_selector);
+ REENTRANT_CHECK(ON);
+
+ return d + 0x1c;
+}
+
+
+void
+fsave(void)
+{
+ char *d;
+ FPU_REG tmp, *rp;
+ int i;
+ short e;
+
+ d = fstenv();
+/* verify_area(VERIFY_WRITE, d, 80);*/
+ for (i = 0; i < 8; i++) {
+ /* Store each register in the order: st(0), st(1), ... */
+ rp = &regs[(top + i) & 7];
+
+ e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
+
+ if (rp->tag == TW_Valid) {
+ if (e >= 0x7fff) {
+ /* Overflow to infinity */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (e <= 0) {
+ if (e > -63) {
+ /* Make a de-normal */
+ reg_move(rp, &tmp);
+ tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 62 */
+ round_to_int(&tmp);
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), tmp.sigl);
+ suword((unsigned long *) (d + i * 10 + 4), tmp.sigh);
+ REENTRANT_CHECK(ON);
+ } else {
+ /* Underflow to zero */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ }
+ e = 0;
+ } else {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ }
+ } else
+ if (rp->tag == TW_Zero) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0);
+ REENTRANT_CHECK(ON);
+ e = 0;
+ } else
+ if (rp->tag == TW_Infinity) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), 0);
+ suword((unsigned long *) (d + i * 10 + 4), 0x80000000);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (rp->tag == TW_NaN) {
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ e = 0x7fff;
+ } else
+ if (rp->tag == TW_Empty) {
+ /* just copy the reg */
+ REENTRANT_CHECK(OFF);
+ suword((unsigned long *) (d + i * 10), rp->sigl);
+ suword((unsigned long *) (d + i * 10 + 4), rp->sigh);
+ REENTRANT_CHECK(ON);
+ }
+ e |= rp->sign == SIGN_POS ? 0 : 0x8000;
+ REENTRANT_CHECK(OFF);
+ susword((unsigned short *) (d + i * 10 + 8), e);
+ REENTRANT_CHECK(ON);
+ }
+
+ finit();
+
+}
+/*===========================================================================*/
diff --git a/sys/gnu/arch/i386/fpemul/reg_mul.c b/sys/gnu/arch/i386/fpemul/reg_mul.c
new file mode 100644
index 00000000000..07187c93cff
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_mul.c
@@ -0,0 +1,163 @@
+/* $OpenBSD: reg_mul.c,v 1.1 1996/08/27 10:33:00 downsj Exp $ */
+/*
+ * reg_mul.c
+ *
+ * Multiply one FPU_REG by another, put the result in a destination FPU_REG.
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_mul.c,v 1.3 1994/06/10 07:44:53 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | The destination may be any FPU_REG, including one of the source FPU_REGs. |
+ +---------------------------------------------------------------------------*/
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/reg_constant.h>
+#include <gnu/arch/i386/fpemul/fpu_emu.h>
+#include <gnu/arch/i386/fpemul/fpu_system.h>
+
+
+/* This routine must be called with non-empty source registers */
+void
+reg_mul(FPU_REG * a, FPU_REG * b, FPU_REG * dest, unsigned int control_w)
+{
+ char sign = (a->sign ^ b->sign);
+
+ if (!(a->tag | b->tag)) {
+ /* This should be the most common case */
+ reg_u_mul(a, b, dest, control_w);
+ dest->sign = sign;
+ return;
+ } else
+ if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero)) {
+#ifdef DENORM_OPERAND
+ if (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ||
+ ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER))) {
+ if (denormal_operand())
+ return;
+ }
+#endif /* DENORM_OPERAND */
+ /* Must have either both arguments == zero, or one
+ * valid and the other zero. The result is therefore
+ * zero. */
+ reg_move(&CONST_Z, dest);
+#ifdef PECULIAR_486
+ /* The 80486 book says that the answer is +0, but a
+ * real 80486 appears to behave this way... */
+ dest->sign = sign;
+#endif /* PECULIAR_486 */
+ return;
+ }
+#if 0 /* TW_Denormal is not used yet... perhaps
+ * never will be. */
+ else
+ if ((a->tag <= TW_Denormal) && (b->tag <= TW_Denormal)) {
+ /* One or both arguments are de-normalized */
+ /* Internal de-normalized numbers are not
+ * supported yet */
+ EXCEPTION(EX_INTERNAL | 0x105);
+ reg_move(&CONST_Z, dest);
+ }
+#endif
+ else {
+ /* Must have infinities, NaNs, etc */
+ if ((a->tag == TW_NaN) || (b->tag == TW_NaN)) {
+ real_2op_NaN(a, b, dest);
+ return;
+ } else
+ if (a->tag == TW_Infinity) {
+ if (b->tag == TW_Zero) {
+ arith_invalid(dest);
+ return;
+ }
+ /* Zero*Infinity is invalid */
+ else {
+#ifdef DENORM_OPERAND
+ if ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(a, dest);
+ dest->sign = sign;
+ }
+ return;
+ } else
+ if (b->tag == TW_Infinity) {
+ if (a->tag == TW_Zero) {
+ arith_invalid(dest);
+ return;
+ }
+ /* Zero*Infinity is
+ * invalid */
+ else {
+#ifdef DENORM_OPERAND
+ if ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER) &&
+ denormal_operand())
+ return;
+#endif /* DENORM_OPERAND */
+ reg_move(b, dest);
+ dest->sign = sign;
+ }
+ return;
+ }
+#ifdef PARANOID
+ else {
+ EXCEPTION(EX_INTERNAL | 0x102);
+ }
+#endif /* PARANOID */
+ }
+}
diff --git a/sys/gnu/arch/i386/fpemul/reg_norm.s b/sys/gnu/arch/i386/fpemul/reg_norm.s
new file mode 100644
index 00000000000..58fe0b4f9e3
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_norm.s
@@ -0,0 +1,185 @@
+/* $OpenBSD: reg_norm.s,v 1.1 1996/08/27 10:33:00 downsj Exp $ */
+/*
+ * reg_norm.s
+ *
+ * Normalize the value in a FPU_REG.
+ *
+ * Call from C as:
+ * void normalize(FPU_REG *n)
+ *
+ * void normalize_nuo(FPU_REG *n)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_norm.s,v 1.3 1994/06/10 07:44:54 rich Exp $
+ *
+ */
+
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+
+.text
+
+ .align 2,144
+.globl _normalize
+
+_normalize:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_done /* Already normalized */
+ jnz L_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_zero /* The contents are zero */
+
+/* L_shift_32: */
+ movl %eax,%edx
+ xorl %eax,%eax
+ subl $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+
+L_done:
+ cmpl EXP_OVER,EXP(%ebx)
+ jge L_overflow
+
+ cmpl EXP_UNDER,EXP(%ebx)
+ jle L_underflow
+
+L_exit:
+ popl %ebx
+ leave
+ ret
+
+
+L_zero:
+ movl EXP_UNDER,EXP(%ebx)
+ movb TW_Zero,TAG(%ebx)
+ jmp L_exit
+
+L_underflow:
+ push %ebx
+ call _arith_underflow
+ pop %ebx
+ jmp L_exit
+
+L_overflow:
+ push %ebx
+ call _arith_overflow
+ pop %ebx
+ jmp L_exit
+
+
+
+/* Normalise without reporting underflow or overflow */
+ .align 2,144
+.globl _normalize_nuo
+
+_normalize_nuo:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %ebx
+
+ movl PARAM1,%ebx
+
+ movl SIGH(%ebx),%edx
+ movl SIGL(%ebx),%eax
+
+ orl %edx,%edx /* ms bits */
+ js L_exit /* Already normalized */
+ jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
+
+ orl %eax,%eax
+ jz L_zero /* The contents are zero */
+
+/* L_nuo_shift_32: */
+ movl %eax,%edx
+ xorl %eax,%eax
+ subl $32,EXP(%ebx) /* This can cause an underflow */
+
+/* We need to shift left by 1 - 31 bits */
+L_nuo_shift_1:
+ bsrl %edx,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%eax,%edx
+ shl %cl,%eax
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
+
+ movl %edx,SIGH(%ebx)
+ movl %eax,SIGL(%ebx)
+ jmp L_exit
+
+
diff --git a/sys/gnu/arch/i386/fpemul/reg_round.s b/sys/gnu/arch/i386/fpemul/reg_round.s
new file mode 100644
index 00000000000..15a37128d47
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_round.s
@@ -0,0 +1,656 @@
+ .file "reg_round.S"
+/* $OpenBSD: reg_round.s,v 1.1 1996/08/27 10:33:01 downsj Exp $ */
+/*
+ * reg_round.S
+ *
+ * Rounding/truncation/etc for FPU basic arithmetic functions.
+ *
+ * This code has four possible entry points.
+ * The following must be entered by a jmp intruction:
+ * FPU_round, FPU_round_sqrt, and FPU_Arith_exit.
+ *
+ * The _round_reg entry point is intended to be used by C code.
+ * From C, call as:
+ * void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_round.s,v 1.3 1994/06/10 07:44:55 rich Exp $
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | Four entry points. |
+ | |
+ | Needed by both the FPU_round and FPU_round_sqrt entry points: |
+ | %eax:%ebx 64 bit significand |
+ | %edx 32 bit extension of the significand |
+ | %edi pointer to an FPU_REG for the result to be stored |
+ | stack calling function must have set up a C stack frame and |
+ | pushed %esi, %edi, and %ebx |
+ | |
+ | Needed just for the FPU_round_sqrt entry point: |
+ | %cx A control word in the same format as the FPU control word. |
+ | Otherwise, PARAM4 must give such a value. |
+ | |
+ | |
+ | The significand and its extension are assumed to be exact in the |
+ | following sense: |
+ | If the significand by itself is the exact result then the significand |
+ | extension (%edx) must contain 0, otherwise the significand extension |
+ | must be non-zero. |
+ | If the significand extension is non-zero then the significand is |
+ | smaller than the magnitude of the correct exact result by an amount |
+ | greater than zero and less than one ls bit of the significand. |
+ | The significand extension is only required to have three possible |
+ | non-zero values: |
+ | less than 0x80000000 <=> the significand is less than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit |
+ | smaller than the magnitude of the true |
+ | exact result. |
+ | greater than 0x80000000 <=> the significand is more than 1/2 an ls |
+ | bit smaller than the magnitude of the |
+ | true exact result. |
+ | |
+ +---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------+
+ | The code in this module has become quite complex, but it should handle |
+ | all of the FPU flags which are set at this stage of the basic arithmetic |
+ | computations. |
+ | There are a few rare cases where the results are not set identically to |
+ | a real FPU. These require a bit more thought because at this stage the |
+ | results of the code here appear to be more consistent... |
+ | This may be changed in a future version. |
+ +---------------------------------------------------------------------------*/
+
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+#define LOST_DOWN $1
+#define LOST_UP $2
+#define DENORMAL $1
+#define UNMASKED_UNDERFLOW $2
+
+.data
+ .align 2,0
+FPU_bits_lost:
+ .byte 0
+FPU_denormal:
+ .byte 0
+
+.text
+ .align 2,144
+.globl FPU_round
+.globl FPU_round_sqrt
+.globl FPU_Arith_exit
+.globl _round_reg
+
+/* Entry point when called from C */
+_round_reg:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%edi
+ movl SIGH(%edi),%eax
+ movl SIGL(%edi),%ebx
+ movl PARAM2,%edx
+ movl PARAM3,%ecx
+ jmp FPU_round_sqrt
+
+FPU_round: /* Normal entry point */
+ movl PARAM4,%ecx
+
+FPU_round_sqrt: /* Entry point from wm_sqrt.S */
+
+#ifdef PARANOID
+/* Cannot use this here yet */
+/* orl %eax,%eax */
+/* jns L_entry_bugged */
+#endif PARANOID
+
+ cmpl EXP_UNDER,EXP(%edi)
+ jle xMake_denorm /* The number is a de-normal*/
+
+ movb $0,FPU_denormal /* 0 -> not a de-normal*/
+
+xDenorm_done:
+ movb $0,FPU_bits_lost /*No bits yet lost in rounding*/
+
+ movl %ecx,%esi
+ andl CW_PC,%ecx
+ cmpl PR_64_BITS,%ecx
+ je LRound_To_64
+
+ cmpl PR_53_BITS,%ecx
+ je LRound_To_53
+
+ cmpl PR_24_BITS,%ecx
+ je LRound_To_24
+
+#ifdef PARANOID
+ jmp L_bugged /* There is no bug, just a bad control word */
+#endif PARANOID
+
+
+/* Round etc to 24 bit precision */
+LRound_To_24:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_24
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_24
+
+ cmpl RC_UP,%ecx /* Towards +infinity */
+ je LUp_24
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
+ je LDown_24
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_24:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_24 /* If negative then up==truncate */
+
+ jmp LCheck_24_round_up
+
+LDown_24:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_24 /* If positive then down==truncate */
+
+LCheck_24_round_up:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jnz LDo_24_round_up
+ jmp LRe_normalise
+
+LRound_nearest_24:
+ /* Do rounding of the 24th bit if needed (nearest or even) */
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ cmpl $0x00000080,%ecx
+ jc LCheck_truncate_24 /*less than half, no increment needed*/
+
+ jne LGreater_Half_24 /* greater than half, increment needed*/
+
+ /* Possibly half, we need to check the ls bits */
+ orl %ebx,%ebx
+ jnz LGreater_Half_24 /* greater than half, increment needed*/
+
+ orl %edx,%edx
+ jnz LGreater_Half_24 /* greater than half, increment needed*/
+
+ /* Exactly half, increment only if 24th bit is 1 (round to even)*/
+ testl $0x00000100,%eax
+ jz LDo_truncate_24
+
+LGreater_Half_24: /*Rounding: increment at the 24th bit*/
+LDo_24_round_up:
+ andl $0xffffff00,%eax /*Truncate to 24 bits*/
+ xorl %ebx,%ebx
+ movb LOST_UP,FPU_bits_lost
+ addl $0x00000100,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_24:
+ movl %eax,%ecx
+ andl $0x000000ff,%ecx
+ orl %ebx,%ecx
+ orl %edx,%ecx
+ jz LRe_normalise /* No truncation needed*/
+
+LDo_truncate_24:
+ andl $0xffffff00,%eax /* Truncate to 24 bits*/
+ xorl %ebx,%ebx
+ movb LOST_DOWN,FPU_bits_lost
+ jmp LRe_normalise
+
+
+/* Round etc to 53 bit precision */
+LRound_To_53:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_53
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_53
+
+ cmpl RC_UP,%ecx /* Towards +infinity*/
+ je LUp_53
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity*/
+ je LDown_53
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_53:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_53 /* If negative then up==truncate*/
+
+ jmp LCheck_53_round_up
+
+LDown_53:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_53 /* If positive then down==truncate*/
+
+LCheck_53_round_up:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jnz LDo_53_round_up
+ jmp LRe_normalise
+
+LRound_nearest_53:
+ /*Do rounding of the 53rd bit if needed (nearest or even)*/
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ cmpl $0x00000400,%ecx
+ jc LCheck_truncate_53 /* less than half, no increment needed*/
+
+ jnz LGreater_Half_53 /* greater than half, increment needed*/
+
+ /*Possibly half, we need to check the ls bits*/
+ orl %edx,%edx
+ jnz LGreater_Half_53 /* greater than half, increment needed*/
+
+ /* Exactly half, increment only if 53rd bit is 1 (round to even)*/
+ testl $0x00000800,%ebx
+ jz LTruncate_53
+
+LGreater_Half_53: /*Rounding: increment at the 53rd bit*/
+LDo_53_round_up:
+ movb LOST_UP,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits*/
+ addl $0x00000800,%ebx
+ adcl $0,%eax
+ jmp LCheck_Round_Overflow
+
+LCheck_truncate_53:
+ movl %ebx,%ecx
+ andl $0x000007ff,%ecx
+ orl %edx,%ecx
+ jz LRe_normalise
+
+LTruncate_53:
+ movb LOST_DOWN,FPU_bits_lost
+ andl $0xfffff800,%ebx /* Truncate to 53 bits*/
+ jmp LRe_normalise
+
+
+/* Round etc to 64 bit precision*/
+LRound_To_64:
+ movl %esi,%ecx
+ andl CW_RC,%ecx
+ cmpl RC_RND,%ecx
+ je LRound_nearest_64
+
+ cmpl RC_CHOP,%ecx
+ je LCheck_truncate_64
+
+ cmpl RC_UP,%ecx /* Towards +infinity*/
+ je LUp_64
+
+ cmpl RC_DOWN,%ecx /* Towards -infinity*/
+ je LDown_64
+
+#ifdef PARANOID
+ jmp L_bugged
+#endif PARANOID
+
+LUp_64:
+ cmpb SIGN_POS,SIGN(%edi)
+ jne LCheck_truncate_64 /* If negative then up==truncate*/
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp LRe_normalise
+
+LDown_64:
+ cmpb SIGN_POS,SIGN(%edi)
+ je LCheck_truncate_64 /*If positive then down==truncate*/
+
+ orl %edx,%edx
+ jnz LDo_64_round_up
+ jmp LRe_normalise
+
+LRound_nearest_64:
+ cmpl $0x80000000,%edx
+ jc LCheck_truncate_64
+
+ jne LDo_64_round_up
+
+ /* Now test for round-to-even */
+ testb $1,%ebx
+ jz LCheck_truncate_64
+
+LDo_64_round_up:
+ movb LOST_UP,FPU_bits_lost
+ addl $1,%ebx
+ adcl $0,%eax
+
+LCheck_Round_Overflow:
+ jnc LRe_normalise /* Rounding done, no overflow */
+
+ /* Overflow, adjust the result (to 1.0) */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ incl EXP(%edi)
+ jmp LRe_normalise
+
+LCheck_truncate_64:
+ orl %edx,%edx
+ jz LRe_normalise
+
+LTruncate_64:
+ movb LOST_DOWN,FPU_bits_lost
+
+LRe_normalise:
+ testb $0xff,FPU_denormal
+ jnz xNormalise_result
+
+xL_Normalised:
+ cmpb LOST_UP,FPU_bits_lost
+ je xL_precision_lost_up
+
+ cmpb LOST_DOWN,FPU_bits_lost
+ je xL_precision_lost_down
+
+xL_no_precision_loss:
+ cmpl EXP_OVER,EXP(%edi)
+ jge L_overflow
+
+ /* store the result */
+ movb TW_Valid,TAG(%edi)
+
+xL_Store_significand:
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+FPU_Arith_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+/* Set the FPU status flags to represent precision loss due to*/
+/* round-up.*/
+xL_precision_lost_up:
+ push %eax
+ call _set_precision_flag_up
+ popl %eax
+ jmp xL_no_precision_loss
+
+/* Set the FPU status flags to represent precision loss due to*/
+/* truncation.*/
+xL_precision_lost_down:
+ push %eax
+ call _set_precision_flag_down
+ popl %eax
+ jmp xL_no_precision_loss
+
+
+/* The number is a denormal (which might get rounded up to a normal)
+// Shift the number right the required number of bits, which will
+// have to be undone later...*/
+xMake_denorm:
+ /* The action to be taken depends upon whether the underflow
+ // exception is masked*/
+ testb CW_Underflow,%cl /* Underflow mask.*/
+ jz xUnmasked_underflow /* Do not make a denormal.*/
+
+ movb DENORMAL,FPU_denormal
+
+ pushl %ecx /* Save*/
+ movl EXP(%edi),%ecx
+ subl EXP_UNDER+1,%ecx
+ negl %ecx
+
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc xDenorm_shift_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc xDenorm_shift_more_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+// is for a small de-normalising shift.
+// Shift by [1..31] bits */
+ addl %ecx,EXP(%edi)
+ orl %edx,%edx /* extension*/
+ setne %ch
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orb %ch,%dl
+ popl %ecx
+ jmp xDenorm_done
+
+/* Shift by [32..63] bits*/
+xDenorm_shift_more_than_32:
+ addl %ecx,EXP(%edi)
+ subb $32,%cl
+ orl %edx,%edx
+ setne %ch
+ orb %ch,%bl
+ xorl %edx,%edx
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %edx,%edx /*test these 32 bits*/
+ setne %cl
+ orb %ch,%bl
+ orb %cl,%bl
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ popl %ecx
+ jmp xDenorm_done
+
+/* Shift by [64..) bits*/
+xDenorm_shift_more_than_63:
+ cmpl $64,%ecx
+ jne xDenorm_shift_more_than_64
+
+/* Exactly 64 bit shift*/
+ addl %ecx,EXP(%edi)
+ xorl %ecx,%ecx
+ orl %edx,%edx
+ setne %cl
+ orl %ebx,%ebx
+ setne %ch
+ orb %ch,%cl
+ orb %cl,%al
+ movl %eax,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp xDenorm_done
+
+xDenorm_shift_more_than_64:
+ movl EXP_UNDER+1,EXP(%edi)
+/* This is easy, %eax must be non-zero, so..*/
+ movl $1,%edx
+ xorl %eax,%eax
+ xorl %ebx,%ebx
+ popl %ecx
+ jmp xDenorm_done
+
+
+xUnmasked_underflow:
+ /* Increase the exponent by the magic number*/
+ addl $(3*(1<<13)),EXP(%edi)
+ movb UNMASKED_UNDERFLOW,FPU_denormal
+ jmp xDenorm_done
+
+
+/* Undo the de-normalisation.*/
+xNormalise_result:
+ cmpb UNMASKED_UNDERFLOW,FPU_denormal
+ je xSignal_underflow
+
+/* The number must be a denormal if we got here.*/
+#ifdef PARANOID
+ /* But check it... just in case.*/
+ cmpl EXP_UNDER+1,EXP(%edi)
+ jne L_norm_bugged
+#endif PARANOID
+
+ orl %eax,%eax /* ms bits*/
+ jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits*/
+
+ orl %ebx,%ebx
+ jz L_underflow_to_zero /* The contents are zero*/
+
+/* Shift left 32 - 63 bits*/
+ movl %ebx,%eax
+ xorl %ebx,%ebx
+ subl $32,EXP(%edi)
+
+LNormalise_shift_up_to_31:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shl %cl,%ebx
+ subl %ecx,EXP(%edi)
+
+LNormalise_shift_done:
+ testb $0xff,FPU_bits_lost /* bits lost == underflow*/
+ jz xL_Normalised
+
+ /* There must be a masked underflow*/
+ push %eax
+ pushl EX_Underflow
+ call _exception
+ popl %eax
+ popl %eax
+ jmp xL_Normalised
+
+
+/* The operations resulted in a number too small to represent.
+// Masked response.*/
+L_underflow_to_zero:
+ push %eax
+ call _set_precision_flag_down
+ popl %eax
+
+ push %eax
+ pushl EX_Underflow
+ call _exception
+ popl %eax
+ popl %eax
+
+ movb TW_Zero,TAG(%edi)
+ jmp xL_Store_significand
+
+
+/* The operations resulted in a number too large to represent.*/
+L_overflow:
+ push %edi
+ call _arith_overflow
+ pop %edi
+ jmp FPU_Arith_exit
+
+
+xSignal_underflow:
+ push %eax
+ pushl EX_Underflow
+ call EXCEPTION
+ popl %eax
+ popl %eax
+ jmp xL_Normalised
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+
+L_norm_bugged:
+ pushl EX_INTERNAL|0x216
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+
+L_entry_bugged:
+ pushl EX_INTERNAL|0x217
+ call EXCEPTION
+ popl %ebx
+ jmp FPU_Arith_exit
+#endif PARANOID
diff --git a/sys/gnu/arch/i386/fpemul/reg_u_add.s b/sys/gnu/arch/i386/fpemul/reg_u_add.s
new file mode 100644
index 00000000000..1d0eb63bfc0
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_u_add.s
@@ -0,0 +1,247 @@
+ .file "reg_u_add.S"
+/* $OpenBSD: reg_u_add.s,v 1.1 1996/08/27 10:33:01 downsj Exp $ */
+/*
+ * reg_u_add.S
+ *
+ * Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the
+ * result in a destination FPU_REG.
+ *
+ * Call from C as:
+ * void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+ * int control_w)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_u_add.s,v 1.3 1994/06/10 07:44:56 rich Exp $
+ *
+ */
+
+
+/*
+ | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their sum as a TW_Valid or TW_S f.p. number.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+.text
+ .align 2,144
+.globl _reg_u_add
+_reg_u_add:
+ pushl %ebp
+ movl %esp,%ebp
+/* subl $16,%esp*/
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ cmpl EXP_UNDER,EXP(%edi)
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+/* xorl %ecx,%ecx*/
+ movl EXP(%esi),%ecx
+ subl EXP(%edi),%ecx /* exp1 - exp2 */
+/* jnc L_arg1_larger*/
+ jge L_arg1_larger
+
+ /* num1 is smaller */
+ movl SIGL(%esi),%ebx
+ movl SIGH(%esi),%eax
+
+ movl %edi,%esi
+ negw %cx
+ jmp L_accum_loaded
+
+L_arg1_larger:
+ /* num1 has larger or equal exponent */
+ movl SIGL(%edi),%ebx
+ movl SIGH(%edi),%eax
+
+L_accum_loaded:
+ movl PARAM3,%edi /* destination */
+ movb SIGN(%esi),%dl
+ movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+
+
+ movl EXP(%esi),%edx
+ movl %edx,EXP(%edi) /* Copy exponent to destination */
+
+ xorl %edx,%edx /* clear the extension */
+
+#ifdef PARANOID
+ testl $0x80000000,%eax
+ je L_bugged
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged
+#endif PARANOID
+
+/* The number to be shifted is in %eax:%ebx:%edx*/
+ cmpw $32,%cx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpw $64,%cx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set*/
+
+ orl $1,%edx /* record the fact in the extension*/
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ movl $1,%edx /* The shifted nr always at least one '1'*/
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+ /* Now do the addition */
+ addl SIGL(%esi),%ebx
+ adcl SIGH(%esi),%eax
+ jnc L_round_the_result
+
+ /* Overflow, adjust the result */
+ rcrl $1,%eax
+ rcrl $1,%ebx
+ rcrl $1,%edx
+ jnc L_no_bit_lost
+
+ orl $1,%edx
+
+L_no_bit_lost:
+ incl EXP(%edi)
+
+L_round_the_result:
+ jmp FPU_round /* Round the result*/
+
+
+
+#ifdef PARANOID
+/* If we ever get here then we have problems! */
+L_bugged:
+ pushl EX_INTERNAL|0x201
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif PARANOID
+
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/arch/i386/fpemul/reg_u_div.s b/sys/gnu/arch/i386/fpemul/reg_u_div.s
new file mode 100644
index 00000000000..92076a8235f
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_u_div.s
@@ -0,0 +1,509 @@
+ .file "reg_u_div.S"
+/* $OpenBSD: reg_u_div.s,v 1.1 1996/08/27 10:33:01 downsj Exp $ */
+/*
+ * reg_u_div.S
+ *
+ * Core division routines
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_u_div.s,v 1.3 1994/06/10 07:44:57 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Kernel for the division routines. |
+ | |
+ | void reg_u_div(FPU_REG *a, FPU_REG *a, |
+ | FPU_REG *dest, unsigned int control_word) |
+ | |
+ | Does not compute the destination exponent, but does adjust it. |
+ +---------------------------------------------------------------------------*/
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+/* #define dSIGL(x) (x) */
+/* #define dSIGH(x) 4(x) */
+
+
+.data
+/*
+ Local storage:
+ Result: accum_3:accum_2:accum_1:accum_0
+ Overflow flag: ovfl_flag
+ */
+ .align 2,0
+accum_3:
+ .long 0
+accum_2:
+ .long 0
+accum_1:
+ .long 0
+accum_0:
+ .long 0
+result_1:
+ .long 0
+result_2:
+ .long 0
+ovfl_flag:
+ .byte 0
+
+
+.text
+ .align 2,144
+
+.globl _reg_u_div
+
+.globl _divide_kernel
+
+_reg_u_div:
+ pushl %ebp
+ movl %esp,%ebp
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* pointer to num */
+ movl PARAM2,%ebx /* pointer to denom */
+ movl PARAM3,%edi /* pointer to answer */
+
+#ifdef DENORM_OPERAND
+ movl EXP(%esi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ movl EXP(%ebx),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+_divide_kernel:
+#ifdef PARANOID
+/* testl $0x80000000, SIGH(%esi) *//* Dividend */
+/* je L_bugged */
+ testl $0x80000000, SIGH(%ebx) /* Divisor*/
+ je L_bugged
+#endif PARANOID
+
+/* Check if the divisor can be treated as having just 32 bits */
+ cmpl $0,SIGL(%ebx)
+ jnz L_Full_Division /* Can't do a quick divide */
+
+/* We should be able to zip through the division here */
+ movl SIGH(%ebx),%ecx /* The divisor */
+ movl SIGH(%esi),%edx /* Dividend */
+ movl SIGL(%esi),%eax /* Dividend */
+
+ cmpl %ecx,%edx
+ setaeb ovfl_flag /* Keep a record */
+ jb L_no_adjust
+
+ subl %ecx,%edx /* Prevent the overflow */
+
+L_no_adjust:
+ /* Divide the 64 bit number by the 32 bit denominator */
+ divl %ecx
+ movl %eax,result_2
+
+ /* Work on the remainder of the first division */
+ xorl %eax,%eax
+ divl %ecx
+ movl %eax,result_1
+
+ /* Work on the remainder of the 64 bit division */
+ xorl %eax,%eax
+ divl %ecx
+
+ testb $255,ovfl_flag /* was the num > denom ? */
+ je L_no_overflow
+
+ /* Do the shifting here */
+ /* increase the exponent */
+ incl EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* To set the ms bit */
+ rcrl result_2
+ rcrl result_1
+ rcrl %eax
+
+L_no_overflow:
+ jmp LRound_precision /* Do the rounding as required*/
+
+
+/*---------------------------------------------------------------------------+
+ | Divide: Return arg1/arg2 to arg3. |
+ | |
+ | This routine does not use the exponents of arg1 and arg2, but does |
+ | adjust the exponent of arg3. |
+ | |
+ | The maximum returned value is (ignoring exponents) |
+ | .ffffffff ffffffff |
+ | ------------------ = 1.ffffffff fffffffe |
+ | .80000000 00000000 |
+ | and the minimum is |
+ | .80000000 00000000 |
+ | ------------------ = .80000000 00000001 (rounded) |
+ | .ffffffff ffffffff |
+ | |
+ +---------------------------------------------------------------------------*/
+
+
+L_Full_Division:
+ /* Save extended dividend in local register*/
+ movl SIGL(%esi),%eax
+ movl %eax,accum_2
+ movl SIGH(%esi),%eax
+ movl %eax,accum_3
+ xorl %eax,%eax
+ movl %eax,accum_1 /* zero the extension */
+ movl %eax,accum_0 /* zero the extension */
+
+ movl SIGL(%esi),%eax /* Get the current num */
+ movl SIGH(%esi),%edx
+
+/*----------------------------------------------------------------------*/
+/* Initialization done */
+/* Do the first 32 bits */
+
+ movb $0,ovfl_flag
+ cmpl SIGH(%ebx),%edx /* Test for imminent overflow */
+ jb LLess_than_1
+ ja LGreater_than_1
+
+ cmpl SIGL(%ebx),%eax
+ jb LLess_than_1
+
+LGreater_than_1:
+/* The dividend is greater or equal, would cause overflow */
+ setaeb ovfl_flag /* Keep a record */
+
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx /* Prevent the overflow */
+ movl %eax,accum_2
+ movl %edx,accum_3
+
+LLess_than_1:
+/* At this point, we have a dividend < divisor, with a record of
+ adjustment in ovfl_flag */
+
+ /* We will divide by a number which is too large */
+ movl SIGH(%ebx),%ecx
+ addl $1,%ecx
+ jnc LFirst_div_not_1
+
+ /* here we need to divide by 100000000h,
+ i.e., no division at all.. */
+ mov %edx,%eax
+ jmp LFirst_div_done
+
+LFirst_div_not_1:
+ divl %ecx /* Divide the numerator by the augmented
+ denom ms dw */
+
+LFirst_div_done:
+ movl %eax,result_2 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,accum_2 /* Subtract from the num local reg */
+ sbbl %edx,accum_3
+
+ movl result_2,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+ sbbl $0,accum_3
+ je LDo_2nd_32_bits /* Must check for non-zero result here */
+
+#ifdef PARANOID
+ jb L_bugged_1
+#endif PARANOID
+
+ /* need to subtract another once of the denom */
+ incl result_2 /* Correct the answer */
+
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+
+#ifdef PARANOID
+ sbbl $0,accum_3
+ jne L_bugged_1 /* Must check for non-zero result here */
+#endif PARANOID
+
+/*----------------------------------------------------------------------*/
+/* Half of the main problem is done, there is just a reduced numerator
+ to handle now */
+/* Work with the second 32 bits, accum_0 not used from now on */
+LDo_2nd_32_bits:
+ movl accum_2,%edx /* get the reduced num */
+ movl accum_1,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx
+ jb LDo_2nd_div
+ ja LPrevent_2nd_overflow
+
+ cmpl SIGL(%ebx),%eax
+ jb LDo_2nd_div
+
+LPrevent_2nd_overflow:
+/* The numerator is greater or equal, would cause overflow */
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,accum_2
+ movl %eax,accum_1
+
+ incl result_2 /* Reflect the subtraction in the answer */
+
+#ifdef PARANOID
+ je L_bugged_2 /* Can't bump the result to 1.0 */
+#endif PARANOID
+
+LDo_2nd_div:
+ cmpl $0,%ecx /* augmented denom msw*/
+ jnz LSecond_div_not_1
+
+ /* %ecx == 0, we are dividing by 1.0 */
+ mov %edx,%eax
+ jmp LSecond_div_done
+
+LSecond_div_not_1:
+ divl %ecx /* Divide the numerator by the denom ms dw */
+
+LSecond_div_done:
+ movl %eax,result_1 /* Put the result in the answer */
+
+ mull SIGH(%ebx) /* mul by the ms dw of the denom */
+
+ subl %eax,accum_1 /* Subtract from the num local reg */
+ sbbl %edx,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif PARANOID
+
+ movl result_1,%eax /* Get the result back */
+ mull SIGL(%ebx) /* now mul the ls dw of the denom */
+
+ subl %eax,accum_0 /* Subtract from the num local reg */
+ sbbl %edx,accum_1 /* Subtract from the num local reg */
+ sbbl $0,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+#endif PARANOID
+
+ jz LDo_3rd_32_bits
+
+#ifdef PARANOID
+ cmpl $1,accum_2
+ jne L_bugged_2
+#endif PARANOID
+
+ /* need to subtract another once of the denom */
+ movl SIGL(%ebx),%eax
+ movl SIGH(%ebx),%edx
+ subl %eax,accum_0 /* Subtract from the num local reg */
+ sbbl %edx,accum_1
+ sbbl $0,accum_2
+
+#ifdef PARANOID
+ jc L_bugged_2
+ jne L_bugged_2
+#endif PARANOID
+
+ addl $1,result_1 /* Correct the answer */
+ adcl $0,result_2
+
+#ifdef PARANOID
+ jc L_bugged_2 /* Must check for non-zero result here */
+#endif PARANOID
+
+/*----------------------------------------------------------------------*/
+/* The division is essentially finished here, we just need to perform
+ tidying operations. */
+/* deal with the 3rd 32 bits */
+LDo_3rd_32_bits:
+ movl accum_1,%edx /* get the reduced num */
+ movl accum_0,%eax
+
+ /* need to check for possible subsequent overflow */
+ cmpl SIGH(%ebx),%edx /* denom*/
+ jb LRound_prep
+ ja LPrevent_3rd_overflow
+
+ cmpl SIGL(%ebx),%eax /* denom */
+ jb LRound_prep
+
+LPrevent_3rd_overflow:
+ /* prevent overflow */
+ subl SIGL(%ebx),%eax
+ sbbl SIGH(%ebx),%edx
+ movl %edx,accum_1
+ movl %eax,accum_0
+
+ addl $1,result_1 /* Reflect the subtraction in the answer */
+ adcl $0,result_2
+ jne LRound_prep
+ jnc LRound_prep
+
+ /* This is a tricky spot, there is an overflow of the answer */
+ movb $255,ovfl_flag /* Overflow -> 1.000 */
+
+LRound_prep:
+/* Prepare for rounding.
+// To test for rounding, we just need to compare 2*accum with the
+// denom. */
+ movl accum_0,%ecx
+ movl accum_1,%edx
+ movl %ecx,%eax
+ orl %edx,%eax
+ jz LRound_ovfl /* The accumulator contains zero.*/
+
+ /* Multiply by 2 */
+ clc
+ rcll $1,%ecx
+ rcll $1,%edx
+ jc LRound_large /* No need to compare, denom smaller */
+
+ subl SIGL(%ebx),%ecx
+ sbbl SIGH(%ebx),%edx
+ jnc LRound_not_small
+
+ movl $0x70000000,%eax /* Denom was larger */
+ jmp LRound_ovfl
+
+LRound_not_small:
+ jnz LRound_large
+
+ movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */
+ jmp LRound_ovfl
+
+LRound_large:
+ movl $0xff000000,%eax /* Denom was smaller */
+
+LRound_ovfl:
+/* We are now ready to deal with rounding, but first we must get
+ the bits properly aligned */
+ testb $255,ovfl_flag /* was the num > denom ? */
+ je LRound_precision
+
+ incl EXP(%edi)
+
+ /* shift the mantissa right one bit */
+ stc /* Will set the ms bit */
+ rcrl result_2
+ rcrl result_1
+ rcrl %eax
+
+/* Round the result as required */
+LRound_precision:
+ decl EXP(%edi) /* binary point between 1st & 2nd bits */
+
+ movl %eax,%edx
+ movl result_1,%ebx
+ movl result_2,%eax
+ jmp FPU_round
+
+
+#ifdef PARANOID
+/* The logic is wrong if we got here */
+L_bugged:
+ pushl EX_INTERNAL|0x202
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_1:
+ pushl EX_INTERNAL|0x203
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x204
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+
+ leave
+ ret
+#endif PARANOID
diff --git a/sys/gnu/arch/i386/fpemul/reg_u_mul.s b/sys/gnu/arch/i386/fpemul/reg_u_mul.s
new file mode 100644
index 00000000000..e7aba6185a4
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_u_mul.s
@@ -0,0 +1,202 @@
+ .file "reg_u_mul.S"
+/* $OpenBSD: reg_u_mul.s,v 1.1 1996/08/27 10:33:02 downsj Exp $ */
+/*
+ * reg_u_mul.S
+ *
+ * Core multiplication routine
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_u_mul.s,v 1.3 1994/06/10 07:44:58 rich Exp $
+ *
+ */
+
+/*---------------------------------------------------------------------------+
+ | Basic multiplication routine. |
+ | Does not check the resulting exponent for overflow/underflow |
+ | |
+ | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); |
+ | |
+ | Internal working is at approx 128 bits. |
+ | Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
+ +---------------------------------------------------------------------------*/
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+
+.data
+ .align 2,0
+accum_0:
+ .long 0
+accum_1:
+ .long 0
+
+
+.text
+ .align 2,144
+
+.globl _reg_u_mul
+_reg_u_mul:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%edi
+
+#ifdef PARANOID
+ testl $0x80000000,SIGH(%esi)
+ jz L_bugged
+ testl $0x80000000,SIGH(%edi)
+ jz L_bugged
+#endif PARANOID
+
+#ifdef DENORM_OPERAND
+ movl EXP(%esi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ movl EXP(%edi),%eax
+ cmpl EXP_UNDER,%eax
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+ xorl %ecx,%ecx
+ xorl %ebx,%ebx
+
+ movl SIGL(%esi),%eax
+ mull SIGL(%edi)
+ movl %eax,accum_0
+ movl %edx,accum_1
+
+ movl SIGL(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,accum_1
+ adcl %edx,%ebx
+/* adcl $0,%ecx *//* overflow here is not possible */
+
+ movl SIGH(%esi),%eax
+ mull SIGL(%edi)
+ addl %eax,accum_1
+ adcl %edx,%ebx
+ adcl $0,%ecx
+
+ movl SIGH(%esi),%eax
+ mull SIGH(%edi)
+ addl %eax,%ebx
+ adcl %edx,%ecx
+
+ movl EXP(%esi),%eax /* Compute the exponent */
+ addl EXP(%edi),%eax
+ subl EXP_BIAS-1,%eax
+/* Have now finished with the sources */
+ movl PARAM3,%edi /* Point to the destination */
+ movl %eax,EXP(%edi)
+
+/* Now make sure that the result is normalized */
+ testl $0x80000000,%ecx
+ jnz LResult_Normalised
+
+ /* Normalize by shifting left one bit */
+ shll $1,accum_0
+ rcll $1,accum_1
+ rcll $1,%ebx
+ rcll $1,%ecx
+ decl EXP(%edi)
+
+LResult_Normalised:
+ movl accum_0,%eax
+ movl accum_1,%edx
+ orl %eax,%eax
+ jz L_extent_zero
+
+ orl $1,%edx
+
+L_extent_zero:
+ movl %ecx,%eax
+ jmp FPU_round
+
+
+#ifdef PARANOID
+L_bugged:
+ pushl EX_INTERNAL|0x205
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+#endif PARANOID
+
diff --git a/sys/gnu/arch/i386/fpemul/reg_u_sub.s b/sys/gnu/arch/i386/fpemul/reg_u_sub.s
new file mode 100644
index 00000000000..8f4c19a1c0f
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/reg_u_sub.s
@@ -0,0 +1,364 @@
+ .file "reg_u_sub.S"
+/* $OpenBSD: reg_u_sub.s,v 1.1 1996/08/27 10:33:02 downsj Exp $ */
+/*
+ * reg_u_sub.S
+ *
+ * Core floating point subtraction routine.
+ *
+ * Call from C as:
+ * void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,
+ * int control_w)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: reg_u_sub.s,v 1.3 1994/06/10 07:44:59 rich Exp $
+ *
+ */
+
+/*
+ | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
+ | Takes two valid reg f.p. numbers (TW_Valid), which are
+ | treated as unsigned numbers,
+ | and returns their difference as a TW_Valid or TW_Zero f.p.
+ | number.
+ | The first number (arg1) must be the larger.
+ | The returned number is normalized.
+ | Basic checks are performed if PARANOID is defined.
+ */
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+#include <gnu/arch/i386/fpemul/control_w.h>
+
+.text
+ .align 2,144
+.globl _reg_u_sub
+_reg_u_sub:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi /* source 1 */
+ movl PARAM2,%edi /* source 2 */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xOp1_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp1_not_denorm:
+ cmpl EXP_UNDER,EXP(%edi)
+ jg xOp2_not_denorm
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz FPU_Arith_exit
+
+xOp2_not_denorm:
+#endif DENORM_OPERAND
+
+/* xorl %ecx,%ecx */
+ movl EXP(%esi),%ecx
+ subl EXP(%edi),%ecx /* exp1 - exp2 */
+
+#ifdef PARANOID
+ /* source 2 is always smaller than source 1 */
+/* jc L_bugged */
+ js L_bugged_1
+
+ testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */
+ je L_bugged_2
+
+ testl $0x80000000,SIGH(%esi)
+ je L_bugged_2
+#endif PARANOID
+
+/*--------------------------------------+
+ | Form a register holding the |
+ | smaller number |
+ +--------------------------------------*/
+ movl SIGH(%edi),%eax /* register ms word */
+ movl SIGL(%edi),%ebx /* register ls word */
+
+ movl PARAM3,%edi /* destination */
+ movl EXP(%esi),%edx
+ movl %edx,EXP(%edi) /* Copy exponent to destination */
+ movb SIGN(%esi),%dl
+ movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+
+ xorl %edx,%edx /* register extension */
+
+/*--------------------------------------+
+ | Shift the temporary register |
+ | right the required number of |
+ | places. |
+ +--------------------------------------*/
+L_shift_r:
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ jmp L_shift_done
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ jz L_exactly_32
+
+ shrd %cl,%eax,%edx
+ shr %cl,%eax
+ orl %ebx,%ebx
+ jz L_more_31_no_low /* none of the lowest bits is set */
+
+ orl $1,%edx /* record the fact in the extension */
+
+L_more_31_no_low:
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_exactly_32:
+ movl %ebx,%edx
+ movl %eax,%ebx
+ xorl %eax,%eax
+ jmp L_shift_done
+
+L_more_than_63:
+ cmpw $65,%cx
+ jnc L_more_than_64
+
+ /* Shift right by 64 bits */
+ movl %eax,%edx
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_64:
+ jne L_more_than_65
+
+ /* Shift right by 65 bits */
+ /* Carry is clear if we get here */
+ movl %eax,%edx
+ rcrl %edx
+ jnc L_shift_65_nc
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_shift_65_nc:
+ orl %ebx,%ebx
+ jz L_more_63_no_low
+
+ orl $1,%edx
+ jmp L_more_63_no_low
+
+L_more_than_65:
+ movl $1,%edx /* The shifted nr always at least one '1' */
+
+L_more_63_no_low:
+ xorl %ebx,%ebx
+ xorl %eax,%eax
+
+L_shift_done:
+L_subtr:
+/*------------------------------+
+ | Do the subtraction |
+ +------------------------------*/
+ xorl %ecx,%ecx
+ subl %edx,%ecx
+ movl %ecx,%edx
+ movl SIGL(%esi),%ecx
+ sbbl %ebx,%ecx
+ movl %ecx,%ebx
+ movl SIGH(%esi),%ecx
+ sbbl %eax,%ecx
+ movl %ecx,%eax
+
+#ifdef PARANOID
+ /* We can never get a borrow */
+ jc L_bugged
+#endif PARANOID
+
+/*--------------------------------------+
+ | Normalize the result |
+ +--------------------------------------*/
+ testl $0x80000000,%eax
+ jnz L_round /* no shifting needed */
+
+ orl %eax,%eax
+ jnz L_shift_1 /* shift left 1 - 31 bits */
+
+ orl %ebx,%ebx
+ jnz L_shift_32 /* shift left 32 - 63 bits */
+
+/* A rare case, the only one which is non-zero if we got here
+// is: 1000000 .... 0000
+// -0111111 .... 1111 1
+// --------------------
+// 0000000 .... 0000 1 */
+
+ cmpl $0x80000000,%edx
+ jnz L_must_be_zero
+
+ /* Shift left 64 bits */
+ subl $64,EXP(%edi)
+ movl %edx,%eax
+ jmp L_store
+
+L_must_be_zero:
+#ifdef PARANOID
+ orl %edx,%edx
+ jnz L_bugged_3
+#endif PARANOID
+
+ /* The result is zero */
+ movb TW_Zero,TAG(%edi)
+ movl $0,EXP(%edi) /* exponent */
+ movl $0,SIGL(%edi)
+ movl $0,SIGH(%edi)
+ jmp L_exit /* Does not underflow */
+
+L_shift_32:
+ movl %ebx,%eax
+ movl %edx,%ebx
+ movl $0,%edx
+ subl $32,EXP(%edi) /* Can get underflow here */
+
+/* We need to shift left by 1 - 31 bits */
+L_shift_1:
+ bsrl %eax,%ecx /* get the required shift in %ecx */
+ subl $31,%ecx
+ negl %ecx
+ shld %cl,%ebx,%eax
+ shld %cl,%edx,%ebx
+ shl %cl,%edx
+ subl %ecx,EXP(%edi) /* Can get underflow here */
+
+L_round:
+ jmp FPU_round /* Round the result */
+
+
+#ifdef PARANOID
+L_bugged_1:
+ pushl EX_INTERNAL|0x206
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_2:
+ pushl EX_INTERNAL|0x209
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_3:
+ pushl EX_INTERNAL|0x210
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged_4:
+ pushl EX_INTERNAL|0x211
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+
+L_bugged:
+ pushl EX_INTERNAL|0x212
+ call EXCEPTION
+ pop %ebx
+ jmp L_exit
+#endif PARANOID
+
+
+L_store:
+/*------------------------------+
+ | Store the result |
+ +------------------------------*/
+ movl %eax,SIGH(%edi)
+ movl %ebx,SIGL(%edi)
+
+ movb TW_Valid,TAG(%edi) /* Set the tags to TW_Valid */
+
+ cmpl EXP_UNDER,EXP(%edi)
+ jle L_underflow
+
+L_exit:
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_underflow:
+ push %edi
+ call _arith_underflow
+ pop %ebx
+ jmp L_exit
+
diff --git a/sys/gnu/arch/i386/fpemul/status_w.h b/sys/gnu/arch/i386/fpemul/status_w.h
new file mode 100644
index 00000000000..d921a05807b
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/status_w.h
@@ -0,0 +1,107 @@
+/* $OpenBSD: status_w.h,v 1.1 1996/08/27 10:33:03 downsj Exp $ */
+/*
+ * status_w.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: status_w.h,v 1.3 1994/06/10 07:45:01 rich Exp $
+ *
+ */
+
+
+#ifndef _STATUS_H_
+#define _STATUS_H_
+
+
+#ifdef _LOCORE
+#define Const__(x) $/**/x
+#else
+#define Const__(x) x
+#endif
+
+#define SW_Backward Const__(0x8000) /* backward compatibility */
+#define SW_C3 Const__(0x4000) /* condition bit 3 */
+#define SW_Top Const__(0x3800) /* top of stack */
+#define SW_Top_Shift Const__(11) /* shift for top of stack bits */
+#define SW_C2 Const__(0x0400) /* condition bit 2 */
+#define SW_C1 Const__(0x0200) /* condition bit 1 */
+#define SW_C0 Const__(0x0100) /* condition bit 0 */
+#define SW_Summary Const__(0x0080) /* exception summary */
+#define SW_Stack_Fault Const__(0x0040) /* stack fault */
+#define SW_Precision Const__(0x0020) /* loss of precision */
+#define SW_Underflow Const__(0x0010) /* underflow */
+#define SW_Overflow Const__(0x0008) /* overflow */
+#define SW_Zero_Div Const__(0x0004) /* divide by zero */
+#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */
+#define SW_Invalid Const__(0x0001) /* invalid operation */
+
+#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */
+
+#ifndef _LOCORE
+
+#define COMP_A_gt_B 1
+#define COMP_A_eq_B 2
+#define COMP_A_lt_B 3
+#define COMP_No_Comp 4
+#define COMP_Denormal 0x20
+#define COMP_NaN 0x40
+#define COMP_SNaN 0x80
+
+#define setcc(cc) ({ \
+ status_word &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \
+ status_word |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); })
+
+#endif /* _LOCORE */
+
+#endif /* _STATUS_H_ */
diff --git a/sys/gnu/arch/i386/fpemul/version.h b/sys/gnu/arch/i386/fpemul/version.h
new file mode 100644
index 00000000000..be412e78d33
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/version.h
@@ -0,0 +1,62 @@
+/* $OpenBSD: version.h,v 1.1 1996/08/27 10:33:03 downsj Exp $ */
+/*
+ * version.h
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: version.h,v 1.3 1994/06/10 07:45:02 rich Exp $
+ *
+ */
+
+#define FPU_VERSION "wm-FPU-emu version BETA 1.4"
diff --git a/sys/gnu/arch/i386/fpemul/wm_shrx.s b/sys/gnu/arch/i386/fpemul/wm_shrx.s
new file mode 100644
index 00000000000..c014f756402
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/wm_shrx.s
@@ -0,0 +1,264 @@
+ .file "wm_shrx.S"
+/* $OpenBSD: wm_shrx.s,v 1.1 1996/08/27 10:33:04 downsj Exp $ */
+/*
+ * wm_shrx.S
+ *
+ * 64 bit right shift functions
+ *
+ * Call from C as:
+ * unsigned shrx(void *arg1, unsigned arg2)
+ * and
+ * unsigned shrxs(void *arg1, unsigned arg2)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: wm_shrx.s,v 1.3 1994/06/10 07:45:03 rich Exp $
+ *
+ */
+
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+.text
+ .align 2,144
+
+/*---------------------------------------------------------------------------+
+ | unsigned shrx(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function. |
+ | Fastest for small shifts. |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+
+ .globl _shrx
+
+_shrx:
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jnc L_more_than_31
+
+/* less than 32 bits */
+ pushl %ebx
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+L_more_than_31:
+ cmpl $64,%ecx
+ jnc L_more_than_63
+
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_63:
+ cmpl $96,%ecx
+ jnc L_more_than_95
+
+ subb $64,%cl
+ movl 4(%esi),%eax /* msl */
+ shr %cl,%eax
+ xorl %edx,%edx
+ movl %edx,(%esi)
+ movl %edx,4(%esi)
+ popl %esi
+ leave
+ ret
+
+L_more_than_95:
+ xorl %eax,%eax
+ movl %eax,(%esi)
+ movl %eax,4(%esi)
+ popl %esi
+ leave
+ ret
+
+
+/*---------------------------------------------------------------------------+
+ | unsigned shrxs(void *arg1, unsigned arg2) |
+ | |
+ | Extended shift right function (optimized for small floating point |
+ | integers). |
+ | Shifts the 64 bit quantity pointed to by the first arg (arg1) |
+ | right by the number of bits specified by the second arg (arg2). |
+ | Forms a 96 bit quantity from the 64 bit arg and eax: |
+ | [ 64 bit arg ][ eax ] |
+ | shift right ---------> |
+ | The eax register is initialized to 0 before the shifting. |
+ | The lower 8 bits of eax are lost and replaced by a flag which is |
+ | set (to 0x01) if any bit, apart from the first one, is set in the |
+ | part which has been shifted out of the arg. |
+ | Results returned in the 64 bit arg and eax. |
+ +---------------------------------------------------------------------------*/
+ .globl _shrxs
+_shrxs:
+ push %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %ebx
+ movl PARAM2,%ecx
+ movl PARAM1,%esi
+ cmpl $64,%ecx /* shrd only works for 0..31 bits */
+ jnc Ls_more_than_63
+
+ cmpl $32,%ecx /* shrd only works for 0..31 bits */
+ jc Ls_less_than_32
+
+/* We got here without jumps by assuming that the most common requirement
+ is for small integers */
+/* Shift by [32..63] bits */
+ subb $32,%cl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %ebx,%ebx
+ shrd %cl,%eax,%ebx
+ shrd %cl,%edx,%eax
+ shr %cl,%edx
+ orl %ebx,%ebx /* test these 32 bits */
+ setne %bl
+ test $0x7fffffff,%eax /* and 31 bits here */
+ setne %bh
+ orw %bx,%bx /* Any of the 63 bit set ? */
+ setne %al
+ movl %edx,(%esi)
+ movl $0,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [0..31] bits */
+Ls_less_than_32:
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
+ shrd %cl,%ebx,%eax
+ shrd %cl,%edx,%ebx
+ shr %cl,%edx
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %al
+ movl %ebx,(%esi)
+ movl %edx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+/* Shift by [64..95] bits */
+Ls_more_than_63:
+ cmpl $96,%ecx
+ jnc Ls_more_than_95
+
+ subb $64,%cl
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%eax /* msl */
+ xorl %edx,%edx /* extension */
+ shrd %cl,%ebx,%edx
+ shrd %cl,%eax,%ebx
+ shr %cl,%eax
+ orl %ebx,%edx
+ setne %bl
+ test $0x7fffffff,%eax /* only need to look at eax here */
+ setne %bh
+ orw %bx,%bx
+ setne %al
+ xorl %edx,%edx
+ movl %edx,(%esi) /* set to zero */
+ movl %edx,4(%esi) /* set to zero */
+ popl %ebx
+ popl %esi
+ leave
+ ret
+
+Ls_more_than_95:
+/* Shift by [96..inf) bits */
+ xorl %eax,%eax
+ movl (%esi),%ebx
+ orl 4(%esi),%ebx
+ setne %al
+ xorl %ebx,%ebx
+ movl %ebx,(%esi)
+ movl %ebx,4(%esi)
+ popl %ebx
+ popl %esi
+ leave
+ ret
diff --git a/sys/gnu/arch/i386/fpemul/wm_sqrt.s b/sys/gnu/arch/i386/fpemul/wm_sqrt.s
new file mode 100644
index 00000000000..849a11ff465
--- /dev/null
+++ b/sys/gnu/arch/i386/fpemul/wm_sqrt.s
@@ -0,0 +1,499 @@
+ .file "wm_sqrt.S"
+/* $OpenBSD: wm_sqrt.s,v 1.1 1996/08/27 10:33:04 downsj Exp $ */
+/*
+ * wm_sqrt.S
+ *
+ * Fixed point arithmetic square root evaluation.
+ *
+ * Call from C as:
+ * void wm_sqrt(FPU_REG *n, unsigned int control_word)
+ *
+ *
+ * Copyright (C) 1992,1993,1994
+ * W. Metzenthen, 22 Parker St, Ormond, Vic 3163,
+ * Australia. E-mail billm@vaxc.cc.monash.edu.au
+ * All rights reserved.
+ *
+ * This copyright notice covers the redistribution and use of the
+ * FPU emulator developed by W. Metzenthen. It covers only its use
+ * in the 386BSD, FreeBSD and NetBSD operating systems. Any other
+ * use is not permitted under this copyright.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must include information specifying
+ * that source code for the emulator is freely available and include
+ * either:
+ * a) an offer to provide the source code for a nominal distribution
+ * fee, or
+ * b) list at least two alternative methods whereby the source
+ * can be obtained, e.g. a publically accessible bulletin board
+ * and an anonymous ftp site from which the software can be
+ * downloaded.
+ * 3. All advertising materials specifically mentioning features or use of
+ * this emulator must acknowledge that it was developed by W. Metzenthen.
+ * 4. The name of W. Metzenthen may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * The purpose of this copyright, based upon the Berkeley copyright, is to
+ * ensure that the covered software remains freely available to everyone.
+ *
+ * The software (with necessary differences) is also available, but under
+ * the terms of the GNU copyleft, for the Linux operating system and for
+ * the djgpp ms-dos extender.
+ *
+ * W. Metzenthen June 1994.
+ *
+ *
+ * $FreeBSD: wm_sqrt.s,v 1.3 1994/06/10 07:45:04 rich Exp $
+ *
+ */
+
+
+/*---------------------------------------------------------------------------+
+ | wm_sqrt(FPU_REG *n, unsigned int control_word) |
+ | returns the square root of n in n. |
+ | |
+ | Use Newton's method to compute the square root of a number, which must |
+ | be in the range [1.0 .. 4.0), to 64 bits accuracy. |
+ | Does not check the sign or tag of the argument. |
+ | Sets the exponent, but not the sign or tag of the result. |
+ | |
+ | The guess is kept in %esi:%edi |
+ +---------------------------------------------------------------------------*/
+
+#include <machine/asm.h>
+
+#include <gnu/arch/i386/fpemul/exception.h>
+#include <gnu/arch/i386/fpemul/fpu_asm.h>
+
+
+.data
+/*
+ Local storage:
+ */
+ .align 4,0
+accum_3:
+ .long 0 /* ms word */
+accum_2:
+ .long 0
+accum_1:
+ .long 0
+accum_0:
+ .long 0
+
+/* The de-normalised argument:
+// sq_2 sq_1 sq_0
+// b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
+// ^ binary point here */
+fsqrt_arg_2:
+ .long 0 /* ms word */
+fsqrt_arg_1:
+ .long 0
+fsqrt_arg_0:
+ .long 0 /* ls word, at most the ms bit is set */
+
+.text
+ .align 2,144
+
+.globl _wm_sqrt
+
+_wm_sqrt:
+ pushl %ebp
+ movl %esp,%ebp
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+
+ movl SIGH(%esi),%eax
+ movl SIGL(%esi),%ecx
+ xorl %edx,%edx
+
+/* We use a rough linear estimate for the first guess.. */
+
+ cmpl EXP_BIAS,EXP(%esi)
+ jnz sqrt_arg_ge_2
+
+ shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */
+ rcrl $1,%ecx
+ rcrl $1,%edx
+
+sqrt_arg_ge_2:
+/* From here on, n is never accessed directly again until it is
+// replaced by the answer. */
+
+ movl %eax,fsqrt_arg_2 /* ms word of n */
+ movl %ecx,fsqrt_arg_1
+ movl %edx,fsqrt_arg_0
+
+/* Make a linear first estimate */
+ shrl $1,%eax
+ addl $0x40000000,%eax
+ movl $0xaaaaaaaa,%ecx
+ mull %ecx
+ shll %edx /* max result was 7fff... */
+ testl $0x80000000,%edx /* but min was 3fff... */
+ jnz sqrt_prelim_no_adjust
+
+ movl $0x80000000,%edx /* round up */
+
+sqrt_prelim_no_adjust:
+ movl %edx,%esi /* Our first guess */
+
+/* We have now computed (approx) (2 + x) / 3, which forms the basis
+ for a few iterations of Newton's method */
+
+ movl fsqrt_arg_2,%ecx /* ms word */
+
+/* From our initial estimate, three iterations are enough to get us
+// to 30 bits or so. This will then allow two iterations at better
+// precision to complete the process.
+
+// Compute (g + n/g)/2 at each iteration (g is the guess). */
+ shrl %ecx /* Doing this first will prevent a divide */
+ /* overflow later. */
+
+ movl %ecx,%edx /* msw of the arg / 2 */
+ divl %esi /* current estimate */
+ shrl %esi /* divide by 2 */
+ addl %eax,%esi /* the new estimate */
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+ movl %ecx,%edx
+ divl %esi
+ shrl %esi
+ addl %eax,%esi
+
+/* Now that an estimate accurate to about 30 bits has been obtained (in %esi),
+// we improve it to 60 bits or so.
+
+// The strategy from now on is to compute new estimates from
+// guess := guess + (n - guess^2) / (2 * guess) */
+
+/* First, find the square of the guess */
+ movl %esi,%eax
+ mull %esi
+/* guess^2 now in %edx:%eax */
+
+ movl fsqrt_arg_1,%ecx
+ subl %ecx,%eax
+ movl fsqrt_arg_2,%ecx /* ms word of normalized n */
+ sbbl %ecx,%edx
+ jnc sqrt_stage_2_positive
+/* subtraction gives a negative result
+// negate the result before division */
+ notl %edx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%edx
+
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+ jmp sqrt_stage_2_finish
+
+sqrt_stage_2_positive:
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ notl %ecx
+ notl %eax
+ addl $1,%eax
+ adcl $0,%ecx
+
+sqrt_stage_2_finish:
+ sarl $1,%ecx /* divide by 2 */
+ rcrl $1,%eax
+
+ /* Form the new estimate in %esi:%edi */
+ movl %eax,%edi
+ addl %ecx,%esi
+
+ jnz sqrt_stage_2_done /* result should be [1..2) */
+
+#ifdef PARANOID
+/* It should be possible to get here only if the arg is ffff....ffff*/
+ cmp $0xffffffff,fsqrt_arg_1
+ jnz sqrt_stage_2_error
+#endif PARANOID
+
+/* The best rounded result.*/
+ xorl %eax,%eax
+ decl %eax
+ movl %eax,%edi
+ movl %eax,%esi
+ movl $0x7fffffff,%eax
+ jmp sqrt_round_result
+
+#ifdef PARANOID
+sqrt_stage_2_error:
+ pushl EX_INTERNAL|0x213
+ call EXCEPTION
+#endif PARANOID
+
+sqrt_stage_2_done:
+
+/* Now the square root has been computed to better than 60 bits */
+
+/* Find the square of the guess*/
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,accum_1
+
+ movl %esi,%eax
+ mull %esi
+ movl %edx,accum_3
+ movl %eax,accum_2
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,accum_1
+ adcl %edx,accum_2
+ adcl $0,accum_3
+
+/* movl %esi,%eax*/
+/* mull %edi*/
+ addl %eax,accum_1
+ adcl %edx,accum_2
+ adcl $0,accum_3
+
+/* guess^2 now in accum_3:accum_2:accum_1*/
+
+ movl fsqrt_arg_0,%eax /* get normalized n*/
+ subl %eax,accum_1
+ movl fsqrt_arg_1,%eax
+ sbbl %eax,accum_2
+ movl fsqrt_arg_2,%eax /* ms word of normalized n*/
+ sbbl %eax,accum_3
+ jnc sqrt_stage_3_positive
+
+/* subtraction gives a negative result*/
+/* negate the result before division */
+ notl accum_1
+ notl accum_2
+ notl accum_3
+ addl $1,accum_1
+ adcl $0,accum_2
+
+#ifdef PARANOID
+ adcl $0,accum_3 /* This must be zero */
+ jz sqrt_stage_3_no_error
+
+sqrt_stage_3_error:
+ pushl EX_INTERNAL|0x207
+ call EXCEPTION
+
+sqrt_stage_3_no_error:
+#endif PARANOID
+
+ movl accum_2,%edx
+ movl accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx / divide by 2*/
+ rcrl $1,%eax
+
+ /* prepare to round the result*/
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+ jmp sqrt_stage_3_finished
+
+sqrt_stage_3_positive:
+ movl accum_2,%edx
+ movl accum_1,%eax
+ divl %esi
+ movl %eax,%ecx
+
+ movl %edx,%eax
+ divl %esi
+
+ sarl $1,%ecx /* divide by 2*/
+ rcrl $1,%eax
+
+ /* prepare to round the result*/
+
+ notl %eax /* Negate the correction term*/
+ notl %ecx
+ addl $1,%eax
+ adcl $0,%ecx /* carry here ==> correction == 0*/
+ adcl $0xffffffff,%esi
+
+ addl %ecx,%edi
+ adcl $0,%esi
+
+sqrt_stage_3_finished:
+
+/* The result in %esi:%edi:%esi should be good to about 90 bits here,
+// and the rounding information here does not have sufficient accuracy
+// in a few rare cases. */
+ cmpl $0xffffffe0,%eax
+ ja sqrt_near_exact_x
+
+ cmpl $0x00000020,%eax
+ jb sqrt_near_exact
+
+ cmpl $0x7fffffe0,%eax
+ jb sqrt_round_result
+
+ cmpl $0x80000020,%eax
+ jb sqrt_get_more_precision
+
+sqrt_round_result:
+/* Set up for rounding operations*/
+ movl %eax,%edx
+ movl %esi,%eax
+ movl %edi,%ebx
+ movl PARAM1,%edi
+ movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0)*/
+ movl PARAM2,%ecx
+ jmp FPU_round_sqrt
+
+
+sqrt_near_exact_x:
+/* First, the estimate must be rounded up.*/
+ addl $1,%edi
+ adcl $0,%esi
+
+sqrt_near_exact:
+/* This is an easy case because x^1/2 is monotonic.
+// We need just find the square of our estimate, compare it
+// with the argument, and deduce whether our estimate is
+// above, below, or exact. We use the fact that the estimate
+// is known to be accurate to about 90 bits. */
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square*/
+ movl %eax,%ecx /* ls word of square*/
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+#ifdef PARANOID
+ cmp $0xffffffb0,%ebx
+ jb sqrt_near_exact_ok
+
+ cmp $0x00000050,%ebx
+ ja sqrt_near_exact_ok
+
+ pushl EX_INTERNAL|0x214
+ call EXCEPTION
+
+sqrt_near_exact_ok:
+#endif PARANOID
+
+ or %ebx,%ebx
+ js sqrt_near_exact_small
+
+ jnz sqrt_near_exact_large
+
+ or %ebx,%edx
+ jnz sqrt_near_exact_large
+
+/* Our estimate is exactly the right answer*/
+ xorl %eax,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_small:
+/* Our estimate is too small*/
+ movl $0x000000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_near_exact_large:
+/* Our estimate is too large, we need to decrement it*/
+ subl $1,%edi
+ sbbl $0,%esi
+ movl $0xffffff00,%eax
+ jmp sqrt_round_result
+
+
+sqrt_get_more_precision:
+/* This case is almost the same as the above, except we start*/
+/* with an extra bit of precision in the estimate.*/
+ stc /* The extra bit.*/
+ rcll $1,%edi /* Shift the estimate left one bit*/
+ rcll $1,%esi
+
+ movl %edi,%eax /* ls word of guess*/
+ mull %edi
+ movl %edx,%ebx /* 2nd ls word of square*/
+ movl %eax,%ecx /* ls word of square*/
+
+ movl %edi,%eax
+ mull %esi
+ addl %eax,%ebx
+ addl %eax,%ebx
+
+/* Put our estimate back to its original value*/
+ stc /* The ms bit.*/
+ rcrl $1,%esi /* Shift the estimate left one bit*/
+ rcrl $1,%edi
+
+#ifdef PARANOID
+ cmp $0xffffff60,%ebx
+ jb sqrt_more_prec_ok
+
+ cmp $0x000000a0,%ebx
+ ja sqrt_more_prec_ok
+
+ pushl EX_INTERNAL|0x215
+ call EXCEPTION
+
+sqrt_more_prec_ok:
+#endif PARANOID
+
+ or %ebx,%ebx
+ js sqrt_more_prec_small
+
+ jnz sqrt_more_prec_large
+
+ or %ebx,%ecx
+ jnz sqrt_more_prec_large
+
+/* Our estimate is exactly the right answer*/
+ movl $0x80000000,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_small:
+/* Our estimate is too small*/
+ movl $0x800000ff,%eax
+ jmp sqrt_round_result
+
+sqrt_more_prec_large:
+/* Our estimate is too large*/
+ movl $0x7fffff00,%eax
+ jmp sqrt_round_result