Fail* directories reorganized, Code-cleanup (-> coding-style), Typos+comments fixed.

git-svn-id: https://www4.informatik.uni-erlangen.de/i4svn/danceos/trunk/devel/fail@1321 8c4709b5-6ec9-48aa-a5cd-a96041d1645a
This commit is contained in:
adrian
2012-06-08 20:09:43 +00:00
parent d474a5b952
commit 2575604b41
866 changed files with 1848 additions and 1879 deletions

View File

@ -0,0 +1,178 @@
# Copyright (C) 2001 The Bochs Project
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@SUFFIX_LINE@
srcdir = @srcdir@
VPATH = @srcdir@
top_builddir = ..
top_srcdir = @top_srcdir@
SHELL = /bin/sh
@SET_MAKE@
CC = @CC@
CFLAGS = @CFLAGS@ @GUI_CFLAGS@
CXX = @CXX@
CXXFLAGS = @CXXFLAGS@ @GUI_CXXFLAGS@
#CFLAGS = -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -mpreferred-stack-boundary=2 -DCPU=686 -march=i686
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
RANLIB = @RANLIB@
L_TARGET = libfpu.a
BX_INCDIRS = -I.. -I$(srcdir)/.. -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@ -I. -I$(srcdir)/. -I./stubs -I$(srcdir)/./stubs
OBJS = ferr.o fpu.o fpu_arith.o fpu_compare.o fpu_const.o \
fpu_load_store.o fpu_misc.o fpu_trans.o fpu_tags.o \
fprem.o fsincos.o f2xm1.o fyl2x.o fpatan.o \
softfloat.o softfloatx80.o softfloat-specialize.o \
softfloat-round-pack.o poly.o
all: libfpu.a
.@CPP_SUFFIX@.o:
$(CXX) @DASH@c $(BX_INCDIRS) $(CXXFLAGS) @CXXFP@$< @OFP@$@
.c.o:
$(CC) @DASH@c $(CFLAGS) $(BX_INCDIRS) $< @OFP@$@
libfpu.a: $(OBJS)
@RMCOMMAND@ libfpu.a
@MAKELIB@ $(OBJS)
$(RANLIB) libfpu.a
clean:
@RMCOMMAND@ *.o
@RMCOMMAND@ *.a
dist-clean: clean
@RMCOMMAND@ Makefile
###########################################
# dependencies generated by
# gcc -MM -I.. -I../instrument/stubs *.cc | sed -e 's/\.cc/.@CPP_SUFFIX@/g'
###########################################
f2xm1.o: f2xm1.@CPP_SUFFIX@ softfloatx80.h softfloat.h ../config.h \
softfloat-specialize.h softfloat-macros.h softfloat-round-pack.h
ferr.o: ferr.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../ltdl.h ../gui/gui.h ../instrument/stubs/instrument.h \
../cpu/cpu.h ../cpu/model_specific.h ../cpu/crregs.h \
../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloat-specialize.h softfloat.h
fpatan.o: fpatan.@CPP_SUFFIX@ softfloatx80.h softfloat.h ../config.h \
softfloat-specialize.h softfloat-macros.h softfloat-round-pack.h \
fpu_constant.h
fprem.o: fprem.@CPP_SUFFIX@ softfloatx80.h softfloat.h ../config.h \
softfloat-specialize.h softfloat-round-pack.h softfloat-macros.h
fpu_arith.o: fpu_arith.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../cpu/cpu.h ../cpu/model_specific.h \
../cpu/crregs.h ../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloatx80.h softfloat.h \
softfloat-specialize.h
fpu.o: fpu.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h ../bx_debug/debug.h \
../config.h ../osdep.h ../bxversion.h ../gui/siminterface.h \
../gui/paramtree.h ../memory/memory.h ../pc_system.h ../plugin.h \
../extplugin.h ../ltdl.h ../gui/gui.h ../instrument/stubs/instrument.h \
../cpu/cpu.h ../cpu/model_specific.h ../cpu/crregs.h \
../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h ../iodev/iodev.h ../param_names.h \
softfloatx80.h softfloat.h softfloat-specialize.h
fpu_compare.o: fpu_compare.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../cpu/cpu.h ../cpu/model_specific.h \
../cpu/crregs.h ../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloatx80.h softfloat.h \
softfloat-specialize.h
fpu_const.o: fpu_const.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../cpu/cpu.h ../cpu/model_specific.h \
../cpu/crregs.h ../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloatx80.h softfloat.h \
softfloat-specialize.h
fpu_load_store.o: fpu_load_store.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../cpu/cpu.h ../cpu/model_specific.h \
../cpu/crregs.h ../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloatx80.h softfloat.h \
softfloat-specialize.h
fpu_misc.o: fpu_misc.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../cpu/cpu.h ../cpu/model_specific.h \
../cpu/crregs.h ../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloatx80.h softfloat.h \
softfloat-specialize.h
fpu_tags.o: fpu_tags.@CPP_SUFFIX@ ../config.h softfloat.h softfloat-specialize.h \
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
../fpu/control_w.h
fpu_trans.o: fpu_trans.@CPP_SUFFIX@ ../bochs.h ../config.h ../osdep.h \
../bx_debug/debug.h ../config.h ../osdep.h ../bxversion.h \
../gui/siminterface.h ../gui/paramtree.h ../memory/memory.h \
../pc_system.h ../plugin.h ../extplugin.h ../ltdl.h ../gui/gui.h \
../instrument/stubs/instrument.h ../cpu/cpu.h ../cpu/model_specific.h \
../cpu/crregs.h ../cpu/descriptor.h ../cpu/instr.h ../cpu/ia_opcodes.h \
../cpu/lazy_flags.h ../cpu/icache.h ../cpu/apic.h ../cpu/i387.h \
../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h ../fpu/control_w.h \
../cpu/xmm.h ../cpu/stack.h softfloatx80.h softfloat.h \
softfloat-specialize.h
fsincos.o: fsincos.@CPP_SUFFIX@ softfloatx80.h softfloat.h ../config.h \
softfloat-specialize.h softfloat-macros.h softfloat-round-pack.h \
fpu_constant.h
fyl2x.o: fyl2x.@CPP_SUFFIX@ softfloatx80.h softfloat.h ../config.h \
softfloat-specialize.h softfloat-macros.h softfloat-round-pack.h \
fpu_constant.h
poly.o: poly.@CPP_SUFFIX@ softfloat.h ../config.h
softfloat.o: softfloat.@CPP_SUFFIX@ softfloat.h ../config.h softfloat-round-pack.h \
softfloat-macros.h softfloat-specialize.h
softfloat-round-pack.o: softfloat-round-pack.@CPP_SUFFIX@ softfloat.h ../config.h \
softfloat-round-pack.h softfloat-macros.h softfloat-specialize.h
softfloat-specialize.o: softfloat-specialize.@CPP_SUFFIX@ softfloat.h ../config.h \
softfloat-specialize.h softfloat-macros.h
softfloatx80.o: softfloatx80.@CPP_SUFFIX@ softfloatx80.h softfloat.h ../config.h \
softfloat-specialize.h softfloat-round-pack.h softfloat-macros.h

View File

@ -0,0 +1,58 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifndef _CONTROL_W_H_
#define _CONTROL_W_H_
/* ************ */
/* Control Word */
/* ************ */
#define FPU_CW_Reserved_Bits (0xe0c0) /* reserved bits */
#define FPU_CW_Inf (0x1000) /* infinity control, legacy */
#define FPU_CW_RC (0x0C00) /* rounding control */
#define FPU_CW_PC (0x0300) /* precision control */
#define FPU_RC_RND (0x0000) /* rounding control */
#define FPU_RC_DOWN (0x0400)
#define FPU_RC_UP (0x0800)
#define FPU_RC_CHOP (0x0C00)
#define FPU_CW_Precision (0x0020) /* loss of precision mask */
#define FPU_CW_Underflow (0x0010) /* underflow mask */
#define FPU_CW_Overflow (0x0008) /* overflow mask */
#define FPU_CW_Zero_Div (0x0004) /* divide by zero mask */
#define FPU_CW_Denormal (0x0002) /* denormalized operand mask */
#define FPU_CW_Invalid (0x0001) /* invalid operation mask */
#define FPU_CW_Exceptions_Mask (0x003f) /* all masks */
/* Precision control bits affect only the following:
ADD, SUB(R), MUL, DIV(R), and SQRT */
#define FPU_PR_32_BITS (0x000)
#define FPU_PR_RESERVED_BITS (0x100)
#define FPU_PR_64_BITS (0x200)
#define FPU_PR_80_BITS (0x300)
#endif

178
simulators/bochs/fpu/f2xm1.cc Executable file
View File

@ -0,0 +1,178 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define FLOAT128
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
static const floatx80 floatx80_negone = packFloatx80(1, 0x3fff, BX_CONST64(0x8000000000000000));
static const floatx80 floatx80_neghalf = packFloatx80(1, 0x3ffe, BX_CONST64(0x8000000000000000));
static const float128 float128_ln2 =
packFloat128(BX_CONST64(0x3ffe62e42fefa39e), BX_CONST64(0xf35793c7673007e6));
#ifdef BETTER_THAN_PENTIUM
#define LN2_SIG_HI BX_CONST64(0xb17217f7d1cf79ab)
#define LN2_SIG_LO BX_CONST64(0xc9e3b39800000000) /* 96 bit precision */
#else
#define LN2_SIG_HI BX_CONST64(0xb17217f7d1cf79ab)
#define LN2_SIG_LO BX_CONST64(0xc000000000000000) /* 67-bit precision */
#endif
#define EXP_ARR_SIZE 15
static float128 exp_arr[EXP_ARR_SIZE] =
{
PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */
PACK_FLOAT_128(0x3ffe000000000000, 0x0000000000000000), /* 2 */
PACK_FLOAT_128(0x3ffc555555555555, 0x5555555555555555), /* 3 */
PACK_FLOAT_128(0x3ffa555555555555, 0x5555555555555555), /* 4 */
PACK_FLOAT_128(0x3ff8111111111111, 0x1111111111111111), /* 5 */
PACK_FLOAT_128(0x3ff56c16c16c16c1, 0x6c16c16c16c16c17), /* 6 */
PACK_FLOAT_128(0x3ff2a01a01a01a01, 0xa01a01a01a01a01a), /* 7 */
PACK_FLOAT_128(0x3fefa01a01a01a01, 0xa01a01a01a01a01a), /* 8 */
PACK_FLOAT_128(0x3fec71de3a556c73, 0x38faac1c88e50017), /* 9 */
PACK_FLOAT_128(0x3fe927e4fb7789f5, 0xc72ef016d3ea6679), /* 10 */
PACK_FLOAT_128(0x3fe5ae64567f544e, 0x38fe747e4b837dc7), /* 11 */
PACK_FLOAT_128(0x3fe21eed8eff8d89, 0x7b544da987acfe85), /* 12 */
PACK_FLOAT_128(0x3fde6124613a86d0, 0x97ca38331d23af68), /* 13 */
PACK_FLOAT_128(0x3fda93974a8c07c9, 0xd20badf145dfa3e5), /* 14 */
PACK_FLOAT_128(0x3fd6ae7f3e733b81, 0xf11d8656b0ee8cb0) /* 15 */
};
extern float128 EvalPoly(float128 x, float128 *arr, unsigned n, float_status_t &status);
/* required -1 < x < 1 */
static float128 poly_exp(float128 x, float_status_t &status)
{
/*
// 2 3 4 5 6 7 8 9
// x x x x x x x x x
// e - 1 ~ x + --- + --- + --- + --- + --- + --- + --- + --- + ...
// 2! 3! 4! 5! 6! 7! 8! 9!
//
// 2 3 4 5 6 7 8
// x x x x x x x x
// = x [ 1 + --- + --- + --- + --- + --- + --- + --- + --- + ... ]
// 2! 3! 4! 5! 6! 7! 8! 9!
//
// 8 8
// -- 2k -- 2k+1
// p(x) = > C * x q(x) = > C * x
// -- 2k -- 2k+1
// k=0 k=0
//
// x
// e - 1 ~ x * [ p(x) + x * q(x) ]
//
*/
float128 t = EvalPoly(x, exp_arr, EXP_ARR_SIZE, status);
return float128_mul(t, x, status);
}
// =================================================
// x
// FX2M1 Compute 2 - 1
// =================================================
//
// Uses the following identities:
//
// 1. ----------------------------------------------------------
// x x*ln(2)
// 2 = e
//
// 2. ----------------------------------------------------------
// 2 3 4 5 n
// x x x x x x x
// e = 1 + --- + --- + --- + --- + --- + ... + --- + ...
// 1! 2! 3! 4! 5! n!
//
floatx80 f2xm1(floatx80 a, float_status_t &status)
{
Bit64u zSig0, zSig1, zSig2;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a))
{
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
int aSign = extractFloatx80Sign(a);
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1))
return propagateFloatx80NaN(a, status);
return (aSign) ? floatx80_negone : a;
}
if (aExp == 0) {
if (aSig == 0) return a;
float_raise(status, float_flag_denormal | float_flag_inexact);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
tiny_argument:
mul128By64To192(LN2_SIG_HI, LN2_SIG_LO, aSig, &zSig0, &zSig1, &zSig2);
if (0 < (Bit64s) zSig0) {
shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1);
--aExp;
}
return
roundAndPackFloatx80(80, aSign, aExp, zSig0, zSig1, status);
}
float_raise(status, float_flag_inexact);
if (aExp < 0x3FFF)
{
if (aExp < EXP_BIAS-68)
goto tiny_argument;
/* ******************************** */
/* using float128 for approximation */
/* ******************************** */
float128 x = floatx80_to_float128(a, status);
x = float128_mul(x, float128_ln2, status);
x = poly_exp(x, status);
return float128_to_floatx80(x, status);
}
else
{
if (a.exp == 0xBFFF && ! (aSig<<1))
return floatx80_neghalf;
return a;
}
}

133
simulators/bochs/fpu/ferr.cc Executable file
View File

@ -0,0 +1,133 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_FPU
#include "softfloat-specialize.h"
void BX_CPU_C::FPU_stack_overflow(void)
{
/* The masked response */
if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
}
FPU_exception(FPU_EX_Stack_Overflow);
}
void BX_CPU_C::FPU_stack_underflow(int stnr, int pop_stack)
{
/* The masked response */
if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_WRITE_FPU_REG(floatx80_default_nan, stnr);
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
FPU_exception(FPU_EX_Stack_Underflow);
}
/* Returns unmasked exceptions if occured */
unsigned BX_CPU_C::FPU_exception(unsigned exception, bx_bool is_store)
{
/* Extract only the bits which we use to set the status word */
exception &= (FPU_SW_Exceptions_Mask);
Bit32u status = FPU_PARTIAL_STATUS;
unsigned unmasked = exception & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask;
// if IE or DZ exception happen nothing else will be reported
if (exception & (FPU_EX_Invalid | FPU_EX_Zero_Div))
unmasked &= (FPU_EX_Invalid | FPU_EX_Zero_Div);
/* Set summary bits iff exception isn't masked */
if (unmasked)
FPU_PARTIAL_STATUS |= (FPU_SW_Summary | FPU_SW_Backward);
if (exception & FPU_EX_Invalid) {
// FPU_EX_Invalid cannot come with any other exception but x87 stack fault
FPU_PARTIAL_STATUS |= exception;
if (exception & FPU_SW_Stack_Fault) {
if (! (exception & FPU_SW_C1)) {
/* This bit distinguishes over- from underflow for a stack fault,
and roundup from round-down for precision loss. */
FPU_PARTIAL_STATUS &= ~FPU_SW_C1;
}
}
return unmasked;
}
if (exception & FPU_EX_Zero_Div) {
FPU_PARTIAL_STATUS |= FPU_EX_Zero_Div;
return unmasked;
}
if (exception & FPU_EX_Denormal) {
FPU_PARTIAL_STATUS |= FPU_EX_Denormal;
if (unmasked & FPU_EX_Denormal)
return unmasked & FPU_EX_Denormal;
}
/* Set the corresponding exception bits */
FPU_PARTIAL_STATUS |= exception;
if (exception & FPU_EX_Precision)
{
if (! (exception & FPU_SW_C1)) {
/* This bit distinguishes over- from underflow for a stack fault,
and roundup from round-down for precision loss. */
FPU_PARTIAL_STATUS &= ~FPU_SW_C1;
}
}
// If #P unmasked exception occured the result still has to be
// written to the destination.
unmasked &= ~FPU_EX_Precision;
if (unmasked & (FPU_EX_Underflow | FPU_EX_Overflow)) {
// If unmasked over- or underflow occurs and dest is a memory location:
// - the TOS and destination operands remain unchanged
// - the inexact-result condition is not reported and C1 flag is cleared
// - no result is stored in the memory
// If the destination is in the register stack, adjusted resulting value
// is stored in the destination operand.
if (! is_store) {
unmasked &= ~(FPU_EX_Underflow | FPU_EX_Overflow);
}
else {
FPU_PARTIAL_STATUS &= ~FPU_SW_C1; // clear C1 flag
if (! (status & FPU_EX_Precision))
FPU_PARTIAL_STATUS &= ~FPU_EX_Precision;
}
}
return unmasked;
}
#endif

283
simulators/bochs/fpu/fpatan.cc Executable file
View File

@ -0,0 +1,283 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define FLOAT128
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
#include "fpu_constant.h"
#define FPATAN_ARR_SIZE 11
static const float128 float128_one =
packFloat128(BX_CONST64(0x3fff000000000000), BX_CONST64(0x0000000000000000));
static const float128 float128_sqrt3 =
packFloat128(BX_CONST64(0x3fffbb67ae8584ca), BX_CONST64(0xa73b25742d7078b8));
static const floatx80 floatx80_pi =
packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235));
static const float128 float128_pi2 =
packFloat128(BX_CONST64(0x3fff921fb54442d1), BX_CONST64(0x8469898CC5170416));
static const float128 float128_pi4 =
packFloat128(BX_CONST64(0x3ffe921fb54442d1), BX_CONST64(0x8469898CC5170416));
static const float128 float128_pi6 =
packFloat128(BX_CONST64(0x3ffe0c152382d736), BX_CONST64(0x58465BB32E0F580F));
static float128 atan_arr[FPATAN_ARR_SIZE] =
{
PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */
PACK_FLOAT_128(0xbffd555555555555, 0x5555555555555555), /* 3 */
PACK_FLOAT_128(0x3ffc999999999999, 0x999999999999999a), /* 5 */
PACK_FLOAT_128(0xbffc249249249249, 0x2492492492492492), /* 7 */
PACK_FLOAT_128(0x3ffbc71c71c71c71, 0xc71c71c71c71c71c), /* 9 */
PACK_FLOAT_128(0xbffb745d1745d174, 0x5d1745d1745d1746), /* 11 */
PACK_FLOAT_128(0x3ffb3b13b13b13b1, 0x3b13b13b13b13b14), /* 13 */
PACK_FLOAT_128(0xbffb111111111111, 0x1111111111111111), /* 15 */
PACK_FLOAT_128(0x3ffae1e1e1e1e1e1, 0xe1e1e1e1e1e1e1e2), /* 17 */
PACK_FLOAT_128(0xbffaaf286bca1af2, 0x86bca1af286bca1b), /* 19 */
PACK_FLOAT_128(0x3ffa861861861861, 0x8618618618618618) /* 21 */
};
extern float128 OddPoly(float128 x, float128 *arr, unsigned n, float_status_t &status);
/* |x| < 1/4 */
static float128 poly_atan(float128 x1, float_status_t &status)
{
/*
// 3 5 7 9 11 13 15 17
// x x x x x x x x
// atan(x) ~ x - --- + --- - --- + --- - ---- + ---- - ---- + ----
// 3 5 7 9 11 13 15 17
//
// 2 4 6 8 10 12 14 16
// x x x x x x x x
// = x * [ 1 - --- + --- - --- + --- - ---- + ---- - ---- + ---- ]
// 3 5 7 9 11 13 15 17
//
// 5 5
// -- 4k -- 4k+2
// p(x) = > C * x q(x) = > C * x
// -- 2k -- 2k+1
// k=0 k=0
//
// 2
// atan(x) ~ x * [ p(x) + x * q(x) ]
//
*/
return OddPoly(x1, atan_arr, FPATAN_ARR_SIZE, status);
}
// =================================================
// FPATAN Compute y * log (x)
// 2
// =================================================
//
// Uses the following identities:
//
// 1. ----------------------------------------------------------
//
// atan(-x) = -atan(x)
//
// 2. ----------------------------------------------------------
//
// x + y
// atan(x) + atan(y) = atan -------, xy < 1
// 1-xy
//
// x + y
// atan(x) + atan(y) = atan ------- + PI, x > 0, xy > 1
// 1-xy
//
// x + y
// atan(x) + atan(y) = atan ------- - PI, x < 0, xy > 1
// 1-xy
//
// 3. ----------------------------------------------------------
//
// atan(x) = atan(INF) + atan(- 1/x)
//
// x-1
// atan(x) = PI/4 + atan( ----- )
// x+1
//
// x * sqrt(3) - 1
// atan(x) = PI/6 + atan( ----------------- )
// x + sqrt(3)
//
// 4. ----------------------------------------------------------
// 3 5 7 9 2n+1
// x x x x n x
// atan(x) = x - --- + --- - --- + --- - ... + (-1) ------ + ...
// 3 5 7 9 2n+1
//
floatx80 fpatan(floatx80 a, floatx80 b, float_status_t &status)
{
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b)) {
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
int aSign = extractFloatx80Sign(a);
Bit64u bSig = extractFloatx80Frac(b);
Bit32s bExp = extractFloatx80Exp(b);
int bSign = extractFloatx80Sign(b);
int zSign = aSign ^ bSign;
if (bExp == 0x7FFF)
{
if ((Bit64u) (bSig<<1))
return propagateFloatx80NaN(a, b, status);
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1))
return propagateFloatx80NaN(a, b, status);
if (aSign) { /* return 3PI/4 */
return roundAndPackFloatx80(80, bSign,
FLOATX80_3PI4_EXP, FLOAT_3PI4_HI, FLOAT_3PI4_LO, status);
}
else { /* return PI/4 */
return roundAndPackFloatx80(80, bSign,
FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status);
}
}
if (aSig && (aExp == 0))
float_raise(status, float_flag_denormal);
/* return PI/2 */
return roundAndPackFloatx80(80, bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status);
}
if (aExp == 0x7FFF)
{
if ((Bit64u) (aSig<<1))
return propagateFloatx80NaN(a, b, status);
if (bSig && (bExp == 0))
float_raise(status, float_flag_denormal);
return_PI_or_ZERO:
if (aSign) { /* return PI */
return roundAndPackFloatx80(80, bSign, FLOATX80_PI_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status);
} else { /* return 0 */
return packFloatx80(bSign, 0, 0);
}
}
if (bExp == 0)
{
if (bSig == 0) {
if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal);
goto return_PI_or_ZERO;
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
if (aExp == 0)
{
if (aSig == 0) /* return PI/2 */
return roundAndPackFloatx80(80, bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status);
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
}
float_raise(status, float_flag_inexact);
/* |a| = |b| ==> return PI/4 */
if (aSig == bSig && aExp == bExp)
return roundAndPackFloatx80(80, bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status);
/* ******************************** */
/* using float128 for approximation */
/* ******************************** */
float128 a128 = normalizeRoundAndPackFloat128(0, aExp-0x10, aSig, 0, status);
float128 b128 = normalizeRoundAndPackFloat128(0, bExp-0x10, bSig, 0, status);
float128 x;
int swap = 0, add_pi6 = 0, add_pi4 = 0;
if (aExp > bExp || (aExp == bExp && aSig > bSig))
{
x = float128_div(b128, a128, status);
}
else {
x = float128_div(a128, b128, status);
swap = 1;
}
Bit32s xExp = extractFloat128Exp(x);
if (xExp <= EXP_BIAS-40)
goto approximation_completed;
if (x.hi >= BX_CONST64(0x3ffe800000000000)) // 3/4 < x < 1
{
/*
arctan(x) = arctan((x-1)/(x+1)) + pi/4
*/
float128 t1 = float128_sub(x, float128_one, status);
float128 t2 = float128_add(x, float128_one, status);
x = float128_div(t1, t2, status);
add_pi4 = 1;
}
else
{
/* argument correction */
if (xExp >= 0x3FFD) // 1/4 < x < 3/4
{
/*
arctan(x) = arctan((x*sqrt(3)-1)/(x+sqrt(3))) + pi/6
*/
float128 t1 = float128_mul(x, float128_sqrt3, status);
float128 t2 = float128_add(x, float128_sqrt3, status);
x = float128_sub(t1, float128_one, status);
x = float128_div(x, t2, status);
add_pi6 = 1;
}
}
x = poly_atan(x, status);
if (add_pi6) x = float128_add(x, float128_pi6, status);
if (add_pi4) x = float128_add(x, float128_pi4, status);
approximation_completed:
if (swap) x = float128_sub(float128_pi2, x, status);
floatx80 result = float128_to_floatx80(x, status);
if (zSign) floatx80_chs(result);
int rSign = extractFloatx80Sign(result);
if (!bSign && rSign)
return floatx80_add(result, floatx80_pi, status);
if (bSign && !rSign)
return floatx80_sub(result, floatx80_pi, status);
return result;
}

