Import of gpl'ed math emulator.

No changes have been done.
This commit is contained in:
gclarkii 1994-04-29 20:42:02 +00:00
parent a497738bea
commit 77d72caa6d
44 changed files with 11697 additions and 0 deletions

View 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
View 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.

View 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

View 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_ */

View 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

View 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;
}

View 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_ */

View 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();
}

View 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_ */

View 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();
}

View 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_ */

View 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-- */
}

View 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]) ();
}

View 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);

View 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

File diff suppressed because it is too large Load Diff

View 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 *) &REG_(FPU_rm);
switch (mod) {
case 0:
if (FPU_rm == 5) {
/* Special case: disp32 */
REENTRANT_CHECK(OFF);
offset = fuword((unsigned long *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP += 4;
FPU_data_address = (void *) offset;
return;
} else {
FPU_data_address = (void *) *cpu_reg_ptr; /* Just return the
* contents of the cpu
* register */
return;
}
case 1:
/* 8 bit signed displacement */
REENTRANT_CHECK(OFF);
offset = (signed char) fubyte((char *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP++;
break;
case 2:
/* 32 bit displacement */
REENTRANT_CHECK(OFF);
offset = (signed) fuword((unsigned long *) FPU_EIP);
REENTRANT_CHECK(ON);
FPU_EIP += 4;
break;
case 3:
/* Not legal for the FPU */
EXCEPTION(EX_Invalid);
}
FPU_data_address = offset + (char *) *cpu_reg_ptr;
}

View 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;
}
}

View 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

View 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;
}

View 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;
}

View 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
/*---------------------------------------------------------------------------*/

View 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;
}

View 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

View 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 */
}
}

View 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);
}
}

View 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

View 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
}

View 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();
}

View 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]) ();
}

View 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_ */

View 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

File diff suppressed because it is too large Load Diff

View 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 */
}
}

View 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

View 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

View 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

View 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

View 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

View 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

View 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_ */

View 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"

View 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

View 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