Import of gpl'ed math emulator.
No changes have been done.
This commit is contained in:
parent
a497738bea
commit
77d72caa6d
36
sys/gnu/i386/fpemul/Changelog
Normal file
36
sys/gnu/i386/fpemul/Changelog
Normal file
@ -0,0 +1,36 @@
|
||||
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)
|
267
sys/gnu/i386/fpemul/README
Normal file
267
sys/gnu/i386/fpemul/README
Normal file
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
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.
|
||||
|
35
sys/gnu/i386/fpemul/bde_trapinfo.mail
Normal file
35
sys/gnu/i386/fpemul/bde_trapinfo.mail
Normal file
@ -0,0 +1,35 @@
|
||||
From bde@kralizec.zeta.org.au Sun Jun 27 01:18:32 1993
|
||||
Received: from ultima.socs.uts.EDU.AU by bsd.coe.montana.edu (5.67/KAOS-1)
|
||||
id AA11952; Sun, 27 Jun 93 01:18:32 -0600
|
||||
Received: by ultima.socs.uts.EDU.AU (5.65+/SMI-3.3)
|
||||
id AA03033; Sun, 27 Jun 93 17:10:22 +1000
|
||||
Received: by kralizec.zeta.org.au (4.0/SMI-4.0)
|
||||
id AA15074; Sat, 26 Jun 93 02:32:58 EST
|
||||
Date: Sat, 26 Jun 93 02:32:58 EST
|
||||
From: bde@kralizec.zeta.org.au (Bruce Evans)
|
||||
Message-Id: <9306251632.AA15074@kralizec.zeta.org.au>
|
||||
To: nate@bsd.coe.montana.edu
|
||||
Subject: Re: Trapframe information
|
||||
Status: OR
|
||||
|
||||
tf_isp original esp (probably spare - popal ignores it)
|
||||
tf_trapno s/w trap no (may be spare - trap.c has already looked at it)
|
||||
tf_err h/w error code (probably spare - gets discarded before iret)
|
||||
|
||||
___fs not stored in 386BSD pcb. Constant anyway unless user has
|
||||
screwed with it (?).
|
||||
___gs ditto
|
||||
___orig_eip in linux, this is on the stack just before the call to the
|
||||
emulator. The reason that it's not a local variable is to
|
||||
avoid passing around pointers to it - current->frame (or
|
||||
whatever) points to everything in the stack frame. The
|
||||
macros hide a lot of slow memory references
|
||||
current->frame->var.
|
||||
|
||||
>(And I need to see if I can map orig_eip to one of the three that I'm unsure of
|
||||
>in the BSD sources)
|
||||
|
||||
tf_isp is the least evil.
|
||||
|
||||
Bruce
|
||||
|
82
sys/gnu/i386/fpemul/control_w.h
Normal file
82
sys/gnu/i386/fpemul/control_w.h
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* control_w.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#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_ */
|
88
sys/gnu/i386/fpemul/div_small.s
Normal file
88
sys/gnu/i386/fpemul/div_small.s
Normal file
@ -0,0 +1,88 @@
|
||||
.file "div_small.S"
|
||||
/*
|
||||
* div_small.S
|
||||
*
|
||||
* Divide a 64 bit integer by a 32 bit integer & return remainder.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| unsigned long div_small(unsigned long long *x, unsigned long y) |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "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
|
||||
|
599
sys/gnu/i386/fpemul/errors.c
Normal file
599
sys/gnu/i386/fpemul/errors.c
Normal file
@ -0,0 +1,599 @@
|
||||
/*
|
||||
* errors.c
|
||||
*
|
||||
* The error handling functions for wm-FPU-emu
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "param.h"
|
||||
#include "proc.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "status_w.h"
|
||||
#include "control_w.h"
|
||||
#include "reg_constant.h"
|
||||
#include "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;
|
||||
|
||||
}
|
88
sys/gnu/i386/fpemul/exception.h
Normal file
88
sys/gnu/i386/fpemul/exception.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* exception.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _EXCEPTION_H_
|
||||
#define _EXCEPTION_H_
|
||||
|
||||
|
||||
#ifdef LOCORE
|
||||
#define Const_(x) $/**/x
|
||||
#else
|
||||
#define Const_(x) x
|
||||
#endif
|
||||
|
||||
#ifndef SW_C1
|
||||
#include "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
|
||||
#define EXCEPTION(x) { printf("exception in %s at line %d\n", \
|
||||
__FILE__, __LINE__); exception(x); }
|
||||
#else
|
||||
#define EXCEPTION(x) exception(x)
|
||||
#endif
|
||||
|
||||
#endif /* LOCORE */
|
||||
|
||||
#endif /* _EXCEPTION_H_ */
|
222
sys/gnu/i386/fpemul/fpu_arith.c
Normal file
222
sys/gnu/i386/fpemul/fpu_arith.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* fpu_arith.c
|
||||
*
|
||||
* Code to implement the FPU register/register arithmetic instructions
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#include "param.h"
|
||||
#include "proc.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "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();
|
||||
}
|
69
sys/gnu/i386/fpemul/fpu_asm.h
Normal file
69
sys/gnu/i386/fpemul/fpu_asm.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* fpu_asm.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FPU_ASM_H_
|
||||
#define _FPU_ASM_H_
|
||||
|
||||
#include "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_ */
|
220
sys/gnu/i386/fpemul/fpu_aux.c
Normal file
220
sys/gnu/i386/fpemul/fpu_aux.c
Normal file
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* fpu_aux.c
|
||||
*
|
||||
* Code to implement some of the FPU auxiliary instructions.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "param.h"
|
||||
#include "proc.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "status_w.h"
|
||||
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
175
sys/gnu/i386/fpemul/fpu_emu.h
Normal file
175
sys/gnu/i386/fpemul/fpu_emu.h
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* fpu_emu.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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 "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 "types.h"
|
||||
#include "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 "fpu_proto.h"
|
||||
#endif
|
||||
|
||||
#endif /* LOCORE */
|
||||
|
||||
#endif /* _FPU_EMU_H_ */
|
500
sys/gnu/i386/fpemul/fpu_entry.c
Normal file
500
sys/gnu/i386/fpemul/fpu_entry.c
Normal file
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* fpu_entry.c
|
||||
*
|
||||
* The entry function for wm-FPU-emu
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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 the copyright is to ensure that the covered software
|
||||
* remains freely available to everyone. It is felt to be necessary to
|
||||
* try and prevent the software being taken by unscrupulous people and
|
||||
* (perhaps after modification) being copyrighted or otherwise
|
||||
* restricted and being made no longer freely available. There are a
|
||||
* number of examples of corporations hijacking ideas and trying to
|
||||
* sue the pants of lesser financed entities who try to subsequently
|
||||
* use the ideas.
|
||||
*
|
||||
* If the software were placed in the public domain then there would
|
||||
* be no protection at all. By claiming a copyright it puts at least a
|
||||
* strong moral pressure on the greedy to restrain themselves and
|
||||
* behave ethically. And let's not be naive, we are all subject to the
|
||||
* emotion of greed to some extent...
|
||||
*
|
||||
* Up until now, the software has been covered by the GNU copyleft.
|
||||
* That copyright mechanism has problems for operating systems which
|
||||
* are not themselves covered by the GNU copyleft. Hence I have
|
||||
* decided to allow the covered software to be used with 386BSD under
|
||||
* restrictions which are meant to be broadly similar, but not
|
||||
* identical, to those which already cover the 386BSD operating
|
||||
* system.
|
||||
*
|
||||
* The software, in its form for the Linux operating system, remains
|
||||
* available under the terms of the GNU copyleft.
|
||||
*
|
||||
* W. Metzenthen June 1993.
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "param.h"
|
||||
#include "systm.h"
|
||||
#include "proc.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "control_w.h"
|
||||
#include "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);
|
||||
|
||||
int
|
||||
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 ((((struct pcb *) curproc->p_addr)->pcb_flags & FP_SOFTFP) == 0) {
|
||||
finit();
|
||||
((struct pcb *) curproc->p_addr)->pcb_flags |= FP_SOFTFP;
|
||||
}
|
||||
FPU_info = tframe;
|
||||
FPU_ORIG_EIP = FPU_EIP; /* --pink-- */
|
||||
|
||||
if (FPU_CS != 0x001f) {
|
||||
printf("math_emulate: %x : %x\n", FPU_CS, FPU_EIP);
|
||||
panic("FPU emulation in kernel");
|
||||
}
|
||||
#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 notnow /* I dont know that much of traceing. Is it right? --pink-- */
|
||||
if (curproc->p_flag & STRC)
|
||||
FPU_lookahead = 0;
|
||||
#endif
|
||||
|
||||
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-- */
|
||||
}
|
162
sys/gnu/i386/fpemul/fpu_etc.c
Normal file
162
sys/gnu/i386/fpemul/fpu_etc.c
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* fpu_etc.c
|
||||
*
|
||||
* Implement a few FPU instructions.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "param.h"
|
||||
#include "proc.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "status_w.h"
|
||||
#include "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]) ();
|
||||
}
|
108
sys/gnu/i386/fpemul/fpu_proto.h
Normal file
108
sys/gnu/i386/fpemul/fpu_proto.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* 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 fclex(void);
|
||||
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 */
|
||||
extern int math_emulate(struct trapframe * info);
|
||||
/* fpu_etc.c */
|
||||
extern void fp_etc(void);
|
||||
/* fpu_trig.c */
|
||||
extern void convert_l2reg(long *arg, FPU_REG * dest);
|
||||
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);
|
||||
extern void poly_add_1(FPU_REG * src);
|
||||
/* 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);
|
84
sys/gnu/i386/fpemul/fpu_system.h
Normal file
84
sys/gnu/i386/fpemul/fpu_system.h
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* fpu_system.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FPU_SYSTEM_H
|
||||
#define _FPU_SYSTEM_H
|
||||
|
||||
/* system dependent definitions */
|
||||
|
||||
/*
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
*/
|
||||
|
||||
#define I387 (*(union i387_union *)&(((struct pcb *)curproc->p_addr)->pcb_savefpu))
|
||||
#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
|
1354
sys/gnu/i386/fpemul/fpu_trig.c
Normal file
1354
sys/gnu/i386/fpemul/fpu_trig.c
Normal file
File diff suppressed because it is too large
Load Diff
190
sys/gnu/i386/fpemul/get_address.c
Normal file
190
sys/gnu/i386/fpemul/get_address.c
Normal file
@ -0,0 +1,190 @@
|
||||
/*
|
||||
* get_address.c
|
||||
*
|
||||
* Get the effective address from an FPU instruction.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "param.h"
|
||||
#include "proc.h"
|
||||
#include "systm.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
#include "machine/reg.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "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 *) ®_(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;
|
||||
}
|
256
sys/gnu/i386/fpemul/load_store.c
Normal file
256
sys/gnu/i386/fpemul/load_store.c
Normal file
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "param.h"
|
||||
#include "proc.h"
|
||||
#include "systm.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "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 = fuword((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);*/
|
||||
suword( (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);*/
|
||||
suword( (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;
|
||||
}
|
||||
}
|
41
sys/gnu/i386/fpemul/math_emu.h
Normal file
41
sys/gnu/i386/fpemul/math_emu.h
Normal file
@ -0,0 +1,41 @@
|
||||
#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
|
128
sys/gnu/i386/fpemul/poly_2xm1.c
Normal file
128
sys/gnu/i386/fpemul/poly_2xm1.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* poly_2xm1.c
|
||||
*
|
||||
* Function to compute 2^x-1 by a polynomial approximation.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "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;
|
||||
|
||||
}
|
239
sys/gnu/i386/fpemul/poly_atan.c
Normal file
239
sys/gnu/i386/fpemul/poly_atan.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* p_atan.c
|
||||
*
|
||||
* Compute the tan of a FPU_REG, using a polynomial approximation.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "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};
|
||||
|
||||
|
||||
|
||||
/*--- 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(&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(&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. */
|
||||
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;
|
||||
|
||||
}
|
131
sys/gnu/i386/fpemul/poly_div.s
Normal file
131
sys/gnu/i386/fpemul/poly_div.s
Normal file
@ -0,0 +1,131 @@
|
||||
.file "poly_div.S"
|
||||
/*
|
||||
* poly_div.S
|
||||
*
|
||||
* A set of functions to divide 64 bit integers by fixed numbers.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "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
|
||||
/*---------------------------------------------------------------------------*/
|
305
sys/gnu/i386/fpemul/poly_l2.c
Normal file
305
sys/gnu/i386/fpemul/poly_l2.c
Normal file
@ -0,0 +1,305 @@
|
||||
/*
|
||||
* poly_l2.c
|
||||
*
|
||||
* Compute the base 2 log of a FPU_REG, using a polynomial approximation.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "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(&(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;
|
||||
}
|
111
sys/gnu/i386/fpemul/poly_mul64.s
Normal file
111
sys/gnu/i386/fpemul/poly_mul64.s
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "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
|
179
sys/gnu/i386/fpemul/poly_sin.c
Normal file
179
sys/gnu/i386/fpemul/poly_sin.c
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* poly_sin.c
|
||||
*
|
||||
* Computation of an approximation of the sin function by a polynomial
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "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(&(accum.sigl), &(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(&(negaccum.sigl), &(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 */
|
||||
}
|
||||
}
|
216
sys/gnu/i386/fpemul/poly_tan.c
Normal file
216
sys/gnu/i386/fpemul/poly_tan.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* poly_tan.c
|
||||
*
|
||||
* Compute the tan of a FPU_REG, using a polynomial approximation.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "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(&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(&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(&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(&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);
|
||||
}
|
||||
|
||||
}
|
179
sys/gnu/i386/fpemul/polynomial.s
Normal file
179
sys/gnu/i386/fpemul/polynomial.s
Normal file
@ -0,0 +1,179 @@
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
.file "fpolynom.s"
|
||||
|
||||
#include "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
|
290
sys/gnu/i386/fpemul/reg_add_sub.c
Normal file
290
sys/gnu/i386/fpemul/reg_add_sub.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* reg_add_sub.c
|
||||
*
|
||||
* Functions to add or subtract two registers and put the result in a third.
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| For each function, the destination may be any FPU_REG, including one of |
|
||||
| the source FPU_REGs. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "control_w.h"
|
||||
#include "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
|
||||
}
|
371
sys/gnu/i386/fpemul/reg_compare.c
Normal file
371
sys/gnu/i386/fpemul/reg_compare.c
Normal file
@ -0,0 +1,371 @@
|
||||
/*
|
||||
* reg_compare.c
|
||||
*
|
||||
* Compare two floating point registers
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| compare() is the core FPU_REG comparison function |
|
||||
+---------------------------------------------------------------------------*/
|
||||
#include "param.h"
|
||||
#include "proc.h"
|
||||
#include "systm.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "exception.h"
|
||||
#include "control_w.h"
|
||||
#include "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, 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, 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, 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();
|
||||
}
|
159
sys/gnu/i386/fpemul/reg_constant.c
Normal file
159
sys/gnu/i386/fpemul/reg_constant.c
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
* reg_constant.c
|
||||
*
|
||||
* All of the constant FPU_REGs
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
#include "param.h"
|
||||
#include "proc.h"
|
||||
#include "systm.h"
|
||||
#include "machine/cpu.h"
|
||||
#include "machine/pcb.h"
|
||||
|
||||
#include "fpu_emu.h"
|
||||
#include "fpu_system.h"
|
||||
#include "status_w.h"
|
||||
#include "reg_constant.h"
|
||||
|
||||
|
||||
FPU_REG CONST_1 = {SIGN_POS, TW_Valid, EXP_BIAS,
|
||||
0x00000000, 0x80000000};
|
||||
FPU_REG CONST_2 = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
|
||||
0x00000000, 0x80000000};
|
||||
FPU_REG CONST_HALF = {SIGN_POS, TW_Valid, EXP_BIAS - 1,
|
||||
0x00000000, 0x80000000};
|
||||
FPU_REG CONST_L2T = {SIGN_POS, TW_Valid, EXP_BIAS + 1,
|
||||
0xcd1b8afe, 0xd49a784b};
|
||||
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};
|
||||
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]) ();
|
||||
}
|
69
sys/gnu/i386/fpemul/reg_constant.h
Normal file
69
sys/gnu/i386/fpemul/reg_constant.h
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* reg_constant.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _REG_CONSTANT_H_
|
||||
#define _REG_CONSTANT_H_
|
||||
|
||||
#include "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_ */
|
282
sys/gnu/i386/fpemul/reg_div.s
Normal file
282
sys/gnu/i386/fpemul/reg_div.s
Normal file
@ -0,0 +1,282 @@
|
||||
.file "reg_div.S"
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
* unsigned int control_word)
|
||||
*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "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
|
1374
sys/gnu/i386/fpemul/reg_ld_str.c
Normal file
1374
sys/gnu/i386/fpemul/reg_ld_str.c
Normal file
File diff suppressed because it is too large
Load Diff
149
sys/gnu/i386/fpemul/reg_mul.c
Normal file
149
sys/gnu/i386/fpemul/reg_mul.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* reg_mul.c
|
||||
*
|
||||
* Multiply one FPU_REG by another, put the result in a destination FPU_REG.
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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 destination may be any FPU_REG, including one of the source FPU_REGs. |
|
||||
+---------------------------------------------------------------------------*/
|
||||
|
||||
#include "exception.h"
|
||||
#include "reg_constant.h"
|
||||
#include "fpu_emu.h"
|
||||
#include "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 */
|
||||
}
|
||||
}
|
169
sys/gnu/i386/fpemul/reg_norm.s
Normal file
169
sys/gnu/i386/fpemul/reg_norm.s
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "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
|
||||
|
||||
|
640
sys/gnu/i386/fpemul/reg_round.s
Normal file
640
sys/gnu/i386/fpemul/reg_round.s
Normal file
@ -0,0 +1,640 @@
|
||||
.file "reg_round.S"
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "fpu_asm.h"
|
||||
#include "exception.h"
|
||||
#include "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
|
231
sys/gnu/i386/fpemul/reg_u_add.s
Normal file
231
sys/gnu/i386/fpemul/reg_u_add.s
Normal file
@ -0,0 +1,231 @@
|
||||
.file "reg_u_add.S"
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
| 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 "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "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
|
493
sys/gnu/i386/fpemul/reg_u_div.s
Normal file
493
sys/gnu/i386/fpemul/reg_u_div.s
Normal file
@ -0,0 +1,493 @@
|
||||
.file "reg_u_div.S"
|
||||
/*
|
||||
* reg_u_div.S
|
||||
*
|
||||
* Core division routines
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "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
|
186
sys/gnu/i386/fpemul/reg_u_mul.s
Normal file
186
sys/gnu/i386/fpemul/reg_u_mul.s
Normal file
@ -0,0 +1,186 @@
|
||||
.file "reg_u_mul.S"
|
||||
/*
|
||||
* reg_u_mul.S
|
||||
*
|
||||
* Core multiplication routine
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "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
|
||||
|
348
sys/gnu/i386/fpemul/reg_u_sub.s
Normal file
348
sys/gnu/i386/fpemul/reg_u_sub.s
Normal file
@ -0,0 +1,348 @@
|
||||
.file "reg_u_sub.S"
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
| 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 "exception.h"
|
||||
#include "fpu_asm.h"
|
||||
#include "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
|
||||
|
93
sys/gnu/i386/fpemul/status_w.h
Normal file
93
sys/gnu/i386/fpemul/status_w.h
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* status_w.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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_ */
|
48
sys/gnu/i386/fpemul/version.h
Normal file
48
sys/gnu/i386/fpemul/version.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* version.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define FPU_VERSION "wm-FPU-emu version BETA 1.4"
|
248
sys/gnu/i386/fpemul/wm_shrx.s
Normal file
248
sys/gnu/i386/fpemul/wm_shrx.s
Normal file
@ -0,0 +1,248 @@
|
||||
.file "wm_shrx.S"
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "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
|
483
sys/gnu/i386/fpemul/wm_sqrt.s
Normal file
483
sys/gnu/i386/fpemul/wm_sqrt.s
Normal file
@ -0,0 +1,483 @@
|
||||
.file "wm_sqrt.S"
|
||||
/*
|
||||
* 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 W. Metzenthen, 22 Parker St, Ormond,
|
||||
* Vic 3163, Australia.
|
||||
* E-mail apm233m@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 operating system. 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------+
|
||||
| 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 "exception.h"
|
||||
#include "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
|
Loading…
Reference in New Issue
Block a user