191
simulators/bochs/fpu/fprem.cc Executable file
View File

@ -0,0 +1,191 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
#define USE_estimateDiv128To64
#include "softfloat-macros.h"
/* executes single exponent reduction cycle */
static Bit64u remainder_kernel(Bit64u aSig0, Bit64u bSig, int expDiff, Bit64u *zSig0, Bit64u *zSig1)
{
Bit64u term0, term1;
Bit64u aSig1 = 0;
shortShift128Left(aSig1, aSig0, expDiff, &aSig1, &aSig0);
Bit64u q = estimateDiv128To64(aSig1, aSig0, bSig);
mul64To128(bSig, q, &term0, &term1);
sub128(aSig1, aSig0, term0, term1, zSig1, zSig0);
while ((Bit64s)(*zSig1) < 0) {
--q;
add128(*zSig1, *zSig0, 0, bSig, zSig1, zSig0);
}
return q;
}
static int do_fprem(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, int rounding_mode, float_status_t &status)
{
Bit32s aExp, bExp, zExp, expDiff;
Bit64u aSig0, aSig1, bSig;
int aSign;
q = 0;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b))
{
float_raise(status, float_flag_invalid);
r = floatx80_default_nan;
return -1;
}
aSig0 = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
aSign = extractFloatx80Sign(a);
bSig = extractFloatx80Frac(b);
bExp = extractFloatx80Exp(b);
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig0<<1) || ((bExp == 0x7FFF) && (Bit64u) (bSig<<1))) {
r = propagateFloatx80NaN(a, b, status);
return -1;
}
float_raise(status, float_flag_invalid);
r = floatx80_default_nan;
return -1;
}
if (bExp == 0x7FFF) {
if ((Bit64u) (bSig<<1)) {
r = propagateFloatx80NaN(a, b, status);
return -1;
}
if (aExp == 0 && aSig0) {
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
r = (a.fraction & BX_CONST64(0x8000000000000000)) ?
packFloatx80(aSign, aExp, aSig0) : a;
return 0;
}
r = a;
return 0;
}
if (bExp == 0) {
if (bSig == 0) {
float_raise(status, float_flag_invalid);
r = floatx80_default_nan;
return -1;
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
if (aExp == 0) {
if (aSig0 == 0) {
r = a;
return 0;
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
}
expDiff = aExp - bExp;
aSig1 = 0;
Bit32u overflow = 0;
if (expDiff >= 64) {
int n = (expDiff & 0x1f) | 0x20;
remainder_kernel(aSig0, bSig, n, &aSig0, &aSig1);
zExp = aExp - n;
overflow = 1;
}
else {
zExp = bExp;
if (expDiff < 0) {
if (expDiff < -1) {
r = (a.fraction & BX_CONST64(0x8000000000000000)) ?
packFloatx80(aSign, aExp, aSig0) : a;
return 0;
}
shift128Right(aSig0, 0, 1, &aSig0, &aSig1);
expDiff = 0;
}
if (expDiff > 0) {
q = remainder_kernel(aSig0, bSig, expDiff, &aSig0, &aSig1);
}
else {
if (bSig <= aSig0) {
aSig0 -= bSig;
q = 1;
}
}
if (rounding_mode == float_round_nearest_even)
{
Bit64u term0, term1;
shift128Right(bSig, 0, 1, &term0, &term1);
if (! lt128(aSig0, aSig1, term0, term1))
{
int lt = lt128(term0, term1, aSig0, aSig1);
int eq = eq128(aSig0, aSig1, term0, term1);
if ((eq && (q & 1)) || lt) {
aSign = !aSign;
++q;
}
if (lt) sub128(bSig, 0, aSig0, aSig1, &aSig0, &aSig1);
}
}
}
r = normalizeRoundAndPackFloatx80(80, aSign, zExp, aSig0, aSig1, status);
return overflow;
}
/*----------------------------------------------------------------------------
| Returns the remainder of the extended double-precision floating-point value
| `a' with respect to the corresponding value `b'. The operation is performed
| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
int floatx80_ieee754_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status)
{
return do_fprem(a, b, r, q, float_round_nearest_even, status);
}
/*----------------------------------------------------------------------------
| Returns the remainder of the extended double-precision floating-point value
| `a' with respect to the corresponding value `b'. Unlike previous function
| the function does not compute the remainder specified in the IEC/IEEE
| Standard for Binary Floating-Point Arithmetic. This function operates
| differently from the previous function in the way that it rounds the
| quotient of 'a' divided by 'b' to an integer.
*----------------------------------------------------------------------------*/
int floatx80_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status)
{
return do_fprem(a, b, r, q, float_round_to_zero, status);
}

569
simulators/bochs/fpu/fpu.cc Normal file
View File

@ -0,0 +1,569 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#include "iodev/iodev.h"
#define CHECK_PENDING_EXCEPTIONS 1
#if BX_SUPPORT_FPU
void BX_CPU_C::prepareFPU(bxInstruction_c *i, bx_bool check_pending_exceptions)
{
if (BX_CPU_THIS_PTR cr0.get_EM() || BX_CPU_THIS_PTR cr0.get_TS())
exception(BX_NM_EXCEPTION, 0);
if (check_pending_exceptions)
BX_CPU_THIS_PTR FPU_check_pending_exceptions();
}
void BX_CPU_C::FPU_update_last_instruction(bxInstruction_c *i)
{
BX_CPU_THIS_PTR the_i387.foo = (((Bit32u)(i->b1()) << 8) | i->modrm()) & 0x7ff;
BX_CPU_THIS_PTR the_i387.fcs = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
BX_CPU_THIS_PTR the_i387.fip = BX_CPU_THIS_PTR prev_rip;
if (! i->modC0()) {
BX_CPU_THIS_PTR the_i387.fds = BX_CPU_THIS_PTR sregs[i->seg()].selector.value;
BX_CPU_THIS_PTR the_i387.fdp = RMAddr(i);
}
}
void BX_CPU_C::FPU_check_pending_exceptions(void)
{
if(BX_CPU_THIS_PTR the_i387.get_partial_status() & FPU_SW_Summary)
{
// NE=1 selects the native or internal mode, which generates #MF,
// which is an extension introduced with 80486.
// NE=0 selects the original (backward compatible) FPU error
// handling, which generates an IRQ 13 via the PIC chip.
#if BX_CPU_LEVEL >= 4
if (BX_CPU_THIS_PTR cr0.get_NE() != 0) {
exception(BX_MF_EXCEPTION, 0);
}
else
#endif
{
// MSDOS compatibility external interrupt (IRQ13)
BX_INFO(("math_abort: MSDOS compatibility FPU exception"));
DEV_pic_raise_irq(13);
}
}
}
bx_address BX_CPU_C::fpu_save_environment(bxInstruction_c *i)
{
unsigned offset;
/* read all registers in stack order and update x87 tag word */
for(int n=0;n<8;n++) {
// update tag only if it is not empty
if (! IS_TAG_EMPTY(n)) {
int tag = FPU_tagof(BX_READ_FPU_REG(n));
BX_CPU_THIS_PTR the_i387.FPU_settagi(tag, n);
}
}
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address asize_mask = i->asize_mask();
if (protected_mode()) /* Protected Mode */
{
if (i->os32L() || i->os64L())
{
Bit32u tmp;
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
write_virtual_dword(i->seg(), eaddr, tmp);
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
write_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
write_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
write_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
tmp = (BX_CPU_THIS_PTR the_i387.fcs & 0xffff) |
((Bit32u)(BX_CPU_THIS_PTR the_i387.foo)) << 16;
write_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask, tmp);
tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
write_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask, tmp);
tmp = 0xffff0000 | (BX_CPU_THIS_PTR the_i387.fds);
write_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask, tmp);
offset = 0x1c;
}
else /* Protected Mode - 16 bit */
{
Bit16u tmp;
tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
write_virtual_word(i->seg(), eaddr, tmp);
tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
write_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask, tmp);
tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
write_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffff;
write_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask, tmp);
tmp = (BX_CPU_THIS_PTR the_i387.fcs);
write_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fdp) & 0xffff;
write_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask, tmp);
tmp = (BX_CPU_THIS_PTR the_i387.fds);
write_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
offset = 0x0e;
}
}
else /* Real or V86 Mode */
{
Bit32u fp_ip = ((Bit32u)(BX_CPU_THIS_PTR the_i387.fcs) << 4) +
(Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
Bit32u fp_dp = ((Bit32u)(BX_CPU_THIS_PTR the_i387.fds) << 4) +
(Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
if (i->os32L())
{
Bit32u tmp;
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
write_virtual_dword(i->seg(), eaddr, tmp);
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
write_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
write_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
tmp = 0xffff0000 | (fp_ip & 0xffff);
write_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
tmp = ((fp_ip & 0xffff0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
write_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask, tmp);
tmp = 0xffff0000 | (fp_dp & 0xffff);
write_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask, tmp);
tmp = (fp_dp & 0xffff0000) >> 4;
write_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask, tmp);
offset = 0x1c;
}
else /* Real or V86 Mode - 16 bit */
{
Bit16u tmp;
tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
write_virtual_word(i->seg(), eaddr, tmp);
tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
write_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask, tmp);
tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
write_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
tmp = fp_ip & 0xffff;
write_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask, tmp);
tmp = (Bit16u)((fp_ip & 0xf0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
write_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
tmp = fp_dp & 0xffff;
write_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask, tmp);
tmp = (Bit16u)((fp_dp & 0xf0000) >> 4);
write_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
offset = 0x0e;
}
}
return (eaddr + offset) & asize_mask;
}
bx_address BX_CPU_C::fpu_load_environment(bxInstruction_c *i)
{
unsigned offset;
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
bx_address asize_mask = i->asize_mask();
if (protected_mode()) /* Protected Mode */
{
if (i->os32L() || i->os64L())
{
Bit32u tmp;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask);
BX_CPU_THIS_PTR the_i387.fds = tmp & 0xffff;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask);
BX_CPU_THIS_PTR the_i387.fdp = tmp;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask);
BX_CPU_THIS_PTR the_i387.fcs = tmp & 0xffff;
BX_CPU_THIS_PTR the_i387.foo = (tmp >> 16) & 0x07ff;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask);
BX_CPU_THIS_PTR the_i387.fip = tmp;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask);
BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask);
BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
tmp = read_virtual_dword(i->seg(), eaddr);
BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
offset = 0x1c;
}
else /* Protected Mode - 16 bit */
{
Bit16u tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask);
BX_CPU_THIS_PTR the_i387.fds = tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask);
BX_CPU_THIS_PTR the_i387.fdp = tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask);
BX_CPU_THIS_PTR the_i387.fcs = tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask);
BX_CPU_THIS_PTR the_i387.fip = tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask);
BX_CPU_THIS_PTR the_i387.twd = tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask);
BX_CPU_THIS_PTR the_i387.swd = tmp;
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
tmp = read_virtual_word(i->seg(), eaddr);
BX_CPU_THIS_PTR the_i387.cwd = tmp;
/* opcode is defined to be zero */
BX_CPU_THIS_PTR the_i387.foo = 0;
offset = 0x0e;
}
}
else /* Real or V86 Mode */
{
Bit32u fp_ip, fp_dp;
if (i->os32L())
{
Bit32u tmp;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask);
fp_dp = (tmp & 0x0ffff000) << 4;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask);
fp_dp |= tmp & 0xffff;
BX_CPU_THIS_PTR the_i387.fdp = fp_dp;
BX_CPU_THIS_PTR the_i387.fds = 0;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask);
BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
fp_ip = (tmp & 0x0ffff000) << 4;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask);
fp_ip |= tmp & 0xffff;
BX_CPU_THIS_PTR the_i387.fip = fp_ip;
BX_CPU_THIS_PTR the_i387.fcs = 0;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask);
BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
tmp = read_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask);
BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
tmp = read_virtual_dword(i->seg(), eaddr);
BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
offset = 0x1c;
}
else /* Real or V86 Mode - 16 bit */
{
Bit16u tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask);
fp_dp = (tmp & 0xf000) << 4;
tmp = read_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask);
BX_CPU_THIS_PTR the_i387.fdp = fp_dp | tmp;
BX_CPU_THIS_PTR the_i387.fds = 0;
tmp = read_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask);
BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
fp_ip = (tmp & 0xf000) << 4;
tmp = read_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask);
BX_CPU_THIS_PTR the_i387.fip = fp_ip | tmp;
BX_CPU_THIS_PTR the_i387.fcs = 0;
tmp = read_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask);
BX_CPU_THIS_PTR the_i387.twd = tmp;
tmp = read_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask);
BX_CPU_THIS_PTR the_i387.swd = tmp;
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
tmp = read_virtual_word(i->seg(), eaddr);
BX_CPU_THIS_PTR the_i387.cwd = tmp;
offset = 0x0e;
}
}
/* always set bit 6 as '1 */
BX_CPU_THIS_PTR the_i387.cwd =
(BX_CPU_THIS_PTR the_i387.cwd & ~FPU_CW_Reserved_Bits) | 0x0040;
/* check for unmasked exceptions */
if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask)
{
/* set the B and ES bits in the status-word */
FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
}
else {
/* clear the B and ES bits in the status-word */
FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
}
return (eaddr + offset) & asize_mask;
}
/* D9 /5 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDCW(bxInstruction_c *i)
{
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u cwd = read_virtual_word(i->seg(), eaddr);
FPU_CONTROL_WORD = (cwd & ~FPU_CW_Reserved_Bits) | 0x0040; // bit 6 is reserved as '1
/* check for unmasked exceptions */
if (FPU_PARTIAL_STATUS & ~FPU_CONTROL_WORD & FPU_CW_Exceptions_Mask)
{
/* set the B and ES bits in the status-word */
FPU_PARTIAL_STATUS |= FPU_SW_Summary | FPU_SW_Backward;
}
else
{
/* clear the B and ES bits in the status-word */
FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
}
}
/* D9 /7 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTCW(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
Bit16u cwd = BX_CPU_THIS_PTR the_i387.get_control_word();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word(i->seg(), eaddr, cwd);
}
/* DD /7 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
Bit16u swd = BX_CPU_THIS_PTR the_i387.get_status_word();
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
write_virtual_word(i->seg(), eaddr, swd);
}
/* DF E0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW_AX(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
AX = BX_CPU_THIS_PTR the_i387.get_status_word();
}
/* DD /4 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FRSTOR(bxInstruction_c *i)
{
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
bx_address offset = fpu_load_environment(i);
floatx80 tmp;
/* read all registers in stack order */
for(int n=0;n<8;n++)
{
tmp.fraction = read_virtual_qword(i->seg(), (offset + n*10) & i->asize_mask());
tmp.exp = read_virtual_word (i->seg(), (offset + n*10 + 8) & i->asize_mask());
// update tag only if it is not empty
BX_WRITE_FPU_REGISTER_AND_TAG(tmp,
IS_TAG_EMPTY(n) ? FPU_Tag_Empty : FPU_tagof(tmp), n);
}
}
/* DD /6 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSAVE(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
bx_address offset = fpu_save_environment(i);
/* save all registers in stack order. */
for(int n=0;n<8;n++)
{
floatx80 stn = BX_READ_FPU_REG(n);
write_virtual_qword(i->seg(), (offset + n*10) & i->asize_mask(), stn.fraction);
write_virtual_word (i->seg(), (offset + n*10 + 8) & i->asize_mask(), stn.exp);
}
BX_CPU_THIS_PTR the_i387.init();
}
/* 9B E2 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNCLEX(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary|FPU_SW_Stack_Fault|FPU_SW_Precision|
FPU_SW_Underflow|FPU_SW_Overflow|FPU_SW_Zero_Div|FPU_SW_Denormal_Op|
FPU_SW_Invalid);
// do not update last fpu instruction pointer
}
/* DB E3 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNINIT(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
BX_CPU_THIS_PTR the_i387.init();
}
/* D9 /4 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDENV(bxInstruction_c *i)
{
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
fpu_load_environment(i);
/* read all registers in stack order and update x87 tag word */
for(int n=0;n<8;n++) {
// update tag only if it is not empty
if (! IS_TAG_EMPTY(n)) {
int tag = FPU_tagof(BX_READ_FPU_REG(n));
BX_CPU_THIS_PTR the_i387.FPU_settagi(tag, n);
}
}
}
/* D9 /6 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTENV(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
fpu_save_environment(i);
/* mask all floating point exceptions */
FPU_CONTROL_WORD |= FPU_CW_Exceptions_Mask;
/* clear the B and ES bits in the status word */
FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary);
}
/* D9 D0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNOP(bxInstruction_c *i)
{
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
FPU_update_last_instruction(i);
// Perform no FPU operation. This instruction takes up space in the
// instruction stream but does not affect the FPU or machine
// context, except the EIP register.
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPLEGACY(bxInstruction_c *i)
{
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
// FPU performs no specific operation and no internal x87 states
// are affected
}
#endif
#if BX_SUPPORT_FPU
#include "softfloatx80.h"
#include <math.h>
void BX_CPU_C::print_state_FPU(void)
{
static double scale_factor = pow(2.0, -63.0);
static const char* cw_round_control[] = {
"NEAREST", "DOWN", "UP", "CHOP"
};
static const char* cw_precision_control[] = {
"32", "RES", "64", "80"
};
static const char* fp_class[] = {
"ZERO", "xNAN", "-INF", "+INF", "DENORMAL", "NORMAL"
};
Bit32u reg;
reg = BX_CPU_THIS_PTR the_i387.get_status_word();
fprintf(stderr, "status word: 0x%04x: ", reg);
fprintf(stderr, "%s %s TOS%d %s %s %s %s %s %s %s %s %s %s %s\n",
(reg & FPU_SW_Backward) ? "B" : "b",
(reg & FPU_SW_C3) ? "C3" : "c3", (FPU_TOS&7),
(reg & FPU_SW_C2) ? "C2" : "c2",
(reg & FPU_SW_C1) ? "C1" : "c1",
(reg & FPU_SW_C0) ? "C0" : "c0",
(reg & FPU_SW_Summary) ? "ES" : "es",
(reg & FPU_SW_Stack_Fault) ? "SF" : "sf",
(reg & FPU_SW_Precision) ? "PE" : "pe",
(reg & FPU_SW_Underflow) ? "UE" : "ue",
(reg & FPU_SW_Overflow) ? "OE" : "oe",
(reg & FPU_SW_Zero_Div) ? "ZE" : "ze",
(reg & FPU_SW_Denormal_Op) ? "DE" : "de",
(reg & FPU_SW_Invalid) ? "IE" : "ie");
reg = BX_CPU_THIS_PTR the_i387.get_control_word();
fprintf(stderr, "control word: 0x%04x: ", reg);
fprintf(stderr, "%s RC_%s PC_%s %s %s %s %s %s %s\n",
(reg & FPU_CW_Inf) ? "INF" : "inf",
(cw_round_control[(reg & FPU_CW_RC) >> 10]),
(cw_precision_control[(reg & FPU_CW_PC) >> 8]),
(reg & FPU_CW_Precision) ? "PM" : "pm",
(reg & FPU_CW_Underflow) ? "UM" : "um",
(reg & FPU_CW_Overflow) ? "OM" : "om",
(reg & FPU_CW_Zero_Div) ? "ZM" : "zm",
(reg & FPU_CW_Denormal) ? "DM" : "dm",
(reg & FPU_CW_Invalid) ? "IM" : "im");
reg = BX_CPU_THIS_PTR the_i387.get_tag_word();
fprintf(stderr, "tag word: 0x%04x\n", reg);
reg = BX_CPU_THIS_PTR the_i387.foo;
fprintf(stderr, "operand: 0x%04x\n", reg);
fprintf(stderr, "fip: 0x" FMT_ADDRX "\n",
BX_CPU_THIS_PTR the_i387.fip);
reg = BX_CPU_THIS_PTR the_i387.fcs;
fprintf(stderr, "fcs: 0x%04x\n", reg);
fprintf(stderr, "fdp: 0x" FMT_ADDRX "\n",
BX_CPU_THIS_PTR the_i387.fdp);
reg = BX_CPU_THIS_PTR the_i387.fds;
fprintf(stderr, "fds: 0x%04x\n", reg);
// print stack too
int tos = FPU_TOS & 7;
for (int i=0; i<8; i++) {
const floatx80 &fp = BX_FPU_REG(i);
unsigned tag = BX_CPU_THIS_PTR the_i387.FPU_gettagi((i-tos)&7);
if (tag != FPU_Tag_Empty) tag = FPU_tagof(fp);
double f = pow(2.0, ((0x7fff & fp.exp) - 0x3fff));
if (fp.exp & 0x8000) f = -f;
#ifdef _MSC_VER
f *= (double)(signed __int64)(fp.fraction>>1) * scale_factor * 2;
#else
f *= fp.fraction*scale_factor;
#endif
float_class_t f_class = floatx80_class(fp);
fprintf(stderr, "%sFP%d ST%d(%c): raw 0x%04x:%08lx%08lx (%.10f) (%s)\n",
i==tos?"=>":" ", i, (i-tos)&7,
"v0se"[tag],
fp.exp & 0xffff, GET32H(fp.fraction), GET32L(fp.fraction),
f, (f_class == float_NaN) ? (floatx80_is_signaling_nan(fp) ? "SNAN" : "QNAN") : fp_class[f_class]);
}
}
#endif

1199
simulators/bochs/fpu/fpu_arith.cc Executable file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,563 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_FPU
extern float_status_t FPU_pre_exception_handling(Bit16u control_word);
#include "softfloatx80.h"
static int status_word_flags_fpu_compare(int float_relation)
{
switch(float_relation) {
case float_relation_unordered:
return (FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
case float_relation_greater:
return (0);
case float_relation_less:
return (FPU_SW_C0);
case float_relation_equal:
return (FPU_SW_C3);
}
return (-1); // should never get here
}
void BX_CPU_C::write_eflags_fpu_compare(int float_relation)
{
switch(float_relation) {
case float_relation_unordered:
setEFlagsOSZAPC(EFlagsZFMask | EFlagsPFMask | EFlagsCFMask);
break;
case float_relation_greater:
setEFlagsOSZAPC(0);
break;
case float_relation_less:
setEFlagsOSZAPC(EFlagsCFMask);
break;
case float_relation_equal:
setEFlagsOSZAPC(EFlagsZFMask);
break;
default:
BX_PANIC(("write_eflags: unknown floating point compare relation"));
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
int pop_stack = i->nnn() & 1;
// handle special case of FSTP opcode @ 0xDE 0xD0..D7
if (i->b1() == 0xde)
pop_stack = 1;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i->rm()))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i->rm()), status);
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOMI_ST0_STj(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
int pop_stack = i->b1() & 4;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i->rm()))
{
FPU_exception(FPU_EX_Stack_Underflow);
setEFlagsOSZAPC(EFlagsZFMask | EFlagsPFMask | EFlagsCFMask);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i->rm()), status);
BX_CPU_THIS_PTR write_eflags_fpu_compare(rc);
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOMI_ST0_STj(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
int pop_stack = i->b1() & 4;
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i->rm()))
{
FPU_exception(FPU_EX_Stack_Underflow);
setEFlagsOSZAPC(EFlagsZFMask | EFlagsPFMask | EFlagsCFMask);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i->rm()), status);
BX_CPU_THIS_PTR write_eflags_fpu_compare(rc);
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOM_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
int pop_stack = i->nnn() & 1;
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i->rm()))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(i->rm()), status);
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_SINGLE_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
int pop_stack = i->nnn() & 1, rc;
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
float32 load_reg = read_virtual_dword(i->seg(), RMAddr(i));
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
floatx80 a = BX_READ_FPU_REG(0);
if (floatx80_is_nan(a) || floatx80_is_unsupported(a) || float32_is_nan(load_reg)) {
rc = float_relation_unordered;
float_raise(status, float_flag_invalid);
}
else {
rc = floatx80_compare(a, float32_to_floatx80(load_reg, status), status);
}
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOM_DOUBLE_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
int pop_stack = i->nnn() & 1, rc;
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
floatx80 a = BX_READ_FPU_REG(0);
if (floatx80_is_nan(a) || floatx80_is_unsupported(a) || float64_is_nan(load_reg)) {
rc = float_relation_unordered;
float_raise(status, float_flag_invalid);
}
else {
rc = floatx80_compare(a, float64_to_floatx80(load_reg, status), status);
}
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_WORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
int pop_stack = i->nnn() & 1;
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare(BX_READ_FPU_REG(0),
int32_to_floatx80((Bit32s)(load_reg)), status);
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FICOM_DWORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
int pop_stack = i->nnn() & 1;
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32s load_reg = (Bit32s) read_virtual_dword(i->seg(), RMAddr(i));
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare(BX_READ_FPU_REG(0), int32_to_floatx80(load_reg), status);
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
/* DE D9 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOMPP(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
/* DA E9 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FUCOMPP(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare_quiet(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
setcc(status_word_flags_fpu_compare(rc));
if (! FPU_exception(status.float_exception_flags)) {
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCMOV_ST0_STj(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(i->rm()))
{
FPU_stack_underflow(0);
return;
}
floatx80 sti_reg = BX_READ_FPU_REG(i->rm());
bx_bool condition = 0;
switch(i->nnn() & 3)
{
case 0: condition = get_CF(); break;
case 1: condition = get_ZF(); break;
case 2: condition = get_CF() || get_ZF(); break;
case 3: condition = get_PF(); break;
default:
BX_PANIC(("FCMOV_ST0_STj: default case"));
}
if (i->b1() & 1)
condition = !condition;
if (condition)
BX_WRITE_FPU_REG(sti_reg, 0);
}
/* D9 E4 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FTST(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0)) {
FPU_exception(FPU_EX_Stack_Underflow);
setcc(FPU_SW_C0|FPU_SW_C2|FPU_SW_C3);
}
else {
extern const floatx80 Const_Z;
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
int rc = floatx80_compare(BX_READ_FPU_REG(0), Const_Z, status);
setcc(status_word_flags_fpu_compare(rc));
FPU_exception(status.float_exception_flags);
}
}
/* D9 E5 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FXAM(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
floatx80 reg = BX_READ_FPU_REG(0);
int sign = floatx80_sign(reg);
/*
* Examine the contents of the ST(0) register and sets the condition
* code flags C0, C2 and C3 in the FPU status word to indicate the
* class of value or number in the register.
*/
if (IS_TAG_EMPTY(0))
{
setcc(FPU_SW_C3|FPU_SW_C1|FPU_SW_C0);
}
else
{
float_class_t aClass = floatx80_class(reg);
switch(aClass)
{
case float_zero:
setcc(FPU_SW_C3|FPU_SW_C1);
break;
case float_NaN:
// unsupported handled as NaNs
if (floatx80_is_unsupported(reg)) {
setcc(FPU_SW_C1);
} else {
setcc(FPU_SW_C1|FPU_SW_C0);
}
break;
case float_negative_inf:
case float_positive_inf:
setcc(FPU_SW_C2|FPU_SW_C1|FPU_SW_C0);
break;
case float_denormal:
setcc(FPU_SW_C3|FPU_SW_C2|FPU_SW_C1);
break;
case float_normalized:
setcc(FPU_SW_C2|FPU_SW_C1);
break;
}
}
/*
* The C1 flag is set to the sign of the value in ST(0), regardless
* of whether the register is empty or full.
*/
if (! sign)
clear_C1();
}
#endif

174
simulators/bochs/fpu/fpu_const.cc Executable file
View File

@ -0,0 +1,174 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_FPU
#include "softfloatx80.h"
const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
const floatx80 Const_Z = packFloatx80(0, 0x0000, 0);
const floatx80 Const_1 = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
const floatx80 Const_L2T = packFloatx80(0, 0x4000, BX_CONST64(0xd49a784bcd1b8afe));
const floatx80 Const_L2E = packFloatx80(0, 0x3fff, BX_CONST64(0xb8aa3b295c17f0bc));
const floatx80 Const_PI = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235));
const floatx80 Const_LG2 = packFloatx80(0, 0x3ffd, BX_CONST64(0x9a209a84fbcff799));
const floatx80 Const_LN2 = packFloatx80(0, 0x3ffe, BX_CONST64(0xb17217f7d1cf79ac));
const floatx80 Const_INF = packFloatx80(0, 0x7fff, BX_CONST64(0x8000000000000000));
/* A fast way to find out whether x is one of RC_DOWN or RC_CHOP
(and not one of RC_RND or RC_UP).
*/
#define DOWN_OR_CHOP() (FPU_CONTROL_WORD & FPU_CW_RC & FPU_RC_DOWN)
BX_CPP_INLINE floatx80 FPU_round_const(const floatx80 &a, int adj)
{
floatx80 result = a;
result.fraction += adj;
return result;
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDL2T(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(FPU_round_const(Const_L2T, (FPU_CONTROL_WORD & FPU_CW_RC) == FPU_RC_UP), 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDL2E(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(FPU_round_const(Const_L2E, DOWN_OR_CHOP() ? -1 : 0), 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDPI(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(FPU_round_const(Const_PI, DOWN_OR_CHOP() ? -1 : 0), 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDLG2(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(FPU_round_const(Const_LG2, DOWN_OR_CHOP() ? -1 : 0), 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDLN2(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(FPU_round_const(Const_LN2, DOWN_OR_CHOP() ? -1 : 0), 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD1(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(Const_1, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDZ(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(Const_Z, 0);
}
}
#endif

View File

@ -0,0 +1,82 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#ifndef _FPU_CONSTANTS_H_
#define _FPU_CONSTANTS_H_
#include <config.h>
// Pentium CPU uses only 68-bit precision M_PI approximation
// #define BETTER_THAN_PENTIUM
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
//////////////////////////////
// PI, PI/2, PI/4 constants
//////////////////////////////
#define FLOATX80_PI_EXP (0x4000)
// 128-bit PI fraction
#ifdef BETTER_THAN_PENTIUM
#define FLOAT_PI_HI (BX_CONST64(0xc90fdaa22168c234))
#define FLOAT_PI_LO (BX_CONST64(0xc4c6628b80dc1cd1))
#else
#define FLOAT_PI_HI (BX_CONST64(0xc90fdaa22168c234))
#define FLOAT_PI_LO (BX_CONST64(0xC000000000000000))
#endif
#define FLOATX80_PI2_EXP (0x3FFF)
#define FLOATX80_PI4_EXP (0x3FFE)
//////////////////////////////
// 3PI/4 constant
//////////////////////////////
#define FLOATX80_3PI4_EXP (0x4000)
// 128-bit 3PI/4 fraction
#ifdef BETTER_THAN_PENTIUM
#define FLOAT_3PI4_HI (BX_CONST64(0x96cbe3f9990e91a7))
#define FLOAT_3PI4_LO (BX_CONST64(0x9394c9e8a0a5159c))
#else
#define FLOAT_3PI4_HI (BX_CONST64(0x96cbe3f9990e91a7))
#define FLOAT_3PI4_LO (BX_CONST64(0x9000000000000000))
#endif
//////////////////////////////
// 1/LN2 constant
//////////////////////////////
#define FLOAT_LN2INV_EXP (0x3FFF)
// 128-bit 1/LN2 fraction
#ifdef BETTER_THAN_PENTIUM
#define FLOAT_LN2INV_HI (BX_CONST64(0xb8aa3b295c17f0bb))
#define FLOAT_LN2INV_LO (BX_CONST64(0xbe87fed0691d3e89))
#else
#define FLOAT_LN2INV_HI (BX_CONST64(0xb8aa3b295c17f0bb))
#define FLOAT_LN2INV_LO (BX_CONST64(0xC000000000000000))
#endif
#endif

View File

@ -0,0 +1,733 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_FPU
#define swap_values16u(a, b) { Bit16u tmp = a; a = b; b = tmp; }
extern float_status_t FPU_pre_exception_handling(Bit16u control_word);
#include "softfloatx80.h"
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
return;
}
floatx80 sti_reg = floatx80_default_nan;
if (IS_TAG_EMPTY(i->rm()))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else {
sti_reg = BX_READ_FPU_REG(i->rm());
}
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(sti_reg, 0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_SINGLE_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
float32 load_reg = read_virtual_dword(i->seg(), RMAddr(i));
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1)) {
FPU_stack_overflow();
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
// convert to floatx80 format
floatx80 result = float32_to_floatx80(load_reg, status);
unsigned unmasked = FPU_exception(status.float_exception_flags);
if (! (unmasked & FPU_CW_Invalid)) {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_DOUBLE_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
float64 load_reg = read_virtual_qword(i->seg(), RMAddr(i));
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1)) {
FPU_stack_overflow();
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
// convert to floatx80 format
floatx80 result = float64_to_floatx80(load_reg, status);
unsigned unmasked = FPU_exception(status.float_exception_flags);
if (! (unmasked & FPU_CW_Invalid)) {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLD_EXTENDED_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
floatx80 result;
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
result.fraction = read_virtual_qword(i->seg(), RMAddr(i));
result.exp = read_virtual_word(i->seg(), (RMAddr(i)+8) & i->asize_mask());
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1)) {
FPU_stack_overflow();
}
else {
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
}
/* DF /0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_WORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16s load_reg = (Bit16s) read_virtual_word(i->seg(), RMAddr(i));
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1)) {
FPU_stack_overflow();
}
else {
floatx80 result = int32_to_floatx80((Bit32s) load_reg);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
}
/* DB /0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_DWORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit32s load_reg = (Bit32s) read_virtual_dword(i->seg(), RMAddr(i));
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1)) {
FPU_stack_overflow();
}
else {
floatx80 result = int32_to_floatx80(load_reg);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
}
/* DF /5 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FILD_QWORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit64s load_reg = (Bit64s) read_virtual_qword(i->seg(), RMAddr(i));
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1)) {
FPU_stack_overflow();
}
else {
floatx80 result = int64_to_floatx80(load_reg);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
}
/* DF /4 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBLD_PACKED_BCD(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
Bit16u hi2 = read_virtual_word(i->seg(), (RMAddr(i) + 8) & i->asize_mask());
Bit64u lo8 = read_virtual_qword(i->seg(), RMAddr(i));
FPU_update_last_instruction(i);
clear_C1();
if (! IS_TAG_EMPTY(-1))
{
FPU_stack_overflow();
return;
}
// convert packed BCD to 64-bit integer
Bit64s scale = 1;
Bit64s val64 = 0;
for (int n = 0; n < 16; n++)
{
val64 += (lo8 & 0x0f) * scale;
lo8 >>= 4;
scale *= 10;
}
val64 += (hi2 & 0x0f) * scale;
val64 += ((hi2>>4) & 0x0f) * scale * 10;
floatx80 result = int64_to_floatx80(val64);
if (hi2 & 0x8000) // set negative
floatx80_chs(result);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(result, 0);
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
FPU_update_last_instruction(i);
int pop_stack = i->nnn() & 1;
// handle special case of FSTP opcode @ 0xDF 0xD0..D7
if (i->b1() == 0xdf)
pop_stack = 1;
clear_C1();
if (IS_TAG_EMPTY(0)) {
FPU_stack_underflow(i->rm(), pop_stack);
}
else {
floatx80 st0_reg = BX_READ_FPU_REG(0);
BX_WRITE_FPU_REG(st0_reg, i->rm());
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_SINGLE_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
clear_C1();
float32 save_reg = float32_default_nan; /* The masked response */
int pop_stack = i->nnn() & 1;
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_float32(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_dword(i->seg(), RMAddr(i), save_reg);
FPU_PARTIAL_STATUS = x87_sw;
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FST_DOUBLE_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
clear_C1();
float64 save_reg = float64_default_nan; /* The masked response */
int pop_stack = i->nnn() & 1;
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_float64(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_qword(i->seg(), RMAddr(i), save_reg);
FPU_PARTIAL_STATUS = x87_sw;
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
/* DB /7 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSTP_EXTENDED_REAL(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
clear_C1();
floatx80 save_reg = floatx80_default_nan; /* The masked response */
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
save_reg = BX_READ_FPU_REG(0);
}
write_virtual_qword(i->seg(), RMAddr(i), save_reg.fraction);
write_virtual_word(i->seg(), (RMAddr(i) + 8) & i->asize_mask(), save_reg.exp);
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_WORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
Bit16s save_reg = int16_indefinite;
int pop_stack = i->nnn() & 1;
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_int16(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_word(i->seg(), RMAddr(i), (Bit16u)(save_reg));
FPU_PARTIAL_STATUS = x87_sw;
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FIST_DWORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
Bit32s save_reg = int32_indefinite; /* The masked response */
int pop_stack = i->nnn() & 1;
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_int32(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg));
FPU_PARTIAL_STATUS = x87_sw;
if (pop_stack)
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTP_QWORD_INTEGER(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
Bit64s save_reg = int64_indefinite; /* The masked response */
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_int64(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_qword(i->seg(), RMAddr(i), (Bit64u)(save_reg));
FPU_PARTIAL_STATUS = x87_sw;
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
/*
* The packed BCD integer indefinite encoding (FFFFC000000000000000H)
* is stored in response to a masked floating-point invalid-operation
* exception.
*/
Bit16u save_reg_hi = 0xFFFF;
Bit64u save_reg_lo = BX_CONST64(0xC000000000000000);
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
floatx80 reg = BX_READ_FPU_REG(0);
Bit64s save_val = floatx80_to_int64(reg, status);
int sign = (reg.exp & 0x8000) != 0;
if (sign)
save_val = -save_val;
if (save_val > BX_CONST64(999999999999999999)) {
status.float_exception_flags = float_flag_invalid; // throw away other flags
}
if (! (status.float_exception_flags & float_flag_invalid))
{
save_reg_hi = (sign) ? 0x8000 : 0;
save_reg_lo = 0;
for (int i=0; i<16; i++) {
save_reg_lo += ((Bit64u)(save_val % 10)) << (4*i);
save_val /= 10;
}
save_reg_hi += (Bit16u)(save_val % 10);
save_val /= 10;
save_reg_hi += (Bit16u)(save_val % 10) << 4;
}
/* check for fpu arithmetic exceptions */
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
// write packed bcd to memory
write_virtual_qword(i->seg(), RMAddr(i), save_reg_lo);
write_virtual_word(i->seg(), (RMAddr(i) + 8) & i->asize_mask(), save_reg_hi);
FPU_PARTIAL_STATUS = x87_sw;
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
/* DF /1 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP16(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
Bit16s save_reg = int16_indefinite; /* The masked response */
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_int16_round_to_zero(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_word(i->seg(), RMAddr(i), (Bit16u)(save_reg));
FPU_PARTIAL_STATUS = x87_sw;
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
/* DB /1 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP32(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
Bit32s save_reg = int32_indefinite; /* The masked response */
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_int32_round_to_zero(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_dword(i->seg(), RMAddr(i), (Bit32u)(save_reg));
FPU_PARTIAL_STATUS = x87_sw;
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
/* DD /1 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FISTTP64(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
FPU_update_last_instruction(i);
Bit16u x87_sw = FPU_PARTIAL_STATUS;
Bit64s save_reg = int64_indefinite; /* The masked response */
clear_C1();
if (IS_TAG_EMPTY(0))
{
FPU_exception(FPU_EX_Stack_Underflow);
if (! BX_CPU_THIS_PTR the_i387.is_IA_masked())
return;
}
else
{
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
save_reg = floatx80_to_int64_round_to_zero(BX_READ_FPU_REG(0), status);
if (FPU_exception(status.float_exception_flags, 1))
return;
}
// store to the memory might generate an exception, in this case origial FPU_SW must be kept
swap_values16u(x87_sw, FPU_PARTIAL_STATUS);
write_virtual_qword(i->seg(), RMAddr(i), (Bit64u)(save_reg));
FPU_PARTIAL_STATUS = x87_sw;
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
#endif

151
simulators/bochs/fpu/fpu_misc.cc Executable file
View File

@ -0,0 +1,151 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_FPU
#include "softfloatx80.h"
/* D9 C8 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FXCH_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
int st0_tag = BX_CPU_THIS_PTR the_i387.FPU_gettagi(0);
int sti_tag = BX_CPU_THIS_PTR the_i387.FPU_gettagi(i->rm());
floatx80 st0_reg = BX_READ_FPU_REG(0);
floatx80 sti_reg = BX_READ_FPU_REG(i->rm());
clear_C1();
if (st0_tag == FPU_Tag_Empty || sti_tag == FPU_Tag_Empty)
{
FPU_exception(FPU_EX_Stack_Underflow);
if(BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
/* Masked response */
if (st0_tag == FPU_Tag_Empty)
st0_reg = floatx80_default_nan;
if (sti_tag == FPU_Tag_Empty)
sti_reg = floatx80_default_nan;
}
else {
return;
}
}
BX_WRITE_FPU_REG(st0_reg, i->rm());
BX_WRITE_FPU_REG(sti_reg, 0);
}
/* D9 E0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCHS(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
if (IS_TAG_EMPTY(0)) {
FPU_stack_underflow(0);
}
else {
clear_C1();
floatx80 st0_reg = BX_READ_FPU_REG(0);
BX_WRITE_FPU_REG(floatx80_chs(st0_reg), 0);
}
}
/* D9 E1 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FABS(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
if (IS_TAG_EMPTY(0)) {
FPU_stack_underflow(0);
}
else {
clear_C1();
floatx80 st0_reg = BX_READ_FPU_REG(0);
BX_WRITE_FPU_REG(floatx80_abs(st0_reg), 0);
}
}
/* D9 F6 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FDECSTP(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
BX_CPU_THIS_PTR the_i387.tos = (BX_CPU_THIS_PTR the_i387.tos-1) & 7;
}
/* D9 F7 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FINCSTP(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
BX_CPU_THIS_PTR the_i387.tos = (BX_CPU_THIS_PTR the_i387.tos+1) & 7;
}
/* DD C0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FFREE_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
BX_CPU_THIS_PTR the_i387.FPU_settagi(FPU_Tag_Empty, i->rm());
}
/*
* Free the st(0) register and pop it from the FPU stack.
* "Undocumented" by Intel & AMD but mentioned in AMDs Athlon Docs.
*/
/* DF C0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FFREEP_STi(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
BX_CPU_THIS_PTR the_i387.FPU_settagi(FPU_Tag_Empty, i->rm());
BX_CPU_THIS_PTR the_i387.FPU_pop();
}
#endif

View File

@ -0,0 +1,66 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#include "config.h"
#if BX_SUPPORT_FPU
#include "softfloat.h"
#include "softfloat-specialize.h"
/* -----------------------------------------------------------
* Slimmed down version used to compile against a CPU simulator
* rather than a kernel (ported by Kevin Lawton)
* ------------------------------------------------------------ */
#include <cpu/i387.h>
int FPU_tagof(const floatx80 &reg)
{
Bit32s exp = floatx80_exp(reg);
if (exp == 0)
{
if (! floatx80_fraction(reg))
return FPU_Tag_Zero;
/* The number is a de-normal or pseudodenormal. */
return FPU_Tag_Special;
}
if (exp == 0x7fff)
{
/* Is an Infinity, a NaN, or an unsupported data type. */
return FPU_Tag_Special;
}
if (!(reg.fraction & BX_CONST64(0x8000000000000000)))
{
/* Unsupported data type. */
/* Valid numbers have the ms bit set to 1. */
return FPU_Tag_Special;
}
return FPU_Tag_Valid;
}
#endif

436
simulators/bochs/fpu/fpu_trans.cc Executable file
View File

@ -0,0 +1,436 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#include "cpu/cpu.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_SUPPORT_FPU
#include "softfloatx80.h"
#include "softfloat-specialize.h"
extern float_status_t FPU_pre_exception_handling(Bit16u control_word);
/* D9 F0 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::F2XM1(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0)) {
FPU_stack_underflow(0);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 result = f2xm1(BX_READ_FPU_REG(0), status);
if (! FPU_exception(status.float_exception_flags))
BX_WRITE_FPU_REG(result, 0);
}
/* D9 F1 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FYL2X(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_stack_underflow(1, 1 /* pop_stack */);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 result = fyl2x(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
if (! FPU_exception(status.float_exception_flags)) {
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_WRITE_FPU_REG(result, 0);
}
}
/* D9 F2 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPTAN(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
clear_C2();
if (IS_TAG_EMPTY(0) || ! IS_TAG_EMPTY(-1))
{
if(IS_TAG_EMPTY(0))
FPU_exception(FPU_EX_Stack_Underflow);
else
FPU_exception(FPU_EX_Stack_Overflow);
/* The masked response */
if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
}
return;
}
extern const floatx80 Const_1;
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 y = BX_READ_FPU_REG(0);
if (ftan(y, status) == -1)
{
FPU_PARTIAL_STATUS |= FPU_SW_C2;
return;
}
if (floatx80_is_nan(y))
{
if (! FPU_exception(status.float_exception_flags))
{
BX_WRITE_FPU_REG(y, 0);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(y, 0);
}
return;
}
if (! FPU_exception(status.float_exception_flags)) {
BX_WRITE_FPU_REG(y, 0);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(Const_1, 0);
}
}
/* D9 F3 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPATAN(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_stack_underflow(1, 1 /* pop_stack */);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 result = fpatan(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
if (! FPU_exception(status.float_exception_flags)) {
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_WRITE_FPU_REG(result, 0);
}
}
/* D9 F4 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FXTRACT(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0) || ! IS_TAG_EMPTY(-1))
{
if(IS_TAG_EMPTY(0))
FPU_exception(FPU_EX_Stack_Underflow);
else
FPU_exception(FPU_EX_Stack_Overflow);
/* The masked response */
if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
floatx80 a = BX_READ_FPU_REG(0);
floatx80 b = floatx80_extract(a, status);
if (! FPU_exception(status.float_exception_flags)) {
BX_WRITE_FPU_REG(b, 0); // exponent
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(a, 0); // fraction
}
}
/* D9 F5 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPREM1(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
clear_C2();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_stack_underflow(0);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
Bit64u quotient;
floatx80 a = BX_READ_FPU_REG(0);
floatx80 b = BX_READ_FPU_REG(1);
floatx80 result;
int flags = floatx80_ieee754_remainder(a, b, result, quotient, status);
if (! FPU_exception(status.float_exception_flags)) {
if (flags >= 0) {
int cc = 0;
if (flags) cc = FPU_SW_C2;
else {
if (quotient & 1) cc |= FPU_SW_C1;
if (quotient & 2) cc |= FPU_SW_C3;
if (quotient & 4) cc |= FPU_SW_C0;
}
setcc(cc);
}
BX_WRITE_FPU_REG(result, 0);
}
}
/* D9 F8 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPREM(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
clear_C2();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_stack_underflow(0);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
Bit64u quotient;
floatx80 a = BX_READ_FPU_REG(0);
floatx80 b = BX_READ_FPU_REG(1);
floatx80 result;
int flags = floatx80_remainder(a, b, result, quotient, status);
if (! FPU_exception(status.float_exception_flags)) {
if (flags >= 0) {
int cc = 0;
if (flags) cc = FPU_SW_C2;
else {
if (quotient & 1) cc |= FPU_SW_C1;
if (quotient & 2) cc |= FPU_SW_C3;
if (quotient & 4) cc |= FPU_SW_C0;
}
setcc(cc);
}
BX_WRITE_FPU_REG(result, 0);
}
}
/* D9 F9 */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FYL2XP1(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_stack_underflow(1, 1 /* pop_stack */);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 result = fyl2xp1(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
if (! FPU_exception(status.float_exception_flags)) {
BX_CPU_THIS_PTR the_i387.FPU_pop();
BX_WRITE_FPU_REG(result, 0);
}
}
/* D9 FB */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSINCOS(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
clear_C2();
if (IS_TAG_EMPTY(0) || ! IS_TAG_EMPTY(-1))
{
if(IS_TAG_EMPTY(0))
FPU_exception(FPU_EX_Stack_Underflow);
else
FPU_exception(FPU_EX_Stack_Overflow);
/* The masked response */
if (BX_CPU_THIS_PTR the_i387.is_IA_masked())
{
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(floatx80_default_nan, 0);
}
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 y = BX_READ_FPU_REG(0);
floatx80 sin_y, cos_y;
if (fsincos(y, &sin_y, &cos_y, status) == -1)
{
FPU_PARTIAL_STATUS |= FPU_SW_C2;
return;
}
if (! FPU_exception(status.float_exception_flags)) {
BX_WRITE_FPU_REG(sin_y, 0);
BX_CPU_THIS_PTR the_i387.FPU_push();
BX_WRITE_FPU_REG(cos_y, 0);
}
}
/* D9 FD */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSCALE(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
if (IS_TAG_EMPTY(0) || IS_TAG_EMPTY(1))
{
FPU_stack_underflow(0);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word());
floatx80 result = floatx80_scale(BX_READ_FPU_REG(0), BX_READ_FPU_REG(1), status);
if (! FPU_exception(status.float_exception_flags))
BX_WRITE_FPU_REG(result, 0);
}
/* D9 FE */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FSIN(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
clear_C2();
if (IS_TAG_EMPTY(0)) {
FPU_stack_underflow(0);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 y = BX_READ_FPU_REG(0);
if (fsin(y, status) == -1)
{
FPU_PARTIAL_STATUS |= FPU_SW_C2;
return;
}
if (! FPU_exception(status.float_exception_flags))
BX_WRITE_FPU_REG(y, 0);
}
/* D9 FF */
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FCOS(bxInstruction_c *i)
{
BX_CPU_THIS_PTR prepareFPU(i);
BX_CPU_THIS_PTR FPU_update_last_instruction(i);
clear_C1();
clear_C2();
if (IS_TAG_EMPTY(0)) {
FPU_stack_underflow(0);
return;
}
float_status_t status =
FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word() | FPU_PR_80_BITS);
floatx80 y = BX_READ_FPU_REG(0);
if (fcos(y, status) == -1)
{
FPU_PARTIAL_STATUS |= FPU_SW_C2;
return;
}
if (! FPU_exception(status.float_exception_flags))
BX_WRITE_FPU_REG(y, 0);
}
#endif

431
simulators/bochs/fpu/fsincos.cc Executable file
View File

@ -0,0 +1,431 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define FLOAT128
#define USE_estimateDiv128To64
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
#include "fpu_constant.h"
static const floatx80 floatx80_one = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
/* reduce trigonometric function argument using 128-bit precision
M_PI approximation */
static Bit64u argument_reduction_kernel(Bit64u aSig0, int Exp, Bit64u *zSig0, Bit64u *zSig1)
{
Bit64u term0, term1, term2;
Bit64u aSig1 = 0;
shortShift128Left(aSig1, aSig0, Exp, &aSig1, &aSig0);
Bit64u q = estimateDiv128To64(aSig1, aSig0, FLOAT_PI_HI);
mul128By64To192(FLOAT_PI_HI, FLOAT_PI_LO, q, &term0, &term1, &term2);
sub128(aSig1, aSig0, term0, term1, zSig1, zSig0);
while ((Bit64s)(*zSig1) < 0) {
--q;
add192(*zSig1, *zSig0, term2, 0, FLOAT_PI_HI, FLOAT_PI_LO, zSig1, zSig0, &term2);
}
*zSig1 = term2;
return q;
}
static int reduce_trig_arg(int expDiff, int &zSign, Bit64u &aSig0, Bit64u &aSig1)
{
Bit64u term0, term1, q = 0;
if (expDiff < 0) {
shift128Right(aSig0, 0, 1, &aSig0, &aSig1);
expDiff = 0;
}
if (expDiff > 0) {
q = argument_reduction_kernel(aSig0, expDiff, &aSig0, &aSig1);
}
else {
if (FLOAT_PI_HI <= aSig0) {
aSig0 -= FLOAT_PI_HI;
q = 1;
}
}
shift128Right(FLOAT_PI_HI, FLOAT_PI_LO, 1, &term0, &term1);
if (! lt128(aSig0, aSig1, term0, term1))
{
int lt = lt128(term0, term1, aSig0, aSig1);
int eq = eq128(aSig0, aSig1, term0, term1);
if ((eq && (q & 1)) || lt) {
zSign = !zSign;
++q;
}
if (lt) sub128(FLOAT_PI_HI, FLOAT_PI_LO, aSig0, aSig1, &aSig0, &aSig1);
}
return (int)(q & 3);
}
#define SIN_ARR_SIZE 11
#define COS_ARR_SIZE 11
static float128 sin_arr[SIN_ARR_SIZE] =
{
PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */
PACK_FLOAT_128(0xbffc555555555555, 0x5555555555555555), /* 3 */
PACK_FLOAT_128(0x3ff8111111111111, 0x1111111111111111), /* 5 */
PACK_FLOAT_128(0xbff2a01a01a01a01, 0xa01a01a01a01a01a), /* 7 */
PACK_FLOAT_128(0x3fec71de3a556c73, 0x38faac1c88e50017), /* 9 */
PACK_FLOAT_128(0xbfe5ae64567f544e, 0x38fe747e4b837dc7), /* 11 */
PACK_FLOAT_128(0x3fde6124613a86d0, 0x97ca38331d23af68), /* 13 */
PACK_FLOAT_128(0xbfd6ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 15 */
PACK_FLOAT_128(0x3fce952c77030ad4, 0xa6b2605197771b00), /* 17 */
PACK_FLOAT_128(0xbfc62f49b4681415, 0x724ca1ec3b7b9675), /* 19 */
PACK_FLOAT_128(0x3fbd71b8ef6dcf57, 0x18bef146fcee6e45) /* 21 */
};
static float128 cos_arr[COS_ARR_SIZE] =
{
PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 0 */
PACK_FLOAT_128(0xbffe000000000000, 0x0000000000000000), /* 2 */
PACK_FLOAT_128(0x3ffa555555555555, 0x5555555555555555), /* 4 */
PACK_FLOAT_128(0xbff56c16c16c16c1, 0x6c16c16c16c16c17), /* 6 */
PACK_FLOAT_128(0x3fefa01a01a01a01, 0xa01a01a01a01a01a), /* 8 */
PACK_FLOAT_128(0xbfe927e4fb7789f5, 0xc72ef016d3ea6679), /* 10 */
PACK_FLOAT_128(0x3fe21eed8eff8d89, 0x7b544da987acfe85), /* 12 */
PACK_FLOAT_128(0xbfda93974a8c07c9, 0xd20badf145dfa3e5), /* 14 */
PACK_FLOAT_128(0x3fd2ae7f3e733b81, 0xf11d8656b0ee8cb0), /* 16 */
PACK_FLOAT_128(0xbfca6827863b97d9, 0x77bb004886a2c2ab), /* 18 */
PACK_FLOAT_128(0x3fc1e542ba402022, 0x507a9cad2bf8f0bb) /* 20 */
};
extern float128 OddPoly (float128 x, float128 *arr, unsigned n, float_status_t &status);
/* 0 <= x <= pi/4 */
BX_CPP_INLINE float128 poly_sin(float128 x, float_status_t &status)
{
// 3 5 7 9 11 13 15
// x x x x x x x
// sin (x) ~ x - --- + --- - --- + --- - ---- + ---- - ---- =
// 3! 5! 7! 9! 11! 13! 15!
//
// 2 4 6 8 10 12 14
// x x x x x x x
// = x * [ 1 - --- + --- - --- + --- - ---- + ---- - ---- ] =
// 3! 5! 7! 9! 11! 13! 15!
//
// 3 3
// -- 4k -- 4k+2
// p(x) = > C * x > 0 q(x) = > C * x < 0
// -- 2k -- 2k+1
// k=0 k=0
//
// 2
// sin(x) ~ x * [ p(x) + x * q(x) ]
//
return OddPoly(x, sin_arr, SIN_ARR_SIZE, status);
}
extern float128 EvenPoly(float128 x, float128 *arr, unsigned n, float_status_t &status);
/* 0 <= x <= pi/4 */
BX_CPP_INLINE float128 poly_cos(float128 x, float_status_t &status)
{
// 2 4 6 8 10 12 14
// x x x x x x x
// cos (x) ~ 1 - --- + --- - --- + --- - ---- + ---- - ----
// 2! 4! 6! 8! 10! 12! 14!
//
// 3 3
// -- 4k -- 4k+2
// p(x) = > C * x > 0 q(x) = > C * x < 0
// -- 2k -- 2k+1
// k=0 k=0
//
// 2
// cos(x) ~ [ p(x) + x * q(x) ]
//
return EvenPoly(x, cos_arr, COS_ARR_SIZE, status);
}
BX_CPP_INLINE void sincos_invalid(floatx80 *sin_a, floatx80 *cos_a, floatx80 a)
{
if (sin_a) *sin_a = a;
if (cos_a) *cos_a = a;
}
BX_CPP_INLINE void sincos_tiny_argument(floatx80 *sin_a, floatx80 *cos_a, floatx80 a)
{
if (sin_a) *sin_a = a;
if (cos_a) *cos_a = floatx80_one;
}
static floatx80 sincos_approximation(int neg, float128 r, Bit64u quotient, float_status_t &status)
{
if (quotient & 0x1) {
r = poly_cos(r, status);
neg = 0;
} else {
r = poly_sin(r, status);
}
floatx80 result = float128_to_floatx80(r, status);
if (quotient & 0x2)
neg = ! neg;
if (neg)
floatx80_chs(result);
return result;
}
// =================================================
// FSINCOS Compute sin(x) and cos(x)
// =================================================
//
// Uses the following identities:
// ----------------------------------------------------------
//
// sin(-x) = -sin(x)
// cos(-x) = cos(x)
//
// sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y)
// cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y)
//
// sin(x+ pi/2) = cos(x)
// sin(x+ pi) = -sin(x)
// sin(x+3pi/2) = -cos(x)
// sin(x+2pi) = sin(x)
//
int fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a, float_status_t &status)
{
Bit64u aSig0, aSig1 = 0;
Bit32s aExp, zExp, expDiff;
int aSign, zSign;
int q = 0;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a)) {
goto invalid;
}
aSig0 = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
aSign = extractFloatx80Sign(a);
/* invalid argument */
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig0<<1)) {
sincos_invalid(sin_a, cos_a, propagateFloatx80NaN(a, status));
return 0;
}
invalid:
float_raise(status, float_flag_invalid);
sincos_invalid(sin_a, cos_a, floatx80_default_nan);
return 0;
}
if (aExp == 0) {
if (aSig0 == 0) {
sincos_tiny_argument(sin_a, cos_a, a);
return 0;
}
float_raise(status, float_flag_denormal);
/* handle pseudo denormals */
if (! (aSig0 & BX_CONST64(0x8000000000000000)))
{
float_raise(status, float_flag_inexact);
if (sin_a)
float_raise(status, float_flag_underflow);
sincos_tiny_argument(sin_a, cos_a, a);
return 0;
}
normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
}
zSign = aSign;
zExp = EXP_BIAS;
expDiff = aExp - zExp;
/* argument is out-of-range */
if (expDiff >= 63)
return -1;
float_raise(status, float_flag_inexact);
if (expDiff < -1) { // doesn't require reduction
if (expDiff <= -68) {
a = packFloatx80(aSign, aExp, aSig0);
sincos_tiny_argument(sin_a, cos_a, a);
return 0;
}
zExp = aExp;
}
else {
q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1);
}
/* **************************** */
/* argument reduction completed */
/* **************************** */
/* using float128 for approximation */
float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1, status);
if (aSign) q = -q;
if (sin_a) *sin_a = sincos_approximation(zSign, r, q, status);
if (cos_a) *cos_a = sincos_approximation(zSign, r, q+1, status);
return 0;
}
int fsin(floatx80 &a, float_status_t &status)
{
return fsincos(a, &a, 0, status);
}
int fcos(floatx80 &a, float_status_t &status)
{
return fsincos(a, 0, &a, status);
}
// =================================================
// FPTAN Compute tan(x)
// =================================================
//
// Uses the following identities:
//
// 1. ----------------------------------------------------------
//
// sin(-x) = -sin(x)
// cos(-x) = cos(x)
//
// sin(x+y) = sin(x)*cos(y)+cos(x)*sin(y)
// cos(x+y) = sin(x)*sin(y)+cos(x)*cos(y)
//
// sin(x+ pi/2) = cos(x)
// sin(x+ pi) = -sin(x)
// sin(x+3pi/2) = -cos(x)
// sin(x+2pi) = sin(x)
//
// 2. ----------------------------------------------------------
//
// sin(x)
// tan(x) = ------
// cos(x)
//
int ftan(floatx80 &a, float_status_t &status)
{
Bit64u aSig0, aSig1 = 0;
Bit32s aExp, zExp, expDiff;
int aSign, zSign;
int q = 0;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a)) {
goto invalid;
}
aSig0 = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
aSign = extractFloatx80Sign(a);
/* invalid argument */
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig0<<1))
{
a = propagateFloatx80NaN(a, status);
return 0;
}
invalid:
float_raise(status, float_flag_invalid);
a = floatx80_default_nan;
return 0;
}
if (aExp == 0) {
if (aSig0 == 0) return 0;
float_raise(status, float_flag_denormal);
/* handle pseudo denormals */
if (! (aSig0 & BX_CONST64(0x8000000000000000)))
{
float_raise(status, float_flag_inexact | float_flag_underflow);
return 0;
}
normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0);
}
zSign = aSign;
zExp = EXP_BIAS;
expDiff = aExp - zExp;
/* argument is out-of-range */
if (expDiff >= 63)
return -1;
float_raise(status, float_flag_inexact);
if (expDiff < -1) { // doesn't require reduction
if (expDiff <= -68) {
a = packFloatx80(aSign, aExp, aSig0);
return 0;
}
zExp = aExp;
}
else {
q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1);
}
/* **************************** */
/* argument reduction completed */
/* **************************** */
/* using float128 for approximation */
float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1, status);
float128 sin_r = poly_sin(r, status);
float128 cos_r = poly_cos(r, status);
if (q & 0x1) {
r = float128_div(cos_r, sin_r, status);
zSign = ! zSign;
} else {
r = float128_div(sin_r, cos_r, status);
}
a = float128_to_floatx80(r, status);
if (zSign)
floatx80_chs(a);
return 0;
}

353
simulators/bochs/fpu/fyl2x.cc Executable file
View File

@ -0,0 +1,353 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define FLOAT128
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
#include "fpu_constant.h"
static const floatx80 floatx80_one =
packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000));
static const float128 float128_one =
packFloat128(BX_CONST64(0x3fff000000000000), BX_CONST64(0x0000000000000000));
static const float128 float128_two =
packFloat128(BX_CONST64(0x4000000000000000), BX_CONST64(0x0000000000000000));
static const float128 float128_ln2inv2 =
packFloat128(BX_CONST64(0x400071547652b82f), BX_CONST64(0xe1777d0ffda0d23a));
#define SQRT2_HALF_SIG BX_CONST64(0xb504f333f9de6484)
extern float128 OddPoly(float128 x, float128 *arr, unsigned n, float_status_t &status);
#define L2_ARR_SIZE 9
static float128 ln_arr[L2_ARR_SIZE] =
{
PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */
PACK_FLOAT_128(0x3ffd555555555555, 0x5555555555555555), /* 3 */
PACK_FLOAT_128(0x3ffc999999999999, 0x999999999999999a), /* 5 */
PACK_FLOAT_128(0x3ffc249249249249, 0x2492492492492492), /* 7 */
PACK_FLOAT_128(0x3ffbc71c71c71c71, 0xc71c71c71c71c71c), /* 9 */
PACK_FLOAT_128(0x3ffb745d1745d174, 0x5d1745d1745d1746), /* 11 */
PACK_FLOAT_128(0x3ffb3b13b13b13b1, 0x3b13b13b13b13b14), /* 13 */
PACK_FLOAT_128(0x3ffb111111111111, 0x1111111111111111), /* 15 */
PACK_FLOAT_128(0x3ffae1e1e1e1e1e1, 0xe1e1e1e1e1e1e1e2) /* 17 */
};
static float128 poly_ln(float128 x1, float_status_t &status)
{
/*
//
// 3 5 7 9 11 13 15
// 1+u u u u u u u u
// 1/2 ln --- ~ u + --- + --- + --- + --- + ---- + ---- + ---- =
// 1-u 3 5 7 9 11 13 15
//
// 2 4 6 8 10 12 14
// u u u u u u u
// = u * [ 1 + --- + --- + --- + --- + ---- + ---- + ---- ] =
// 3 5 7 9 11 13 15
//
// 3 3
// -- 4k -- 4k+2
// p(u) = > C * u q(u) = > C * u
// -- 2k -- 2k+1
// k=0 k=0
//
// 1+u 2
// 1/2 ln --- ~ u * [ p(u) + u * q(u) ]
// 1-u
//
*/
return OddPoly(x1, ln_arr, L2_ARR_SIZE, status);
}
/* required sqrt(2)/2 < x < sqrt(2) */
static float128 poly_l2(float128 x, float_status_t &status)
{
/* using float128 for approximation */
float128 x_p1 = float128_add(x, float128_one, status);
float128 x_m1 = float128_sub(x, float128_one, status);
x = float128_div(x_m1, x_p1, status);
x = poly_ln(x, status);
x = float128_mul(x, float128_ln2inv2, status);
return x;
}
static float128 poly_l2p1(float128 x, float_status_t &status)
{
/* using float128 for approximation */
float128 x_p2 = float128_add(x, float128_two, status);
x = float128_div(x, x_p2, status);
x = poly_ln(x, status);
x = float128_mul(x, float128_ln2inv2, status);
return x;
}
// =================================================
// FYL2X Compute y * log (x)
// 2
// =================================================
//
// Uses the following identities:
//
// 1. ----------------------------------------------------------
// ln(x)
// log (x) = -------, ln (x*y) = ln(x) + ln(y)
// 2 ln(2)
//
// 2. ----------------------------------------------------------
// 1+u x-1
// ln (x) = ln -----, when u = -----
// 1-u x+1
//
// 3. ----------------------------------------------------------
// 3 5 7 2n+1
// 1+u u u u u
// ln ----- = 2 [ u + --- + --- + --- + ... + ------ + ... ]
// 1-u 3 5 7 2n+1
//
floatx80 fyl2x(floatx80 a, floatx80 b, float_status_t &status)
{
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b)) {
invalid:
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
int aSign = extractFloatx80Sign(a);
Bit64u bSig = extractFloatx80Frac(b);
Bit32s bExp = extractFloatx80Exp(b);
int bSign = extractFloatx80Sign(b);
int zSign = bSign ^ 1;
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1)
|| ((bExp == 0x7FFF) && (Bit64u) (bSig<<1)))
{
return propagateFloatx80NaN(a, b, status);
}
if (aSign) goto invalid;
else {
if (bExp == 0) {
if (bSig == 0) goto invalid;
float_raise(status, float_flag_denormal);
}
return packFloatx80(bSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
}
if (bExp == 0x7FFF)
{
if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status);
if (aSign && (Bit64u)(aExp | aSig)) goto invalid;
if (aSig && (aExp == 0))
float_raise(status, float_flag_denormal);
if (aExp < 0x3FFF) {
return packFloatx80(zSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0x3FFF && ((Bit64u) (aSig<<1) == 0)) goto invalid;
return packFloatx80(bSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0) {
if (aSig == 0) {
if ((bExp | bSig) == 0) goto invalid;
float_raise(status, float_flag_divbyzero);
return packFloatx80(zSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aSign) goto invalid;
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
}
if (aSign) goto invalid;
if (bExp == 0) {
if (bSig == 0) {
if (aExp < 0x3FFF) return packFloatx80(zSign, 0, 0);
return packFloatx80(bSign, 0, 0);
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
if (aExp == 0x3FFF && ((Bit64u) (aSig<<1) == 0))
return packFloatx80(bSign, 0, 0);
float_raise(status, float_flag_inexact);
int ExpDiff = aExp - 0x3FFF;
aExp = 0;
if (aSig >= SQRT2_HALF_SIG) {
ExpDiff++;
aExp--;
}
/* ******************************** */
/* using float128 for approximation */
/* ******************************** */
Bit64u zSig0, zSig1;
shift128Right(aSig<<1, 0, 16, &zSig0, &zSig1);
float128 x = packFloat128(0, aExp+0x3FFF, zSig0, zSig1);
x = poly_l2(x, status);
x = float128_add(x, int64_to_float128((Bit64s) ExpDiff), status);
return floatx80_mul(b, x, status);
}
// =================================================
// FYL2XP1 Compute y * log (x + 1)
// 2
// =================================================
//
// Uses the following identities:
//
// 1. ----------------------------------------------------------
// ln(x)
// log (x) = -------
// 2 ln(2)
//
// 2. ----------------------------------------------------------
// 1+u x
// ln (x+1) = ln -----, when u = -----
// 1-u x+2
//
// 3. ----------------------------------------------------------
// 3 5 7 2n+1
// 1+u u u u u
// ln ----- = 2 [ u + --- + --- + --- + ... + ------ + ... ]
// 1-u 3 5 7 2n+1
//
floatx80 fyl2xp1(floatx80 a, floatx80 b, float_status_t &status)
{
Bit32s aExp, bExp;
Bit64u aSig, bSig, zSig0, zSig1, zSig2;
int aSign, bSign;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b)) {
invalid:
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
aSig = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
aSign = extractFloatx80Sign(a);
bSig = extractFloatx80Frac(b);
bExp = extractFloatx80Exp(b);
bSign = extractFloatx80Sign(b);
int zSign = aSign ^ bSign;
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1)
|| ((bExp == 0x7FFF) && (Bit64u) (bSig<<1)))
{
return propagateFloatx80NaN(a, b, status);
}
if (aSign) goto invalid;
else {
if (bExp == 0) {
if (bSig == 0) goto invalid;
float_raise(status, float_flag_denormal);
}
return packFloatx80(bSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
}
if (bExp == 0x7FFF)
{
if ((Bit64u) (bSig<<1))
return propagateFloatx80NaN(a, b, status);
if (aExp == 0) {
if (aSig == 0) goto invalid;
float_raise(status, float_flag_denormal);
}
return packFloatx80(zSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0) {
if (aSig == 0) {
if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal);
return packFloatx80(zSign, 0, 0);
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
}
if (bExp == 0) {
if (bSig == 0) return packFloatx80(zSign, 0, 0);
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
float_raise(status, float_flag_inexact);
if (aSign && aExp >= 0x3FFF)
return a;
if (aExp >= 0x3FFC) // big argument
{
return fyl2x(floatx80_add(a, floatx80_one, status), b, status);
}
// handle tiny argument
if (aExp < EXP_BIAS-70)
{
// first order approximation, return (a*b)/ln(2)
Bit32s zExp = aExp + FLOAT_LN2INV_EXP - 0x3FFE;
mul128By64To192(FLOAT_LN2INV_HI, FLOAT_LN2INV_LO, aSig, &zSig0, &zSig1, &zSig2);
if (0 < (Bit64s) zSig0) {
shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1);
--zExp;
}
zExp = zExp + bExp - 0x3FFE;
mul128By64To192(zSig0, zSig1, bSig, &zSig0, &zSig1, &zSig2);
if (0 < (Bit64s) zSig0) {
shortShift128Left(zSig0, zSig1, 1, &zSig0, &zSig1);
--zExp;
}
return
roundAndPackFloatx80(80, aSign ^ bSign, zExp, zSig0, zSig1, status);
}
/* ******************************** */
/* using float128 for approximation */
/* ******************************** */
shift128Right(aSig<<1, 0, 16, &zSig0, &zSig1);
float128 x = packFloat128(aSign, aExp, zSig0, zSig1);
x = poly_l2p1(x, status);
return floatx80_mul(b, x, status);
}

105
simulators/bochs/fpu/poly.cc Executable file
View File

@ -0,0 +1,105 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define FLOAT128
#include <assert.h>
#include "softfloat.h"
// 2 3 4 n
// f(x) ~ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
// 0 1 2 3 4 n
//
// -- 2k -- 2k+1
// p(x) = > C * x q(x) = > C * x
// -- 2k -- 2k+1
//
// f(x) ~ [ p(x) + x * q(x) ]
//
float128 EvalPoly(float128 x, float128 *arr, unsigned n, float_status_t &status)
{
float128 x2 = float128_mul(x, x, status);
unsigned i;
assert(n > 1);
float128 r1 = arr[--n];
i = n;
while(i >= 2) {
r1 = float128_mul(r1, x2, status);
i -= 2;
r1 = float128_add(r1, arr[i], status);
}
if (i) r1 = float128_mul(r1, x, status);
float128 r2 = arr[--n];
i = n;
while(i >= 2) {
r2 = float128_mul(r2, x2, status);
i -= 2;
r2 = float128_add(r2, arr[i], status);
}
if (i) r2 = float128_mul(r2, x, status);
return float128_add(r1, r2, status);
}
// 2 4 6 8 2n
// f(x) ~ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
// 0 1 2 3 4 n
//
// -- 4k -- 4k+2
// p(x) = > C * x q(x) = > C * x
// -- 2k -- 2k+1
//
// 2
// f(x) ~ [ p(x) + x * q(x) ]
//
float128 EvenPoly(float128 x, float128 *arr, unsigned n, float_status_t &status)
{
return EvalPoly(float128_mul(x, x, status), arr, n, status);
}
// 3 5 7 9 2n+1
// f(x) ~ (C * x) + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
// 0 1 2 3 4 n
// 2 4 6 8 2n
// = x * [ C + (C * x) + (C * x) + (C * x) + (C * x) + ... + (C * x)
// 0 1 2 3 4 n
//
// -- 4k -- 4k+2
// p(x) = > C * x q(x) = > C * x
// -- 2k -- 2k+1
//
// 2
// f(x) ~ x * [ p(x) + x * q(x) ]
//
float128 OddPoly(float128 x, float128 *arr, unsigned n, float_status_t &status)
{
return float128_mul(x, EvenPoly(x, arr, n, status), status);
}

View File

@ -0,0 +1,496 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOAT_COMPARE_H_
#define _SOFTFLOAT_COMPARE_H_
#include "softfloat.h"
// ======= float32 ======= //
typedef int (*float32_compare_method)(float32, float32, float_status_t &status);
// 0x00
BX_CPP_INLINE int float32_eq_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_equal);
}
// 0x01
BX_CPP_INLINE int float32_lt_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_less);
}
// 0x02
BX_CPP_INLINE int float32_le_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x03
BX_CPP_INLINE int float32_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_unordered);
}
// 0x04
BX_CPP_INLINE int float32_neq_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_equal);
}
// 0x05
BX_CPP_INLINE int float32_nlt_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation != float_relation_less);
}
// 0x06
BX_CPP_INLINE int float32_nle_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x07
BX_CPP_INLINE int float32_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_unordered);
}
// 0x08
BX_CPP_INLINE int float32_eq_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x09
BX_CPP_INLINE int float32_nge_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x0a
BX_CPP_INLINE int float32_ngt_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation != float_relation_greater);
}
// 0x0b
BX_CPP_INLINE int float32_false_quiet(float32 a, float32 b, float_status_t &status)
{
float32_compare_quiet(a, b, status);
return 0;
}
// 0x0c
BX_CPP_INLINE int float32_neq_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x0d
BX_CPP_INLINE int float32_ge_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x0e
BX_CPP_INLINE int float32_gt_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_greater);
}
// 0x0f
BX_CPP_INLINE int float32_true_quiet(float32 a, float32 b, float_status_t &status)
{
float32_compare_quiet(a, b, status);
return 1;
}
// 0x10
BX_CPP_INLINE int float32_eq_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_equal);
}
// 0x11
BX_CPP_INLINE int float32_lt_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_less);
}
// 0x12
BX_CPP_INLINE int float32_le_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x13
BX_CPP_INLINE int float32_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_unordered);
}
// 0x14
BX_CPP_INLINE int float32_neq_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation != float_relation_equal);
}
// 0x15
BX_CPP_INLINE int float32_nlt_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_less);
}
// 0x16
BX_CPP_INLINE int float32_nle_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x17
BX_CPP_INLINE int float32_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation != float_relation_unordered);
}
// 0x18
BX_CPP_INLINE int float32_eq_unordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x19
BX_CPP_INLINE int float32_nge_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x1a
BX_CPP_INLINE int float32_ngt_unordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation != float_relation_greater);
}
// 0x1b
BX_CPP_INLINE int float32_false_signalling(float32 a, float32 b, float_status_t &status)
{
float32_compare(a, b, status);
return 0;
}
// 0x1c
BX_CPP_INLINE int float32_neq_ordered_signalling(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x1d
BX_CPP_INLINE int float32_ge_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x1e
BX_CPP_INLINE int float32_gt_ordered_quiet(float32 a, float32 b, float_status_t &status)
{
int relation = float32_compare_quiet(a, b, status);
return (relation == float_relation_greater);
}
// 0x1f
BX_CPP_INLINE int float32_true_signalling(float32 a, float32 b, float_status_t &status)
{
float32_compare(a, b, status);
return 1;
}
// ======= float64 ======= //
typedef int (*float64_compare_method)(float64, float64, float_status_t &status);
// 0x00
BX_CPP_INLINE int float64_eq_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_equal);
}
// 0x01
BX_CPP_INLINE int float64_lt_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_less);
}
// 0x02
BX_CPP_INLINE int float64_le_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x03
BX_CPP_INLINE int float64_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_unordered);
}
// 0x04
BX_CPP_INLINE int float64_neq_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_equal);
}
// 0x05
BX_CPP_INLINE int float64_nlt_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation != float_relation_less);
}
// 0x06
BX_CPP_INLINE int float64_nle_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x07
BX_CPP_INLINE int float64_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_unordered);
}
// 0x08
BX_CPP_INLINE int float64_eq_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x09
BX_CPP_INLINE int float64_nge_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x0a
BX_CPP_INLINE int float64_ngt_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation != float_relation_greater);
}
// 0x0b
BX_CPP_INLINE int float64_false_quiet(float64 a, float64 b, float_status_t &status)
{
float64_compare_quiet(a, b, status);
return 0;
}
// 0x0c
BX_CPP_INLINE int float64_neq_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x0d
BX_CPP_INLINE int float64_ge_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x0e
BX_CPP_INLINE int float64_gt_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_greater);
}
// 0x0f
BX_CPP_INLINE int float64_true_quiet(float64 a, float64 b, float_status_t &status)
{
float64_compare_quiet(a, b, status);
return 1;
}
// 0x10
BX_CPP_INLINE int float64_eq_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_equal);
}
// 0x11
BX_CPP_INLINE int float64_lt_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_less);
}
// 0x12
BX_CPP_INLINE int float64_le_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_equal);
}
// 0x13
BX_CPP_INLINE int float64_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_unordered);
}
// 0x14
BX_CPP_INLINE int float64_neq_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation != float_relation_equal);
}
// 0x15
BX_CPP_INLINE int float64_nlt_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_less);
}
// 0x16
BX_CPP_INLINE int float64_nle_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_less) && (relation != float_relation_equal);
}
// 0x17
BX_CPP_INLINE int float64_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation != float_relation_unordered);
}
// 0x18
BX_CPP_INLINE int float64_eq_unordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation == float_relation_equal) || (relation == float_relation_unordered);
}
// 0x19
BX_CPP_INLINE int float64_nge_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_less) || (relation == float_relation_unordered);
}
// 0x1a
BX_CPP_INLINE int float64_ngt_unordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation != float_relation_greater);
}
// 0x1b
BX_CPP_INLINE int float64_false_signalling(float64 a, float64 b, float_status_t &status)
{
float64_compare(a, b, status);
return 0;
}
// 0x1c
BX_CPP_INLINE int float64_neq_ordered_signalling(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare(a, b, status);
return (relation != float_relation_equal) && (relation != float_relation_unordered);
}
// 0x1d
BX_CPP_INLINE int float64_ge_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_greater) || (relation == float_relation_equal);
}
// 0x1e
BX_CPP_INLINE int float64_gt_ordered_quiet(float64 a, float64 b, float_status_t &status)
{
int relation = float64_compare_quiet(a, b, status);
return (relation == float_relation_greater);
}
// 0x1f
BX_CPP_INLINE int float64_true_signalling(float64 a, float64 b, float_status_t &status)
{
float64_compare(a, b, status);
return 1;
}
#endif

View File

@ -0,0 +1,650 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal notice) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOAT_MACROS_H_
#define _SOFTFLOAT_MACROS_H_
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 32, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32u shift32RightJamming(Bit32u a, int count)
{
Bit32u z;
if (count == 0) {
z = a;
}
else if (count < 32) {
z = (a>>count) | ((a<<((-count) & 31)) != 0);
}
else {
z = (a != 0);
}
return z;
}
/*----------------------------------------------------------------------------
| Shifts `a' right by the number of bits given in `count'. If any nonzero
| bits are shifted off, they are ``jammed'' into the least significant bit of
| the result by setting the least significant bit to 1. The value of `count'
| can be arbitrarily large; in particular, if `count' is greater than 64, the
| result will be either 0 or 1, depending on whether `a' is zero or nonzero.
| The result is stored in the location pointed to by `zPtr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u shift64RightJamming(Bit64u a, int count)
{
Bit64u z;
if (count == 0) {
z = a;
}
else if (count < 64) {
z = (a>>count) | ((a << ((-count) & 63)) != 0);
}
else {
z = (a != 0);
}
return z;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64
| _plus_ the number of bits given in `count'. The shifted result is at most
| 64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The
| bits shifted off form a second 64-bit result as follows: The _last_ bit
| shifted off is the most-significant bit of the extra result, and the other
| 63 bits of the extra result are all zero if and only if _all_but_the_last_
| bits shifted off were all zero. This extra result is stored in the location
| pointed to by `z1Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0' and `a1' are considered to form
| a fixed-point value with binary point between `a0' and `a1'. This fixed-
| point value is shifted right by the number of bits given in `count', and
| the integer part of the result is returned at the location pointed to by
| `z0Ptr'. The fractional part of the result may be slightly corrupted as
| described above, and is returned at the location pointed to by `z1Ptr'.)
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
shift64ExtraRightJamming(
Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z0, z1;
int negCount = (-count) & 63;
if (count == 0) {
z1 = a1;
z0 = a0;
}
else if (count < 64) {
z1 = (a0<<negCount) | (a1 != 0);
z0 = a0>>count;
}
else {
if (count == 64) {
z1 = a0 | (a1 != 0);
}
else {
z1 = ((a0 | a1) != 0);
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit
| value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so
| any carry out is lost. The result is broken into two 64-bit pieces which
| are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
add128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z1 = a1 + b1;
*z1Ptr = z1;
*z0Ptr = a0 + b0 + (z1 < a1);
}
/*----------------------------------------------------------------------------
| Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the
| 128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo
| 2^128, so any borrow out (carry out) is lost. The result is broken into two
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr' and
| `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
sub128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
*z1Ptr = a1 - b1;
*z0Ptr = a0 - b0 - (a1 < b1);
}
/*----------------------------------------------------------------------------
| Multiplies `a' by `b' to obtain a 128-bit product. The product is broken
| into two 64-bit pieces which are stored at the locations pointed to by
| `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void mul64To128(Bit64u a, Bit64u b, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit32u aHigh, aLow, bHigh, bLow;
Bit64u z0, zMiddleA, zMiddleB, z1;
aLow = (Bit32u) a;
aHigh = (Bit32u)(a>>32);
bLow = (Bit32u) b;
bHigh = (Bit32u)(b>>32);
z1 = ((Bit64u) aLow) * bLow;
zMiddleA = ((Bit64u) aLow) * bHigh;
zMiddleB = ((Bit64u) aHigh) * bLow;
z0 = ((Bit64u) aHigh) * bHigh;
zMiddleA += zMiddleB;
z0 += (((Bit64u) (zMiddleA < zMiddleB))<<32) + (zMiddleA>>32);
zMiddleA <<= 32;
z1 += zMiddleA;
z0 += (z1 < zMiddleA);
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns an approximation to the 64-bit integer quotient obtained by dividing
| `b' into the 128-bit value formed by concatenating `a0' and `a1'. The
| divisor `b' must be at least 2^63. If q is the exact quotient truncated
| toward zero, the approximation returned lies between q and q + 2 inclusive.
| If the exact quotient q is larger than 64 bits, the maximum positive 64-bit
| unsigned integer is returned.
*----------------------------------------------------------------------------*/
#ifdef USE_estimateDiv128To64
static Bit64u estimateDiv128To64(Bit64u a0, Bit64u a1, Bit64u b)
{
Bit64u b0, b1;
Bit64u rem0, rem1, term0, term1;
Bit64u z;
if (b <= a0) return BX_CONST64(0xFFFFFFFFFFFFFFFF);
b0 = b>>32;
z = (b0<<32 <= a0) ? BX_CONST64(0xFFFFFFFF00000000) : (a0 / b0)<<32;
mul64To128(b, z, &term0, &term1);
sub128(a0, a1, term0, term1, &rem0, &rem1);
while (((Bit64s) rem0) < 0) {
z -= BX_CONST64(0x100000000);
b1 = b<<32;
add128(rem0, rem1, b0, b1, &rem0, &rem1);
}
rem0 = (rem0<<32) | (rem1>>32);
z |= (b0<<32 <= rem0) ? 0xFFFFFFFF : rem0 / b0;
return z;
}
#endif
/*----------------------------------------------------------------------------
| Returns an approximation to the square root of the 32-bit significand given
| by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of
| `aExp' (the least significant bit) is 1, the integer returned approximates
| 2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp'
| is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either
| case, the approximation returned lies strictly within +/-2 of the exact
| value.
*----------------------------------------------------------------------------*/
#ifdef USE_estimateSqrt32
static Bit32u estimateSqrt32(Bit16s aExp, Bit32u a)
{
static const Bit16u sqrtOddAdjustments[] = {
0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0,
0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67
};
static const Bit16u sqrtEvenAdjustments[] = {
0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E,
0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002
};
Bit32u z;
int index = (a>>27) & 15;
if (aExp & 1) {
z = 0x4000 + (a>>17) - sqrtOddAdjustments[index];
z = ((a / z)<<14) + (z<<15);
a >>= 1;
}
else {
z = 0x8000 + (a>>17) - sqrtEvenAdjustments[index];
z = a / z + z;
z = (0x20000 <= z) ? 0xFFFF8000 : (z<<15);
if (z <= a) return (Bit32u) (((Bit32s) a)>>1);
}
return ((Bit32u) ((((Bit64u) a)<<31) / z)) + (z>>1);
}
#endif
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 32 is returned.
*----------------------------------------------------------------------------*/
static int countLeadingZeros32(Bit32u a)
{
static const int countLeadingZerosHigh[] = {
8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
int shiftCount = 0;
if (a < 0x10000) {
shiftCount += 16;
a <<= 16;
}
if (a < 0x1000000) {
shiftCount += 8;
a <<= 8;
}
shiftCount += countLeadingZerosHigh[ a>>24 ];
return shiftCount;
}
/*----------------------------------------------------------------------------
| Returns the number of leading 0 bits before the most-significant 1 bit of
| `a'. If `a' is zero, 64 is returned.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int countLeadingZeros64(Bit64u a)
{
int shiftCount = 0;
if (a < ((Bit64u) 1)<<32) {
shiftCount += 32;
}
else {
a >>= 32;
}
shiftCount += countLeadingZeros32((int)(a));
return shiftCount;
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' can be arbitrarily large; in particular, if `count' is greater
| than 128, the result will be 0. The result is broken into two 64-bit pieces
| which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
shift128Right(Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z0, z1;
int negCount = (-count) & 63;
if (count == 0) {
z1 = a1;
z0 = a0;
}
else if (count < 64) {
z1 = (a0<<negCount) | (a1>>count);
z0 = a0>>count;
}
else {
z1 = (count < 64) ? (a0>>(count & 63)) : 0;
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the
| number of bits given in `count'. If any nonzero bits are shifted off, they
| are ``jammed'' into the least significant bit of the result by setting the
| least significant bit to 1. The value of `count' can be arbitrarily large;
| in particular, if `count' is greater than 128, the result will be either
| 0 or 1, depending on whether the concatenation of `a0' and `a1' is zero or
| nonzero. The result is broken into two 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
shift128RightJamming(
Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
Bit64u z0, z1;
int negCount = (-count) & 63;
if (count == 0) {
z1 = a1;
z0 = a0;
}
else if (count < 64) {
z1 = (a0<<negCount) | (a1>>count) | ((a1<<negCount) != 0);
z0 = a0>>count;
}
else {
if (count == 64) {
z1 = a0 | (a1 != 0);
}
else if (count < 128) {
z1 = (a0>>(count & 63)) | (((a0<<negCount) | a1) != 0);
}
else {
z1 = ((a0 | a1) != 0);
}
z0 = 0;
}
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the
| number of bits given in `count'. Any bits shifted off are lost. The value
| of `count' must be less than 64. The result is broken into two 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void
shortShift128Left(
Bit64u a0, Bit64u a1, int count, Bit64u *z0Ptr, Bit64u *z1Ptr)
{
*z1Ptr = a1<<count;
*z0Ptr = (count == 0) ? a0 : (a0<<count) | (a1>>((-count) & 63));
}
/*----------------------------------------------------------------------------
| Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the
| 192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is
| modulo 2^192, so any carry out is lost. The result is broken into three
| 64-bit pieces which are stored at the locations pointed to by `z0Ptr',
| `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void add192(
Bit64u a0,
Bit64u a1,
Bit64u a2,
Bit64u b0,
Bit64u b1,
Bit64u b2,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2;
unsigned carry0, carry1;
z2 = a2 + b2;
carry1 = (z2 < a2);
z1 = a1 + b1;
carry0 = (z1 < a1);
z0 = a0 + b0;
z1 += carry1;
z0 += (z1 < carry1);
z0 += carry0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2'
| from the 192-bit value formed by concatenating `a0', `a1', and `a2'.
| Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The
| result is broken into three 64-bit pieces which are stored at the locations
| pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void sub192(
Bit64u a0,
Bit64u a1,
Bit64u a2,
Bit64u b0,
Bit64u b1,
Bit64u b2,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2;
unsigned borrow0, borrow1;
z2 = a2 - b2;
borrow1 = (a2 < b2);
z1 = a1 - b1;
borrow0 = (a1 < b1);
z0 = a0 - b0;
z0 -= (z1 < borrow1);
z1 -= borrow1;
z0 -= borrow0;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1'
| is equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int eq128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1)
{
return (a0 == b0) && (a1 == b1);
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than or equal to the 128-bit value formed by concatenating `b0' and `b1'.
| Otherwise, returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int le128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1)
{
return (a0 < b0) || ((a0 == b0) && (a1 <= b1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less
| than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise,
| returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int lt128(Bit64u a0, Bit64u a1, Bit64u b0, Bit64u b1)
{
return (a0 < b0) || ((a0 == b0) && (a1 < b1));
}
#endif /* FLOATX80 */
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' by
| `b' to obtain a 192-bit product. The product is broken into three 64-bit
| pieces which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and
| `z2Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void mul128By64To192(
Bit64u a0,
Bit64u a1,
Bit64u b,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2, more1;
mul64To128(a1, b, &z1, &z2);
mul64To128(a0, b, &z0, &more1);
add128(z0, more1, 0, z1, &z0, &z1);
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the
| 128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit
| product. The product is broken into four 64-bit pieces which are stored at
| the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void mul128To256(
Bit64u a0,
Bit64u a1,
Bit64u b0,
Bit64u b1,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr,
Bit64u *z3Ptr
)
{
Bit64u z0, z1, z2, z3;
Bit64u more1, more2;
mul64To128(a1, b1, &z2, &z3);
mul64To128(a1, b0, &z1, &more2);
add128(z1, more2, 0, z2, &z1, &z2);
mul64To128(a0, b0, &z0, &more1);
add128(z0, more1, 0, z1, &z0, &z1);
mul64To128(a0, b1, &more1, &more2);
add128(more1, more2, 0, z2, &more1, &z2);
add128(z0, z1, 0, more1, &z0, &z1);
*z3Ptr = z3;
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
/*----------------------------------------------------------------------------
| Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right
| by 64 _plus_ the number of bits given in `count'. The shifted result is
| at most 128 nonzero bits; these are broken into two 64-bit pieces which are
| stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted
| off form a third 64-bit result as follows: The _last_ bit shifted off is
| the most-significant bit of the extra result, and the other 63 bits of the
| extra result are all zero if and only if _all_but_the_last_ bits shifted off
| were all zero. This extra result is stored in the location pointed to by
| `z2Ptr'. The value of `count' can be arbitrarily large.
| (This routine makes more sense if `a0', `a1', and `a2' are considered
| to form a fixed-point value with binary point between `a1' and `a2'. This
| fixed-point value is shifted right by the number of bits given in `count',
| and the integer part of the result is returned at the locations pointed to
| by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly
| corrupted as described above, and is returned at the location pointed to by
| `z2Ptr'.)
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void shift128ExtraRightJamming(
Bit64u a0,
Bit64u a1,
Bit64u a2,
int count,
Bit64u *z0Ptr,
Bit64u *z1Ptr,
Bit64u *z2Ptr
)
{
Bit64u z0, z1, z2;
int negCount = (-count) & 63;
if (count == 0) {
z2 = a2;
z1 = a1;
z0 = a0;
}
else {
if (count < 64) {
z2 = a1<<negCount;
z1 = (a0<<negCount) | (a1>>count);
z0 = a0>>count;
}
else {
if (count == 64) {
z2 = a1;
z1 = a0;
}
else {
a2 |= a1;
if (count < 128) {
z2 = a0<<negCount;
z1 = a0>>(count & 63);
}
else {
z2 = (count == 128) ? a0 : (a0 != 0);
z1 = 0;
}
}
z0 = 0;
}
z2 |= (a2 != 0);
}
*z2Ptr = z2;
*z1Ptr = z1;
*z0Ptr = z0;
}
#endif /* FLOAT128 */
#endif

View File

@ -0,0 +1,730 @@
/*============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#define FLOAT128
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloat.h"
#include "softfloat-round-pack.h"
/*----------------------------------------------------------------------------
| Primitive arithmetic functions, including multi-word arithmetic, and
| division and square root approximations. (Can be specialized to target
| if desired).
*----------------------------------------------------------------------------*/
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| Functions and definitions to determine: (1) whether tininess for underflow
| is detected before or after rounding by default, (2) what (if anything)
| happens when exceptions are raised, (3) how signaling NaNs are distinguished
| from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
| are propagated from function inputs to output. These details are target-
| specific.
*----------------------------------------------------------------------------*/
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
| and 7, and returns the properly rounded 32-bit integer corresponding to the
| input. If `zSign' is 1, the input is negated before being converted to an
| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
| is simply rounded to an integer, with the inexact exception raised if the
| input cannot be represented exactly as an integer. However, if the fixed-
| point input is too large, the invalid exception is raised and the integer
| indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit32s roundAndPackInt32(int zSign, Bit64u exactAbsZ, float_status_t &status)
{
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
int roundIncrement = 0x40;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = 0x7F;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
int roundBits = (int)(exactAbsZ & 0x7F);
Bit64u absZ = (exactAbsZ + roundIncrement)>>7;
absZ &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
Bit32s z = (Bit32s) absZ;
if (zSign) z = -z;
if ((absZ>>32) || (z && ((z < 0) ^ zSign))) {
float_raise(status, float_flag_invalid);
return (Bit32s)(int32_indefinite);
}
if (roundBits) {
float_raise(status, float_flag_inexact);
if ((absZ << 7) > exactAbsZ)
set_float_rounding_up(status);
}
return z;
}
/*----------------------------------------------------------------------------
| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
| `absZ1', with binary point between bits 63 and 64 (between the input words),
| and returns the properly rounded 64-bit integer corresponding to the input.
| If `zSign' is 1, the input is negated before being converted to an integer.
| Ordinarily, the fixed-point input is simply rounded to an integer, with
| the inexact exception raised if the input cannot be represented exactly as
| an integer. However, if the fixed-point input is too large, the invalid
| exception is raised and the integer indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit64s roundAndPackInt64(int zSign, Bit64u absZ0, Bit64u absZ1, float_status_t &status)
{
Bit64s z;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
int increment = ((Bit64s) absZ1 < 0);
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) increment = 0;
else {
if (zSign) {
increment = (roundingMode == float_round_down) && absZ1;
}
else {
increment = (roundingMode == float_round_up) && absZ1;
}
}
}
Bit64u exactAbsZ0 = absZ0;
if (increment) {
++absZ0;
if (absZ0 == 0) goto overflow;
absZ0 &= ~(((Bit64u) (absZ1<<1) == 0) & roundNearestEven);
}
z = absZ0;
if (zSign) z = -z;
if (z && ((z < 0) ^ zSign)) {
overflow:
float_raise(status, float_flag_invalid);
return (Bit64s)(int64_indefinite);
}
if (absZ1) {
float_raise(status, float_flag_inexact);
if (absZ0 > exactAbsZ0)
set_float_rounding_up(status);
}
return z;
}
/*----------------------------------------------------------------------------
| Normalizes the subnormal single-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat32Subnormal(Bit32u aSig, Bit16s *zExpPtr, Bit32u *zSigPtr)
{
int shiftCount = countLeadingZeros32(aSig) - 8;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the single-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal single-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 30
| and 29, which is 7 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 roundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, float_status_t &status)
{
Bit32s roundIncrement, roundBits, roundMask;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
roundIncrement = 0x40;
roundMask = 0x7F;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = roundMask;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = zSig & roundMask;
if (0xFD <= (Bit16u) zExp) {
if ((0xFD < zExp)
|| ((zExp == 0xFD)
&& ((Bit32s) (zSig + roundIncrement) < 0)))
{
float_raise(status, float_flag_overflow);
if (roundBits || float_exception_masked(status, float_flag_overflow)) {
float_raise(status, float_flag_inexact);
if (roundIncrement != 0) set_float_rounding_up(status);
}
return packFloat32(zSign, 0xFF, 0) - (roundIncrement == 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1) || (zSig + roundIncrement < 0x80000000);
zSig = shift32RightJamming(zSig, -zExp);
zExp = 0;
roundBits = zSig & roundMask;
if (isTiny && (roundBits || !float_exception_masked(status, float_flag_underflow))) {
float_raise(status, float_flag_underflow);
if(get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_inexact);
return packFloat32(zSign, 0, 0);
}
}
}
}
if (roundBits) float_raise(status, float_flag_inexact);
Bit32u zSigRound = ((zSig + roundIncrement) & ~roundMask) >> 7;
zSigRound &= ~(((roundBits ^ 0x40) == 0) & roundNearestEven);
if ((zSigRound << 7) > zSig) set_float_rounding_up(status);
if (zSigRound == 0) zExp = 0;
return packFloat32(zSign, zExp, zSigRound);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat32' except that `zSig' does not have to be normalized.
| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float32 normalizeRoundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, float_status_t &status)
{
int shiftCount = countLeadingZeros32(zSig) - 1;
return roundAndPackFloat32(zSign, zExp - shiftCount, zSig<<shiftCount, status);
}
/*----------------------------------------------------------------------------
| Normalizes the subnormal double-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat64Subnormal(Bit64u aSig, Bit16s *zExpPtr, Bit64u *zSigPtr)
{
int shiftCount = countLeadingZeros64(aSig) - 11;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the double-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded
| to a subnormal number, and the underflow and inexact exceptions are raised
| if the abstract input cannot be represented exactly as a subnormal double-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 62
| and 61, which is 10 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float64 roundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, float_status_t &status)
{
Bit16s roundIncrement, roundBits;
int roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
roundIncrement = 0x200;
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = 0x3FF;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = (Bit16s)(zSig & 0x3FF);
if (0x7FD <= (Bit16u) zExp) {
if ((0x7FD < zExp)
|| ((zExp == 0x7FD)
&& ((Bit64s) (zSig + roundIncrement) < 0)))
{
float_raise(status, float_flag_overflow);
if (roundBits || float_exception_masked(status, float_flag_overflow)) {
float_raise(status, float_flag_inexact);
if (roundIncrement != 0) set_float_rounding_up(status);
}
return packFloat64(zSign, 0x7FF, 0) - (roundIncrement == 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1) || (zSig + roundIncrement < BX_CONST64(0x8000000000000000));
zSig = shift64RightJamming(zSig, -zExp);
zExp = 0;
roundBits = (Bit16s)(zSig & 0x3FF);
if (isTiny && (roundBits || !float_exception_masked(status, float_flag_underflow))) {
float_raise(status, float_flag_underflow);
if(get_flush_underflow_to_zero(status)) {
float_raise(status, float_flag_inexact);
return packFloat64(zSign, 0, 0);
}
}
}
}
if (roundBits) float_raise(status, float_flag_inexact);
Bit64u zSigRound = (zSig + roundIncrement)>>10;
zSigRound &= ~(((roundBits ^ 0x200) == 0) & roundNearestEven);
if ((zSigRound << 10) > zSig) set_float_rounding_up(status);
if (zSigRound == 0) zExp = 0;
return packFloat64(zSign, zExp, zSigRound);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat64' except that `zSig' does not have to be normalized.
| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float64 normalizeRoundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, float_status_t &status)
{
int shiftCount = countLeadingZeros64(zSig) - 1;
return roundAndPackFloat64(zSign, zExp - shiftCount, zSig<<shiftCount, status);
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Normalizes the subnormal extended double-precision floating-point value
| represented by the denormalized significand `aSig'. The normalized exponent
| and significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloatx80Subnormal(Bit64u aSig, Bit32s *zExpPtr, Bit64u *zSigPtr)
{
int shiftCount = countLeadingZeros64(aSig);
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| rounded and packed into the extended double-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal extended
| double-precision floating-point number.
| If `roundingPrecision' is 32 or 64, the result is rounded to the same
| number of bits as single or double precision, respectively. Otherwise, the
| result is rounded to the full precision of the extended double-precision
| format.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. The
| handling of underflow and overflow follows the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 SoftFloatRoundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status)
{
Bit64u roundIncrement, roundMask, roundBits;
int increment;
Bit64u zSigExact; /* support rounding-up response */
Bit8u roundingMode = get_float_rounding_mode(status);
int roundNearestEven = (roundingMode == float_round_nearest_even);
if (roundingPrecision == 64) {
roundIncrement = BX_CONST64(0x0000000000000400);
roundMask = BX_CONST64(0x00000000000007FF);
}
else if (roundingPrecision == 32) {
roundIncrement = BX_CONST64(0x0000008000000000);
roundMask = BX_CONST64(0x000000FFFFFFFFFF);
}
else goto precision80;
zSig0 |= (zSig1 != 0);
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) roundIncrement = 0;
else {
roundIncrement = roundMask;
if (zSign) {
if (roundingMode == float_round_up) roundIncrement = 0;
}
else {
if (roundingMode == float_round_down) roundIncrement = 0;
}
}
}
roundBits = zSig0 & roundMask;
if (0x7FFD <= (Bit32u) (zExp - 1)) {
if ((0x7FFE < zExp)
|| ((zExp == 0x7FFE) && (zSig0 + roundIncrement < zSig0)))
{
goto overflow;
}
if (zExp <= 0) {
int isTiny = (zExp < 0) || (zSig0 <= zSig0 + roundIncrement);
zSig0 = shift64RightJamming(zSig0, 1 - zExp);
zSigExact = zSig0;
zExp = 0;
roundBits = zSig0 & roundMask;
if (isTiny) {
if (roundBits || (zSig0 && !float_exception_masked(status, float_flag_underflow)))
float_raise(status, float_flag_underflow);
}
if (roundBits) float_raise(status, float_flag_inexact);
zSig0 += roundIncrement;
if ((Bit64s) zSig0 < 0) zExp = 1;
roundIncrement = roundMask + 1;
if (roundNearestEven && (roundBits<<1 == roundIncrement))
roundMask |= roundIncrement;
zSig0 &= ~roundMask;
if (zSig0 > zSigExact) set_float_rounding_up(status);
return packFloatx80(zSign, zExp, zSig0);
}
}
if (roundBits) float_raise(status, float_flag_inexact);
zSigExact = zSig0;
zSig0 += roundIncrement;
if (zSig0 < roundIncrement) {
// Basically scale by shifting right and keep overflow
++zExp;
zSig0 = BX_CONST64(0x8000000000000000);
zSigExact >>= 1; // must scale also, or else later tests will fail
}
roundIncrement = roundMask + 1;
if (roundNearestEven && (roundBits<<1 == roundIncrement))
roundMask |= roundIncrement;
zSig0 &= ~roundMask;
if (zSig0 > zSigExact) set_float_rounding_up(status);
if (zSig0 == 0) zExp = 0;
return packFloatx80(zSign, zExp, zSig0);
precision80:
increment = ((Bit64s) zSig1 < 0);
if (! roundNearestEven) {
if (roundingMode == float_round_to_zero) increment = 0;
else {
if (zSign) {
increment = (roundingMode == float_round_down) && zSig1;
}
else {
increment = (roundingMode == float_round_up) && zSig1;
}
}
}
if (0x7FFD <= (Bit32u) (zExp - 1)) {
if ((0x7FFE < zExp)
|| ((zExp == 0x7FFE)
&& (zSig0 == BX_CONST64(0xFFFFFFFFFFFFFFFF))
&& increment))
{
roundMask = 0;
overflow:
float_raise(status, float_flag_overflow | float_flag_inexact);
if ((roundingMode == float_round_to_zero)
|| (zSign && (roundingMode == float_round_up))
|| (! zSign && (roundingMode == float_round_down)))
{
return packFloatx80(zSign, 0x7FFE, ~roundMask);
}
set_float_rounding_up(status);
return packFloatx80(zSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (zExp <= 0) {
int isTiny = (zExp < 0) || (! increment)
|| (zSig0 < BX_CONST64(0xFFFFFFFFFFFFFFFF));
shift64ExtraRightJamming(zSig0, zSig1, 1 - zExp, &zSig0, &zSig1);
zExp = 0;
if (isTiny) {
if (zSig1 || (zSig0 && !float_exception_masked(status, float_flag_underflow)))
float_raise(status, float_flag_underflow);
}
if (zSig1) float_raise(status, float_flag_inexact);
if (roundNearestEven) increment = ((Bit64s) zSig1 < 0);
else {
if (zSign) {
increment = (roundingMode == float_round_down) && zSig1;
} else {
increment = (roundingMode == float_round_up) && zSig1;
}
}
if (increment) {
zSigExact = zSig0++;
zSig0 &= ~(((Bit64u) (zSig1<<1) == 0) & roundNearestEven);
if (zSig0 > zSigExact) set_float_rounding_up(status);
if ((Bit64s) zSig0 < 0) zExp = 1;
}
return packFloatx80(zSign, zExp, zSig0);
}
}
if (zSig1) float_raise(status, float_flag_inexact);
if (increment) {
zSigExact = zSig0++;
if (zSig0 == 0) {
zExp++;
zSig0 = BX_CONST64(0x8000000000000000);
zSigExact >>= 1; // must scale also, or else later tests will fail
}
else {
zSig0 &= ~(((Bit64u) (zSig1<<1) == 0) & roundNearestEven);
}
if (zSig0 > zSigExact) set_float_rounding_up(status);
}
else {
if (zSig0 == 0) zExp = 0;
}
return packFloatx80(zSign, zExp, zSig0);
}
floatx80 roundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status)
{
float_status_t round_status = status;
floatx80 result = SoftFloatRoundAndPackFloatx80(roundingPrecision, zSign, zExp, zSig0, zSig1, status);
// bias unmasked undeflow
if (status.float_exception_flags & ~status.float_exception_masks & float_flag_underflow) {
float_raise(round_status, float_flag_underflow);
return SoftFloatRoundAndPackFloatx80(roundingPrecision, zSign, zExp + 0x6000, zSig0, zSig1, status = round_status);
}
// bias unmasked overflow
if (status.float_exception_flags & ~status.float_exception_masks & float_flag_overflow) {
float_raise(round_status, float_flag_overflow);
return SoftFloatRoundAndPackFloatx80(roundingPrecision, zSign, zExp - 0x6000, zSig0, zSig1, status = round_status);
}
return result;
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent
| `zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. This routine is just like
| `roundAndPackFloatx80' except that the input significand does not have to be
| normalized.
*----------------------------------------------------------------------------*/
floatx80 normalizeRoundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status)
{
if (zSig0 == 0) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
int shiftCount = countLeadingZeros64(zSig0);
shortShift128Left(zSig0, zSig1, shiftCount, &zSig0, &zSig1);
zExp -= shiftCount;
return
roundAndPackFloatx80(roundingPrecision, zSign, zExp, zSig0, zSig1, status);
}
#endif
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Normalizes the subnormal quadruple-precision floating-point value
| represented by the denormalized significand formed by the concatenation of
| `aSig0' and `aSig1'. The normalized exponent is stored at the location
| pointed to by `zExpPtr'. The most significant 49 bits of the normalized
| significand are stored at the location pointed to by `zSig0Ptr', and the
| least significant 64 bits of the normalized significand are stored at the
| location pointed to by `zSig1Ptr'.
*----------------------------------------------------------------------------*/
void normalizeFloat128Subnormal(
Bit64u aSig0, Bit64u aSig1, Bit32s *zExpPtr, Bit64u *zSig0Ptr, Bit64u *zSig1Ptr)
{
int shiftCount;
if (aSig0 == 0) {
shiftCount = countLeadingZeros64(aSig1) - 15;
if (shiftCount < 0) {
*zSig0Ptr = aSig1 >>(-shiftCount);
*zSig1Ptr = aSig1 << (shiftCount & 63);
}
else {
*zSig0Ptr = aSig1 << shiftCount;
*zSig1Ptr = 0;
}
*zExpPtr = - shiftCount - 63;
}
else {
shiftCount = countLeadingZeros64(aSig0) - 15;
shortShift128Left(aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr);
*zExpPtr = 1 - shiftCount;
}
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0', `zSig1',
| and `zSig2', and returns the proper quadruple-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| simply rounded and packed into the quadruple-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal quadruple-
| precision floating-point number.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. In the
| usual case that the input significand is normalized, `zExp' must be 1 less
| than the ``true'' floating-point exponent. The handling of underflow and
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float128 roundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, Bit64u zSig2, float_status_t &status)
{
int increment = ((Bit64s) zSig2 < 0);
if (0x7FFD <= (Bit32u) zExp) {
if ((0x7FFD < zExp)
|| ((zExp == 0x7FFD)
&& eq128(BX_CONST64(0x0001FFFFFFFFFFFF),
BX_CONST64(0xFFFFFFFFFFFFFFFF), zSig0, zSig1)
&& increment))
{
float_raise(status, float_flag_overflow | float_flag_inexact);
return packFloat128(zSign, 0x7FFF, 0, 0);
}
if (zExp < 0) {
int isTiny = (zExp < -1)
|| ! increment
|| lt128(zSig0, zSig1,
BX_CONST64(0x0001FFFFFFFFFFFF),
BX_CONST64(0xFFFFFFFFFFFFFFFF));
shift128ExtraRightJamming(
zSig0, zSig1, zSig2, -zExp, &zSig0, &zSig1, &zSig2);
zExp = 0;
if (isTiny && zSig2) float_raise(status, float_flag_underflow);
increment = ((Bit64s) zSig2 < 0);
}
}
if (zSig2) float_raise(status, float_flag_inexact);
if (increment) {
add128(zSig0, zSig1, 0, 1, &zSig0, &zSig1);
zSig1 &= ~((zSig2 + zSig2 == 0) & 1);
}
else {
if ((zSig0 | zSig1) == 0) zExp = 0;
}
return packFloat128(zSign, zExp, zSig0, zSig1);
}
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand formed by the concatenation of `zSig0' and `zSig1', and
| returns the proper quadruple-precision floating-point value corresponding
| to the abstract input. This routine is just like `roundAndPackFloat128'
| except that the input significand has fewer bits and does not have to be
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
| point exponent.
*----------------------------------------------------------------------------*/
float128 normalizeRoundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status)
{
Bit64u zSig2;
if (zSig0 == 0) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
int shiftCount = countLeadingZeros64(zSig0) - 15;
if (0 <= shiftCount) {
zSig2 = 0;
shortShift128Left(zSig0, zSig1, shiftCount, &zSig0, &zSig1);
}
else {
shift128ExtraRightJamming(
zSig0, zSig1, 0, -shiftCount, &zSig0, &zSig1, &zSig2);
}
zExp -= shiftCount;
return roundAndPackFloat128(zSign, zExp, zSig0, zSig1, zSig2, status);
}
#endif

View File

@ -0,0 +1,260 @@
/*============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOAT_ROUND_PACK_H_
#define _SOFTFLOAT_ROUND_PACK_H_
#include "softfloat.h"
/*----------------------------------------------------------------------------
| Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
| and 7, and returns the properly rounded 32-bit integer corresponding to the
| input. If `zSign' is 1, the input is negated before being converted to an
| integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
| is simply rounded to an integer, with the inexact exception raised if the
| input cannot be represented exactly as an integer. However, if the fixed-
| point input is too large, the invalid exception is raised and the integer
| indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit32s roundAndPackInt32(int zSign, Bit64u absZ, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
| `absZ1', with binary point between bits 63 and 64 (between the input words),
| and returns the properly rounded 64-bit integer corresponding to the input.
| If `zSign' is 1, the input is negated before being converted to an integer.
| Ordinarily, the fixed-point input is simply rounded to an integer, with
| the inexact exception raised if the input cannot be represented exactly as
| an integer. However, if the fixed-point input is too large, the invalid
| exception is raised and the integer indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit64s roundAndPackInt64(int zSign, Bit64u absZ0, Bit64u absZ1, float_status_t &status);
/*----------------------------------------------------------------------------
| Normalizes the subnormal single-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat32Subnormal(Bit32u aSig, Bit16s *zExpPtr, Bit32u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the single-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal single-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 30
| and 29, which is 7 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float32 roundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper single-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat32' except that `zSig' does not have to be normalized.
| Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float32 normalizeRoundAndPackFloat32(int zSign, Bit16s zExp, Bit32u zSig, float_status_t &status);
/*----------------------------------------------------------------------------
| Normalizes the subnormal double-precision floating-point value represented
| by the denormalized significand `aSig'. The normalized exponent and
| significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloat64Subnormal(Bit64u aSig, Bit16s *zExpPtr, Bit64u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. Ordinarily, the abstract
| value is simply rounded and packed into the double-precision format, with
| the inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded
| to a subnormal number, and the underflow and inexact exceptions are raised
| if the abstract input cannot be represented exactly as a subnormal double-
| precision floating-point number.
| The input significand `zSig' has its binary point between bits 62
| and 61, which is 10 bits to the left of the usual location. This shifted
| significand must be normalized or smaller. If `zSig' is not normalized,
| `zExp' must be 0; in that case, the result returned is a subnormal number,
| and it must not require rounding. In the usual case that `zSig' is
| normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
| The handling of underflow and overflow follows the IEC/IEEE Standard for
| Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float64 roundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand `zSig', and returns the proper double-precision floating-
| point value corresponding to the abstract input. This routine is just like
| `roundAndPackFloat64' except that `zSig' does not have to be normalized.
| Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
| floating-point exponent.
*----------------------------------------------------------------------------*/
float64 normalizeRoundAndPackFloat64(int zSign, Bit16s zExp, Bit64u zSig, float_status_t &status);
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Normalizes the subnormal extended double-precision floating-point value
| represented by the denormalized significand `aSig'. The normalized exponent
| and significand are stored at the locations pointed to by `zExpPtr' and
| `zSigPtr', respectively.
*----------------------------------------------------------------------------*/
void normalizeFloatx80Subnormal(Bit64u aSig, Bit32s *zExpPtr, Bit64u *zSigPtr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| rounded and packed into the extended double-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal extended
| double-precision floating-point number.
| If `roundingPrecision' is 32 or 64, the result is rounded to the same
| number of bits as single or double precision, respectively. Otherwise, the
| result is rounded to the full precision of the extended double-precision
| format.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. The
| handling of underflow and overflow follows the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 roundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent
| `zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
| and returns the proper extended double-precision floating-point value
| corresponding to the abstract input. This routine is just like
| `roundAndPackFloatx80' except that the input significand does not have to be
| normalized.
*----------------------------------------------------------------------------*/
floatx80 normalizeRoundAndPackFloatx80(int roundingPrecision,
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status);
#endif // FLOATX80
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Normalizes the subnormal quadruple-precision floating-point value
| represented by the denormalized significand formed by the concatenation of
| `aSig0' and `aSig1'. The normalized exponent is stored at the location
| pointed to by `zExpPtr'. The most significant 49 bits of the normalized
| significand are stored at the location pointed to by `zSig0Ptr', and the
| least significant 64 bits of the normalized significand are stored at the
| location pointed to by `zSig1Ptr'.
*----------------------------------------------------------------------------*/
void normalizeFloat128Subnormal(
Bit64u aSig0, Bit64u aSig1, Bit32s *zExpPtr, Bit64u *zSig0Ptr, Bit64u *zSig1Ptr);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and extended significand formed by the concatenation of `zSig0', `zSig1',
| and `zSig2', and returns the proper quadruple-precision floating-point value
| corresponding to the abstract input. Ordinarily, the abstract value is
| simply rounded and packed into the quadruple-precision format, with the
| inexact exception raised if the abstract input cannot be represented
| exactly. However, if the abstract value is too large, the overflow and
| inexact exceptions are raised and an infinity or maximal finite value is
| returned. If the abstract value is too small, the input value is rounded to
| a subnormal number, and the underflow and inexact exceptions are raised if
| the abstract input cannot be represented exactly as a subnormal quadruple-
| precision floating-point number.
| The input significand must be normalized or smaller. If the input
| significand is not normalized, `zExp' must be 0; in that case, the result
| returned is a subnormal number, and it must not require rounding. In the
| usual case that the input significand is normalized, `zExp' must be 1 less
| than the ``true'' floating-point exponent. The handling of underflow and
| overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
float128 roundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, Bit64u zSig2, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes an abstract floating-point value having sign `zSign', exponent `zExp',
| and significand formed by the concatenation of `zSig0' and `zSig1', and
| returns the proper quadruple-precision floating-point value corresponding
| to the abstract input. This routine is just like `roundAndPackFloat128'
| except that the input significand has fewer bits and does not have to be
| normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
| point exponent.
*----------------------------------------------------------------------------*/
float128 normalizeRoundAndPackFloat128(
int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1, float_status_t &status);
#endif // FLOAT128
#endif

View File

@ -0,0 +1,195 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#define FLOAT128
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloat.h"
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float32 propagateFloat32NaN(float32 a, float32 b, float_status_t &status)
{
int aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float32_is_nan(a);
aIsSignalingNaN = float32_is_signaling_nan(a);
bIsNaN = float32_is_nan(b);
bIsSignalingNaN = float32_is_signaling_nan(b);
a |= 0x00400000;
b |= 0x00400000;
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (get_float_nan_handling_mode(status) == float_larger_significand_nan) {
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | ! bIsNaN) return a;
returnLargerSignificand:
if ((Bit32u) (a<<1) < (Bit32u) (b<<1)) return b;
if ((Bit32u) (b<<1) < (Bit32u) (a<<1)) return a;
return (a < b) ? a : b;
}
else {
return b;
}
} else {
return (aIsSignalingNaN | aIsNaN) ? a : b;
}
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float64 propagateFloat64NaN(float64 a, float64 b, float_status_t &status)
{
int aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float64_is_nan(a);
aIsSignalingNaN = float64_is_signaling_nan(a);
bIsNaN = float64_is_nan(b);
bIsSignalingNaN = float64_is_signaling_nan(b);
a |= BX_CONST64(0x0008000000000000);
b |= BX_CONST64(0x0008000000000000);
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (get_float_nan_handling_mode(status) == float_larger_significand_nan) {
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | ! bIsNaN) return a;
returnLargerSignificand:
if ((Bit64u) (a<<1) < (Bit64u) (b<<1)) return b;
if ((Bit64u) (b<<1) < (Bit64u) (a<<1)) return a;
return (a < b) ? a : b;
}
else {
return b;
}
} else {
return (aIsSignalingNaN | aIsNaN) ? a : b;
}
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status_t &status)
{
int aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = floatx80_is_nan(a);
aIsSignalingNaN = floatx80_is_signaling_nan(a);
bIsNaN = floatx80_is_nan(b);
bIsSignalingNaN = floatx80_is_signaling_nan(b);
a.fraction |= BX_CONST64(0xC000000000000000);
b.fraction |= BX_CONST64(0xC000000000000000);
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | ! bIsNaN) return a;
returnLargerSignificand:
if (a.fraction < b.fraction) return b;
if (b.fraction < a.fraction) return a;
return (a.exp < b.exp) ? a : b;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
const floatx80 floatx80_default_nan =
packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction);
#endif /* FLOATX80 */
#ifdef FLOAT128
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float128 propagateFloat128NaN(float128 a, float128 b, float_status_t &status)
{
int aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN;
aIsNaN = float128_is_nan(a);
aIsSignalingNaN = float128_is_signaling_nan(a);
bIsNaN = float128_is_nan(b);
bIsSignalingNaN = float128_is_signaling_nan(b);
a.hi |= BX_CONST64(0x0000800000000000);
b.hi |= BX_CONST64(0x0000800000000000);
if (aIsSignalingNaN | bIsSignalingNaN) float_raise(status, float_flag_invalid);
if (aIsSignalingNaN) {
if (bIsSignalingNaN) goto returnLargerSignificand;
return bIsNaN ? b : a;
}
else if (aIsNaN) {
if (bIsSignalingNaN | !bIsNaN) return a;
returnLargerSignificand:
if (lt128(a.hi<<1, a.lo, b.hi<<1, b.lo)) return b;
if (lt128(b.hi<<1, b.lo, a.hi<<1, a.lo)) return a;
return (a.hi < b.hi) ? a : b;
}
else {
return b;
}
}
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN.
*----------------------------------------------------------------------------*/
const float128 float128_default_nan =
packFloat128(float128_default_nan_hi, float128_default_nan_lo);
#endif /* FLOAT128 */

View File

@ -0,0 +1,619 @@
/*============================================================================
This C source fragment is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
#ifndef _SOFTFLOAT_SPECIALIZE_H_
#define _SOFTFLOAT_SPECIALIZE_H_
#include "softfloat.h"
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#define int16_indefinite ((Bit16s)0x8000)
#define int32_indefinite ((Bit32s)0x80000000)
#define int64_indefinite BX_CONST64(0x8000000000000000)
/*----------------------------------------------------------------------------
| Internal canonical NaN format.
*----------------------------------------------------------------------------*/
typedef struct {
int sign;
Bit64u hi, lo;
} commonNaNT;
/*----------------------------------------------------------------------------
| The pattern for a default generated single-precision NaN.
*----------------------------------------------------------------------------*/
#define float32_default_nan 0xFFC00000
#define float32_fraction extractFloat32Frac
#define float32_exp extractFloat32Exp
#define float32_sign extractFloat32Sign
/*----------------------------------------------------------------------------
| Returns the fraction bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32u extractFloat32Frac(float32 a)
{
return a & 0x007FFFFF;
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16s extractFloat32Exp(float32 a)
{
return (a>>23) & 0xFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the single-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat32Sign(float32 a)
{
return a>>31;
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
| single-precision floating-point value, returning the result. After being
| shifted into the proper positions, the three fields are simply added
| together to form the result. This means that any integer portion of `zSig'
| will be added into the exponent. Since a properly normalized significand
| will have an integer portion equal to 1, the `zExp' input should be 1 less
| than the desired result exponent whenever `zSig' is a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 packFloat32(int zSign, Bit16s zExp, Bit32u zSig)
{
return (((Bit32u) zSign)<<31) + (((Bit32u) zExp)<<23) + zSig;
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float32_is_nan(float32 a)
{
return (0xFF000000 < (Bit32u) (a<<1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the single-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float32_is_signaling_nan(float32 a)
{
return (((a>>22) & 0x1FF) == 0x1FE) && (a & 0x003FFFFF);
}
/*----------------------------------------------------------------------------
| Convert float32 denormals to zero
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 float32_denormal_to_zero(float32 op)
{
if (float32_class(op) == float_denormal) op &= ((Bit32u)(1) << 31);
return op;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the single-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float32ToCommonNaN(float32 a, float_status_t &status)
{
commonNaNT z;
if (float32_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = a>>31;
z.lo = 0;
z.hi = ((Bit64u) a)<<41;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the single-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 commonNaNToFloat32(commonNaNT a)
{
return (((Bit32u) a.sign)<<31) | 0x7FC00000 | (Bit32u)(a.hi>>41);
}
/*----------------------------------------------------------------------------
| Takes two single-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float32 propagateFloat32NaN(float32 a, float32 b, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes single-precision floating-point NaN `a' and returns the appropriate
| NaN result. If `a' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float32 propagateFloat32NaN(float32 a, float_status_t &status)
{
if (float32_is_signaling_nan(a))
float_raise(status, float_flag_invalid);
return a | 0x00400000;
}
/*----------------------------------------------------------------------------
| The pattern for a default generated double-precision NaN.
*----------------------------------------------------------------------------*/
#define float64_default_nan BX_CONST64(0xFFF8000000000000)
#define float64_fraction extractFloat64Frac
#define float64_exp extractFloat64Exp
#define float64_sign extractFloat64Sign
/*----------------------------------------------------------------------------
| Returns the fraction bits of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloat64Frac(float64 a)
{
return a & BX_CONST64(0x000FFFFFFFFFFFFF);
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit16s extractFloat64Exp(float64 a)
{
return (Bit16s)(a>>52) & 0x7FF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the double-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat64Sign(float64 a)
{
return (int)(a>>63);
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
| double-precision floating-point value, returning the result. After being
| shifted into the proper positions, the three fields are simply added
| together to form the result. This means that any integer portion of `zSig'
| will be added into the exponent. Since a properly normalized significand
| will have an integer portion equal to 1, the `zExp' input should be 1 less
| than the desired result exponent whenever `zSig' is a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 packFloat64(int zSign, Bit16s zExp, Bit64u zSig)
{
return (((Bit64u) zSign)<<63) + (((Bit64u) zExp)<<52) + zSig;
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float64_is_nan(float64 a)
{
return (BX_CONST64(0xFFE0000000000000) < (Bit64u) (a<<1));
}
/*----------------------------------------------------------------------------
| Returns 1 if the double-precision floating-point value `a' is a signaling
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float64_is_signaling_nan(float64 a)
{
return (((a>>51) & 0xFFF) == 0xFFE) && (a & BX_CONST64(0x0007FFFFFFFFFFFF));
}
/*----------------------------------------------------------------------------
| Convert float64 denormals to zero
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 float64_denormal_to_zero(float64 op)
{
if (float64_class(op) == float_denormal) op &= ((Bit64u)(1) << 63);
return op;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the double-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float64ToCommonNaN(float64 a, float_status_t &status)
{
commonNaNT z;
if (float64_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = (int)(a>>63);
z.lo = 0;
z.hi = a<<12;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the double-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 commonNaNToFloat64(commonNaNT a)
{
return (((Bit64u) a.sign)<<63) | BX_CONST64(0x7FF8000000000000) | (a.hi>>12);
}
/*----------------------------------------------------------------------------
| Takes two double-precision floating-point values `a' and `b', one of which
| is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a
| signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float64 propagateFloat64NaN(float64 a, float64 b, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes double-precision floating-point NaN `a' and returns the appropriate
| NaN result. If `a' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float64 propagateFloat64NaN(float64 a, float_status_t &status)
{
if (float64_is_signaling_nan(a))
float_raise(status, float_flag_invalid);
return a | BX_CONST64(0x0008000000000000);
}
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN. The
| `high' and `low' values hold the most- and least-significant bits,
| respectively.
*----------------------------------------------------------------------------*/
#define floatx80_default_nan_exp 0xFFFF
#define floatx80_default_nan_fraction BX_CONST64(0xC000000000000000)
#define floatx80_fraction extractFloatx80Frac
#define floatx80_exp extractFloatx80Exp
#define floatx80_sign extractFloatx80Sign
#define EXP_BIAS 0x3FFF
/*----------------------------------------------------------------------------
| Returns the fraction bits of the extended double-precision floating-point
| value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloatx80Frac(floatx80 a)
{
return a.fraction;
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the extended double-precision floating-point
| value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32s extractFloatx80Exp(floatx80 a)
{
return a.exp & 0x7FFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the extended double-precision floating-point value
| `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloatx80Sign(floatx80 a)
{
return a.exp>>15;
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
| extended double-precision floating-point value, returning the result.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80 packFloatx80(int zSign, Bit32s zExp, Bit64u zSig)
{
floatx80 z;
z.fraction = zSig;
z.exp = (zSign << 15) + zExp;
return z;
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int floatx80_is_nan(floatx80 a)
{
return ((a.exp & 0x7FFF) == 0x7FFF) && (Bit64s) (a.fraction<<1);
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int floatx80_is_signaling_nan(floatx80 a)
{
Bit64u aLow = a.fraction & ~BX_CONST64(0x4000000000000000);
return ((a.exp & 0x7FFF) == 0x7FFF) &&
((Bit64u) (aLow<<1)) && (a.fraction == aLow);
}
/*----------------------------------------------------------------------------
| Returns 1 if the extended double-precision floating-point value `a' is an
| unsupported; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int floatx80_is_unsupported(floatx80 a)
{
return ((a.exp & 0x7FFF) && !(a.fraction & BX_CONST64(0x8000000000000000)));
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the
| invalid exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT floatx80ToCommonNaN(floatx80 a, float_status_t &status)
{
commonNaNT z;
if (floatx80_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = a.exp >> 15;
z.lo = 0;
z.hi = a.fraction << 1;
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the extended
| double-precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80 commonNaNToFloatx80(commonNaNT a)
{
floatx80 z;
z.fraction = BX_CONST64(0xC000000000000000) | (a.hi>>1);
z.exp = (((Bit16u) a.sign)<<15) | 0x7FFF;
return z;
}
/*----------------------------------------------------------------------------
| Takes two extended double-precision floating-point values `a' and `b', one
| of which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
floatx80 propagateFloatx80NaN(floatx80 a, floatx80 b, float_status_t &status);
/*----------------------------------------------------------------------------
| Takes extended double-precision floating-point NaN `a' and returns the
| appropriate NaN result. If `a' is a signaling NaN, the invalid exception
| is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80 propagateFloatx80NaN(floatx80 a, float_status_t &status)
{
if (floatx80_is_signaling_nan(a))
float_raise(status, float_flag_invalid);
a.fraction |= BX_CONST64(0xC000000000000000);
return a;
}
/*----------------------------------------------------------------------------
| The pattern for a default generated extended double-precision NaN.
*----------------------------------------------------------------------------*/
extern const floatx80 floatx80_default_nan;
#endif /* FLOATX80 */
#ifdef FLOAT128
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN. The `high' and
| `low' values hold the most- and least-significant bits, respectively.
*----------------------------------------------------------------------------*/
#define float128_default_nan_hi BX_CONST64(0xFFFF800000000000)
#define float128_default_nan_lo BX_CONST64(0x0000000000000000)
#define float128_exp extractFloat128Exp
/*----------------------------------------------------------------------------
| Returns the least-significant 64 fraction bits of the quadruple-precision
| floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloat128Frac1(float128 a)
{
return a.lo;
}
/*----------------------------------------------------------------------------
| Returns the most-significant 48 fraction bits of the quadruple-precision
| floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit64u extractFloat128Frac0(float128 a)
{
return a.hi & BX_CONST64(0x0000FFFFFFFFFFFF);
}
/*----------------------------------------------------------------------------
| Returns the exponent bits of the quadruple-precision floating-point value
| `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE Bit32s extractFloat128Exp(float128 a)
{
return ((Bit32s)(a.hi>>48)) & 0x7FFF;
}
/*----------------------------------------------------------------------------
| Returns the sign bit of the quadruple-precision floating-point value `a'.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int extractFloat128Sign(float128 a)
{
return (int)(a.hi >> 63);
}
/*----------------------------------------------------------------------------
| Packs the sign `zSign', the exponent `zExp', and the significand formed
| by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
| floating-point value, returning the result. After being shifted into the
| proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
| added together to form the most significant 32 bits of the result. This
| means that any integer portion of `zSig0' will be added into the exponent.
| Since a properly normalized significand will have an integer portion equal
| to 1, the `zExp' input should be 1 less than the desired result exponent
| whenever `zSig0' and `zSig1' concatenated form a complete, normalized
| significand.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float128 packFloat128(int zSign, Bit32s zExp, Bit64u zSig0, Bit64u zSig1)
{
float128 z;
z.lo = zSig1;
z.hi = (((Bit64u) zSign)<<63) + (((Bit64u) zExp)<<48) + zSig0;
return z;
}
/*----------------------------------------------------------------------------
| Packs two 64-bit precision integers into into the quadruple-precision
| floating-point value, returning the result.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float128 packFloat128(Bit64u zHi, Bit64u zLo)
{
float128 z;
z.lo = zLo;
z.hi = zHi;
return z;
}
#ifdef _MSC_VER
#define PACK_FLOAT_128(hi,lo) { lo, hi }
#else
#define PACK_FLOAT_128(hi,lo) packFloat128(BX_CONST64(hi),BX_CONST64(lo))
#endif
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a NaN;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float128_is_nan(float128 a)
{
return (BX_CONST64(0xFFFE000000000000) <= (Bit64u) (a.hi<<1))
&& (a.lo || (a.hi & BX_CONST64(0x0000FFFFFFFFFFFF)));
}
/*----------------------------------------------------------------------------
| Returns 1 if the quadruple-precision floating-point value `a' is a
| signaling NaN; otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float128_is_signaling_nan(float128 a)
{
return (((a.hi>>47) & 0xFFFF) == 0xFFFE)
&& (a.lo || (a.hi & BX_CONST64(0x00007FFFFFFFFFFF)));
}
/*----------------------------------------------------------------------------
| Returns the result of converting the quadruple-precision floating-point NaN
| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid
| exception is raised.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE commonNaNT float128ToCommonNaN(float128 a, float_status_t &status)
{
commonNaNT z;
if (float128_is_signaling_nan(a)) float_raise(status, float_flag_invalid);
z.sign = (int)(a.hi>>63);
shortShift128Left(a.hi, a.lo, 16, &z.hi, &z.lo);
return z;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the canonical NaN `a' to the quadruple-
| precision floating-point format.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE float128 commonNaNToFloat128(commonNaNT a)
{
float128 z;
shift128Right(a.hi, a.lo, 16, &z.hi, &z.lo);
z.hi |= (((Bit64u) a.sign)<<63) | BX_CONST64(0x7FFF800000000000);
return z;
}
/*----------------------------------------------------------------------------
| Takes two quadruple-precision floating-point values `a' and `b', one of
| which is a NaN, and returns the appropriate NaN result. If either `a' or
| `b' is a signaling NaN, the invalid exception is raised.
*----------------------------------------------------------------------------*/
float128 propagateFloat128NaN(float128 a, float128 b, float_status_t &status);
/*----------------------------------------------------------------------------
| The pattern for a default generated quadruple-precision NaN.
*----------------------------------------------------------------------------*/
extern const float128 float128_default_nan;
#endif /* FLOAT128 */
#endif

2911
simulators/bochs/fpu/softfloat.cc Executable file

File diff suppressed because it is too large Load Diff

339
simulators/bochs/fpu/softfloat.h Executable file
View File

@ -0,0 +1,339 @@
/*============================================================================
This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic
Package, Release 2b.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://www.cs.berkeley.edu/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Adapted for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include <config.h> /* generated by configure script from config.h.in */
#ifndef _SOFTFLOAT_H_
#define _SOFTFLOAT_H_
#define FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
typedef Bit32u float32;
typedef Bit64u float64;
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point class.
*----------------------------------------------------------------------------*/
typedef enum {
float_zero,
float_NaN,
float_negative_inf,
float_positive_inf,
float_denormal,
float_normalized
} float_class_t;
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point NaN operands handling mode.
*----------------------------------------------------------------------------*/
enum float_nan_handling_mode_t {
float_larger_significand_nan = 0, // this mode used by x87 FPU
float_first_operand_nan = 1 // this mode used by SSE
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point rounding mode.
*----------------------------------------------------------------------------*/
enum float_round_t {
float_round_nearest_even = 0,
float_round_down = 1,
float_round_up = 2,
float_round_to_zero = 3
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point exception flags.
*----------------------------------------------------------------------------*/
enum float_exception_flag_t {
float_flag_invalid = 0x01,
float_flag_denormal = 0x02,
float_flag_divbyzero = 0x04,
float_flag_overflow = 0x08,
float_flag_underflow = 0x10,
float_flag_inexact = 0x20
};
#ifdef FLOATX80
#define RAISE_SW_C1 0x0200
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point ordering relations
*----------------------------------------------------------------------------*/
enum {
float_relation_less = -1,
float_relation_equal = 0,
float_relation_greater = 1,
float_relation_unordered = 2
};
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point status structure.
*----------------------------------------------------------------------------*/
struct float_status_t
{
#ifdef FLOATX80
int float_rounding_precision; /* floatx80 only */
#endif
int float_rounding_mode;
int float_exception_flags;
int float_exception_masks;
int float_nan_handling_mode; /* flag register */
int flush_underflow_to_zero; /* flag register */
};
/*----------------------------------------------------------------------------
| Routine to raise any or all of the software IEC/IEEE floating-point
| exception flags.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE void float_raise(float_status_t &status, int flags)
{
status.float_exception_flags |= flags;
}
/*----------------------------------------------------------------------------
| Routine to check if any or all of the software IEC/IEEE floating-point
| exceptions are masked.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int float_exception_masked(float_status_t &status, int flag)
{
return status.float_exception_masks & flag;
}
/*----------------------------------------------------------------------------
| Returns current floating point rounding mode specified by status word.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_float_rounding_mode(float_status_t &status)
{
return status.float_rounding_mode;
}
/*----------------------------------------------------------------------------
| Returns current floating point precision (floatx80 only).
*----------------------------------------------------------------------------*/
#ifdef FLOATX80
BX_CPP_INLINE int get_float_rounding_precision(float_status_t &status)
{
return status.float_rounding_precision;
}
#endif
/*----------------------------------------------------------------------------
| Returns current floating point NaN operands handling mode specified
| by status word.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_float_nan_handling_mode(float_status_t &status)
{
return status.float_nan_handling_mode;
}
/*----------------------------------------------------------------------------
| Raise floating point precision lost up flag (floatx80 only).
*----------------------------------------------------------------------------*/
#ifdef FLOATX80
BX_CPP_INLINE void set_float_rounding_up(float_status_t &status)
{
status.float_exception_flags |= (float_flag_inexact | RAISE_SW_C1);
}
#endif
/*----------------------------------------------------------------------------
| Returns 1 if the <flush-underflow-to-zero> feature is supported;
| otherwise returns 0.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE int get_flush_underflow_to_zero(float_status_t &status)
{
return status.flush_underflow_to_zero;
}
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
float32 int32_to_float32(Bit32s, float_status_t &status);
float64 int32_to_float64(Bit32s);
float32 int64_to_float32(Bit64s, float_status_t &status);
float64 int64_to_float64(Bit64s, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision conversion routines.
*----------------------------------------------------------------------------*/
Bit32s float32_to_int32(float32, float_status_t &status);
Bit32s float32_to_int32_round_to_zero(float32, float_status_t &status);
Bit64s float32_to_int64(float32, float_status_t &status);
Bit64s float32_to_int64_round_to_zero(float32, float_status_t &status);
float64 float32_to_float64(float32, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE single-precision operations.
*----------------------------------------------------------------------------*/
float32 float32_round_to_int(float32, float_status_t &status);
float32 float32_add(float32, float32, float_status_t &status);
float32 float32_sub(float32, float32, float_status_t &status);
float32 float32_mul(float32, float32, float_status_t &status);
float32 float32_div(float32, float32, float_status_t &status);
float32 float32_sqrt(float32, float_status_t &status);
int float32_compare(float32, float32, float_status_t &status);
int float32_compare_quiet(float32, float32, float_status_t &status);
float_class_t float32_class(float32);
int float32_is_signaling_nan(float32);
int float32_is_nan(float32);
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision conversion routines.
*----------------------------------------------------------------------------*/
Bit32s float64_to_int32(float64, float_status_t &status);
Bit32s float64_to_int32_round_to_zero(float64, float_status_t &status);
Bit64s float64_to_int64(float64, float_status_t &status);
Bit64s float64_to_int64_round_to_zero(float64, float_status_t &status);
float32 float64_to_float32(float64, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE double-precision operations.
*----------------------------------------------------------------------------*/
float64 float64_round_to_int(float64, float_status_t &status);
float64 float64_add(float64, float64, float_status_t &status);
float64 float64_sub(float64, float64, float_status_t &status);
float64 float64_mul(float64, float64, float_status_t &status);
float64 float64_div(float64, float64, float_status_t &status);
float64 float64_sqrt(float64, float_status_t &status);
int float64_compare(float64, float64, float_status_t &status);
int float64_compare_quiet(float64, float64, float_status_t &status);
float_class_t float64_class(float64);
int float64_is_signaling_nan(float64);
int float64_is_nan(float64);
#ifdef FLOATX80
/*----------------------------------------------------------------------------
| Software IEC/IEEE floating-point types.
*----------------------------------------------------------------------------*/
#ifdef BX_BIG_ENDIAN
struct floatx80 { // leave alignment to compiler
Bit16u exp;
Bit64u fraction;
};
#else
struct floatx80 {
Bit64u fraction;
Bit16u exp;
};
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
floatx80 int32_to_floatx80(Bit32s);
floatx80 int64_to_floatx80(Bit64s);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision conversion routines.
*----------------------------------------------------------------------------*/
floatx80 float32_to_floatx80(float32, float_status_t &status);
floatx80 float64_to_floatx80(float64, float_status_t &status);
Bit32s floatx80_to_int32(floatx80, float_status_t &status);
Bit32s floatx80_to_int32_round_to_zero(floatx80, float_status_t &status);
Bit64s floatx80_to_int64(floatx80, float_status_t &status);
Bit64s floatx80_to_int64_round_to_zero(floatx80, float_status_t &status);
float32 floatx80_to_float32(floatx80, float_status_t &status);
float64 floatx80_to_float64(floatx80, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_round_to_int(floatx80, float_status_t &status);
floatx80 floatx80_add(floatx80, floatx80, float_status_t &status);
floatx80 floatx80_sub(floatx80, floatx80, float_status_t &status);
floatx80 floatx80_mul(floatx80, floatx80, float_status_t &status);
floatx80 floatx80_div(floatx80, floatx80, float_status_t &status);
floatx80 floatx80_sqrt(floatx80, float_status_t &status);
float_class_t floatx80_class(floatx80);
int floatx80_is_signaling_nan(floatx80);
int floatx80_is_nan(floatx80);
#endif /* FLOATX80 */
#ifdef FLOAT128
#ifdef BX_BIG_ENDIAN
struct float128 {
Bit64u hi, lo;
};
#else
struct float128 {
Bit64u lo, hi;
};
#endif
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision conversion routines.
*----------------------------------------------------------------------------*/
float128 floatx80_to_float128(floatx80 a, float_status_t &status);
floatx80 float128_to_floatx80(float128 a, float_status_t &status);
float128 int64_to_float128(Bit64s a);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
floatx80 floatx80_mul(floatx80 a, float128 b, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE quadruple-precision operations.
*----------------------------------------------------------------------------*/
float128 float128_add(float128 a, float128 b, float_status_t &status);
float128 float128_sub(float128 a, float128 b, float_status_t &status);
float128 float128_mul(float128 a, float128 b, float_status_t &status);
float128 float128_div(float128 a, float128 b, float_status_t &status);
#endif /* FLOAT128 */
#endif

View File

@ -0,0 +1,363 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#include "softfloatx80.h"
#include "softfloat-round-pack.h"
#include "softfloat-macros.h"
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point value `a' to the 16-bit two's complement integer format. The
| conversion is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic - which means in particular that the conversion
| is rounded according to the current rounding mode. If `a' is a NaN or the
| conversion overflows, the integer indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit16s floatx80_to_int16(floatx80 a, float_status_t &status)
{
if (floatx80_is_unsupported(a))
{
float_raise(status, float_flag_invalid);
return int16_indefinite;
}
Bit32s v32 = floatx80_to_int32(a, status);
if ((v32 > 32767) || (v32 < -32768)) {
status.float_exception_flags = float_flag_invalid; // throw way other flags
return int16_indefinite;
}
return (Bit16s) v32;
}
/*----------------------------------------------------------------------------
| Returns the result of converting the extended double-precision floating-
| point value `a' to the 16-bit two's complement integer format. The
| conversion is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic, except that the conversion is always rounded
| toward zero. If `a' is a NaN or the conversion overflows, the integer
| indefinite value is returned.
*----------------------------------------------------------------------------*/
Bit16s floatx80_to_int16_round_to_zero(floatx80 a, float_status_t &status)
{
if (floatx80_is_unsupported(a))
{
float_raise(status, float_flag_invalid);
return int16_indefinite;
}
Bit32s v32 = floatx80_to_int32_round_to_zero(a, status);
if ((v32 > 32767) || (v32 < -32768)) {
status.float_exception_flags = float_flag_invalid; // throw way other flags
return int16_indefinite;
}
return (Bit16s) v32;
}
/*----------------------------------------------------------------------------
| Separate the source extended double-precision floating point value `a'
| into its exponent and significand, store the significant back to the
| 'a' and return the exponent. The operation performed is a superset of
| the IEC/IEEE recommended logb(x) function.
*----------------------------------------------------------------------------*/
floatx80 floatx80_extract(floatx80 &a, float_status_t &status)
{
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
int aSign = extractFloatx80Sign(a);
if (floatx80_is_unsupported(a))
{
float_raise(status, float_flag_invalid);
a = floatx80_default_nan;
return a;
}
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1))
{
a = propagateFloatx80NaN(a, status);
return a;
}
return packFloatx80(0, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0)
{
if (aSig == 0) {
float_raise(status, float_flag_divbyzero);
a = packFloatx80(aSign, 0, 0);
return packFloatx80(1, 0x7FFF, BX_CONST64(0x8000000000000000));
}
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
}
a.exp = (aSign << 15) + 0x3FFF;
a.fraction = aSig;
return int32_to_floatx80(aExp - 0x3FFF);
}
/*----------------------------------------------------------------------------
| Scales extended double-precision floating-point value in operand `a' by
| value `b'. The function truncates the value in the second operand 'b' to
| an integral value and adds that value to the exponent of the operand 'a'.
| The operation performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status_t &status)
{
Bit32s aExp, bExp;
Bit64u aSig, bSig;
// handle unsupported extended double-precision floating encodings
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b))
{
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
aSig = extractFloatx80Frac(a);
aExp = extractFloatx80Exp(a);
int aSign = extractFloatx80Sign(a);
bSig = extractFloatx80Frac(b);
bExp = extractFloatx80Exp(b);
int bSign = extractFloatx80Sign(b);
if (aExp == 0x7FFF) {
if ((Bit64u) (aSig<<1) || ((bExp == 0x7FFF) && (Bit64u) (bSig<<1)))
{
return propagateFloatx80NaN(a, b, status);
}
if ((bExp == 0x7FFF) && bSign) {
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal);
return a;
}
if (bExp == 0x7FFF) {
if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status);
if ((aExp | aSig) == 0) {
if (! bSign) {
float_raise(status, float_flag_invalid);
return floatx80_default_nan;
}
return a;
}
if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal);
if (bSign) return packFloatx80(aSign, 0, 0);
return packFloatx80(aSign, 0x7FFF, BX_CONST64(0x8000000000000000));
}
if (aExp == 0) {
if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal);
if (aSig == 0) return a;
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
if (bExp < 0x3FFF)
return normalizeRoundAndPackFloatx80(80, aSign, aExp, aSig, 0, status);
}
if (bExp == 0) {
if (bSig == 0) return a;
float_raise(status, float_flag_denormal);
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
}
if (bExp > 0x400E) {
/* generate appropriate overflow/underflow */
return roundAndPackFloatx80(80, aSign,
bSign ? -0x3FFF : 0x7FFF, aSig, 0, status);
}
if (bExp < 0x3FFF) return a;
int shiftCount = 0x403E - bExp;
bSig >>= shiftCount;
Bit32s scale = (Bit32s) bSig;
if (bSign) scale = -scale; /* -32768..32767 */
return
roundAndPackFloatx80(80, aSign, aExp+scale, aSig, 0, status);
}
/*----------------------------------------------------------------------------
| Determine extended-precision floating-point number class.
*----------------------------------------------------------------------------*/
float_class_t floatx80_class(floatx80 a)
{
Bit32s aExp = extractFloatx80Exp(a);
Bit64u aSig = extractFloatx80Frac(a);
if(aExp == 0) {
if (aSig == 0)
return float_zero;
/* denormal or pseudo-denormal */
return float_denormal;
}
/* valid numbers have the MS bit set */
if (!(aSig & BX_CONST64(0x8000000000000000)))
return float_NaN; /* report unsupported as NaNs */
if(aExp == 0x7fff) {
int aSign = extractFloatx80Sign(a);
if (((Bit64u) (aSig<< 1)) == 0)
return (aSign) ? float_negative_inf : float_positive_inf;
return float_NaN;
}
return float_normalized;
}
/*----------------------------------------------------------------------------
| Compare between two extended precision floating point numbers. Returns
| 'float_relation_equal' if the operands are equal, 'float_relation_less' if
| the value 'a' is less than the corresponding value `b',
| 'float_relation_greater' if the value 'a' is greater than the corresponding
| value `b', or 'float_relation_unordered' otherwise.
*----------------------------------------------------------------------------*/
int floatx80_compare(floatx80 a, floatx80 b, float_status_t &status)
{
float_class_t aClass = floatx80_class(a);
float_class_t bClass = floatx80_class(b);
if (aClass == float_NaN || bClass == float_NaN)
{
float_raise(status, float_flag_invalid);
return float_relation_unordered;
}
if (aClass == float_denormal || bClass == float_denormal)
{
float_raise(status, float_flag_denormal);
}
int aSign = extractFloatx80Sign(a);
int bSign = extractFloatx80Sign(b);
if (aClass == float_zero) {
if (bClass == float_zero) return float_relation_equal;
return bSign ? float_relation_greater : float_relation_less;
}
if (bClass == float_zero || aSign != bSign) {
return aSign ? float_relation_less : float_relation_greater;
}
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
Bit64u bSig = extractFloatx80Frac(b);
Bit32s bExp = extractFloatx80Exp(b);
if (aClass == float_denormal)
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
if (bClass == float_denormal)
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
if (aExp == bExp && aSig == bSig)
return float_relation_equal;
int less_than =
aSign ? ((bExp < aExp) || ((bExp == aExp) && (bSig < aSig)))
: ((aExp < bExp) || ((aExp == bExp) && (aSig < bSig)));
if (less_than) return float_relation_less;
return float_relation_greater;
}
/*----------------------------------------------------------------------------
| Compare between two extended precision floating point numbers. Returns
| 'float_relation_equal' if the operands are equal, 'float_relation_less' if
| the value 'a' is less than the corresponding value `b',
| 'float_relation_greater' if the value 'a' is greater than the corresponding
| value `b', or 'float_relation_unordered' otherwise. Quiet NaNs do not cause
| an exception.
*----------------------------------------------------------------------------*/
int floatx80_compare_quiet(floatx80 a, floatx80 b, float_status_t &status)
{
float_class_t aClass = floatx80_class(a);
float_class_t bClass = floatx80_class(b);
if (aClass == float_NaN || bClass == float_NaN)
{
if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b))
float_raise(status, float_flag_invalid);
if (floatx80_is_signaling_nan(a) || floatx80_is_signaling_nan(b))
float_raise(status, float_flag_invalid);
return float_relation_unordered;
}
if (aClass == float_denormal || bClass == float_denormal)
{
float_raise(status, float_flag_denormal);
}
int aSign = extractFloatx80Sign(a);
int bSign = extractFloatx80Sign(b);
if (aClass == float_zero) {
if (bClass == float_zero) return float_relation_equal;
return bSign ? float_relation_greater : float_relation_less;
}
if (bClass == float_zero || aSign != bSign) {
return aSign ? float_relation_less : float_relation_greater;
}
Bit64u aSig = extractFloatx80Frac(a);
Bit32s aExp = extractFloatx80Exp(a);
Bit64u bSig = extractFloatx80Frac(b);
Bit32s bExp = extractFloatx80Exp(b);
if (aClass == float_denormal)
normalizeFloatx80Subnormal(aSig, &aExp, &aSig);
if (bClass == float_denormal)
normalizeFloatx80Subnormal(bSig, &bExp, &bSig);
if (aExp == bExp && aSig == bSig)
return float_relation_equal;
int less_than =
aSign ? ((bExp < aExp) || ((bExp == aExp) && (bSig < aSig)))
: ((aExp < bExp) || ((aExp == bExp) && (aSig < bSig)));
if (less_than) return float_relation_less;
return float_relation_greater;
}

View File

@ -0,0 +1,100 @@
/*============================================================================
This source file is an extension to the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2b, written for Bochs (x86 achitecture simulator)
floating point emulation.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort has
been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT TIMES
RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO PERSONS
AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ALL LOSSES,
COSTS, OR OTHER PROBLEMS THEY INCUR DUE TO THE SOFTWARE, AND WHO FURTHERMORE
EFFECTIVELY INDEMNIFY JOHN HAUSER AND THE INTERNATIONAL COMPUTER SCIENCE
INSTITUTE (possibly via similar legal warning) AGAINST ALL LOSSES, COSTS, OR
OTHER PROBLEMS INCURRED BY THEIR CUSTOMERS AND CLIENTS DUE TO THE SOFTWARE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) the source code for the derivative work includes prominent notice that
the work is derivative, and (2) the source code includes prominent notice with
these four paragraphs for those parts of this code that are retained.
=============================================================================*/
/*============================================================================
* Written for Bochs (x86 achitecture simulator) by
* Stanislav Shwartsman [sshwarts at sourceforge net]
* ==========================================================================*/
#ifndef _SOFTFLOATX80_EXTENSIONS_H_
#define _SOFTFLOATX80_EXTENSIONS_H_
#include "softfloat.h"
#include "softfloat-specialize.h"
/*----------------------------------------------------------------------------
| Software IEC/IEEE integer-to-floating-point conversion routines.
*----------------------------------------------------------------------------*/
Bit16s floatx80_to_int16(floatx80, float_status_t &status);
Bit16s floatx80_to_int16_round_to_zero(floatx80, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision operations.
*----------------------------------------------------------------------------*/
float_class_t floatx80_class(floatx80);
floatx80 floatx80_extract(floatx80 &a, float_status_t &status);
floatx80 floatx80_scale(floatx80 a, floatx80 b, float_status_t &status);
int floatx80_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status);
int floatx80_ieee754_remainder(floatx80 a, floatx80 b, floatx80 &r, Bit64u &q, float_status_t &status);
floatx80 f2xm1(floatx80 a, float_status_t &status);
floatx80 fyl2x(floatx80 a, floatx80 b, float_status_t &status);
floatx80 fyl2xp1(floatx80 a, floatx80 b, float_status_t &status);
floatx80 fpatan(floatx80 a, floatx80 b, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision trigonometric functions.
*----------------------------------------------------------------------------*/
int fsincos(floatx80 a, floatx80 *sin_a, floatx80 *cos_a, float_status_t &status);
int fsin(floatx80 &a, float_status_t &status);
int fcos(floatx80 &a, float_status_t &status);
int ftan(floatx80 &a, float_status_t &status);
/*----------------------------------------------------------------------------
| Software IEC/IEEE extended double-precision compare.
*----------------------------------------------------------------------------*/
int floatx80_compare(floatx80, floatx80, float_status_t &status);
int floatx80_compare_quiet(floatx80, floatx80, float_status_t &status);
/*-----------------------------------------------------------------------------
| Calculates the absolute value of the extended double-precision floating-point
| value `a'. The operation is performed according to the IEC/IEEE Standard
| for Binary Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80& floatx80_abs(floatx80 &reg)
{
reg.exp &= 0x7FFF;
return reg;
}
/*-----------------------------------------------------------------------------
| Changes the sign of the extended double-precision floating-point value 'a'.
| The operation is performed according to the IEC/IEEE Standard for Binary
| Floating-Point Arithmetic.
*----------------------------------------------------------------------------*/
BX_CPP_INLINE floatx80& floatx80_chs(floatx80 &reg)
{
reg.exp ^= 0x8000;
return reg;
}
/*-----------------------------------------------------------------------------
| Commonly used extended double-precision floating-point constants.
*----------------------------------------------------------------------------*/
extern const floatx80 Const_Z;
extern const floatx80 Const_1;
#endif

View File

@ -0,0 +1,69 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef _STATUS_H_
#define _STATUS_H_
/* Status Word */
#define FPU_SW_Backward (0x8000) /* backward compatibility */
#define FPU_SW_C3 (0x4000) /* condition bit 3 */
#define FPU_SW_Top (0x3800) /* top of stack */
#define FPU_SW_C2 (0x0400) /* condition bit 2 */
#define FPU_SW_C1 (0x0200) /* condition bit 1 */
#define FPU_SW_C0 (0x0100) /* condition bit 0 */
#define FPU_SW_Summary (0x0080) /* exception summary */
#define FPU_SW_Stack_Fault (0x0040) /* stack fault */
#define FPU_SW_Precision (0x0020) /* loss of precision */
#define FPU_SW_Underflow (0x0010) /* underflow */
#define FPU_SW_Overflow (0x0008) /* overflow */
#define FPU_SW_Zero_Div (0x0004) /* divide by zero */
#define FPU_SW_Denormal_Op (0x0002) /* denormalized operand */
#define FPU_SW_Invalid (0x0001) /* invalid operation */
#define FPU_SW_CC (FPU_SW_C0|FPU_SW_C1|FPU_SW_C2|FPU_SW_C3)
#define FPU_SW_Exceptions_Mask (0x027f) /* status word exceptions bit mask */
/* Exception flags: */
#define FPU_EX_Precision (0x0020) /* loss of precision */
#define FPU_EX_Underflow (0x0010) /* underflow */
#define FPU_EX_Overflow (0x0008) /* overflow */
#define FPU_EX_Zero_Div (0x0004) /* divide by zero */
#define FPU_EX_Denormal (0x0002) /* denormalized operand */
#define FPU_EX_Invalid (0x0001) /* invalid operation */
/* Special exceptions: */
#define FPU_EX_Stack_Overflow (0x0041|FPU_SW_C1) /* stack overflow */
#define FPU_EX_Stack_Underflow (0x0041) /* stack underflow */
/* precision control */
#define FPU_EX_Precision_Lost_Up (EX_Precision | SW_C1)
#define FPU_EX_Precision_Lost_Dn (EX_Precision)
#define setcc(cc) \
FPU_PARTIAL_STATUS = (FPU_PARTIAL_STATUS & ~(FPU_SW_CC)) | ((cc) & FPU_SW_CC)
#define clear_C1() { FPU_PARTIAL_STATUS &= ~FPU_SW_C1; }
#define clear_C2() { FPU_PARTIAL_STATUS &= ~FPU_SW_C2; }
#endif

33
simulators/bochs/fpu/tag_w.h Executable file
View File

@ -0,0 +1,33 @@
/////////////////////////////////////////////////////////////////////////
// $Id$
/////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003-2009 Stanislav Shwartsman
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
/////////////////////////////////////////////////////////////////////////
#ifndef _TAG_W_H
#define _TAG_W_H
/* Tag Word */
#define FPU_Tag_Valid 0x00
#define FPU_Tag_Zero 0x01
#define FPU_Tag_Special 0x02
#define FPU_Tag_Empty 0x03
#endif

7
simulators/bochs/fpu/todo Executable file
View File

@ -0,0 +1,7 @@
TODO:
----
Elliminate floa128 use, Intel uses only 67-bit precision calculations
when float128 has at least 112-bit. Replacement of float128 with for
example 96-bit precision number could significantly speed up
calculations.