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:
178
simulators/bochs/fpu/Makefile.in
Normal file
178
simulators/bochs/fpu/Makefile.in
Normal 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
|
||||
58
simulators/bochs/fpu/control_w.h
Normal file
58
simulators/bochs/fpu/control_w.h
Normal 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
178
simulators/bochs/fpu/f2xm1.cc
Executable 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
133
simulators/bochs/fpu/ferr.cc
Executable 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
283
simulators/bochs/fpu/fpatan.cc
Executable 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
191
simulators/bochs/fpu/fprem.cc
Executable 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
569
simulators/bochs/fpu/fpu.cc
Normal 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
1199
simulators/bochs/fpu/fpu_arith.cc
Executable file
File diff suppressed because it is too large
Load Diff
563
simulators/bochs/fpu/fpu_compare.cc
Executable file
563
simulators/bochs/fpu/fpu_compare.cc
Executable 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
174
simulators/bochs/fpu/fpu_const.cc
Executable 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
|
||||
82
simulators/bochs/fpu/fpu_constant.h
Executable file
82
simulators/bochs/fpu/fpu_constant.h
Executable 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
|
||||
733
simulators/bochs/fpu/fpu_load_store.cc
Executable file
733
simulators/bochs/fpu/fpu_load_store.cc
Executable 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
151
simulators/bochs/fpu/fpu_misc.cc
Executable 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
|
||||
66
simulators/bochs/fpu/fpu_tags.cc
Normal file
66
simulators/bochs/fpu/fpu_tags.cc
Normal 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 ®)
|
||||
{
|
||||
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
436
simulators/bochs/fpu/fpu_trans.cc
Executable 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
431
simulators/bochs/fpu/fsincos.cc
Executable 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
353
simulators/bochs/fpu/fyl2x.cc
Executable 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
105
simulators/bochs/fpu/poly.cc
Executable 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);
|
||||
}
|
||||
496
simulators/bochs/fpu/softfloat-compare.h
Executable file
496
simulators/bochs/fpu/softfloat-compare.h
Executable 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
|
||||
650
simulators/bochs/fpu/softfloat-macros.h
Executable file
650
simulators/bochs/fpu/softfloat-macros.h
Executable 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
|
||||
730
simulators/bochs/fpu/softfloat-round-pack.cc
Executable file
730
simulators/bochs/fpu/softfloat-round-pack.cc
Executable 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
|
||||
260
simulators/bochs/fpu/softfloat-round-pack.h
Executable file
260
simulators/bochs/fpu/softfloat-round-pack.h
Executable 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
|
||||
195
simulators/bochs/fpu/softfloat-specialize.cc
Executable file
195
simulators/bochs/fpu/softfloat-specialize.cc
Executable 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 */
|
||||
619
simulators/bochs/fpu/softfloat-specialize.h
Executable file
619
simulators/bochs/fpu/softfloat-specialize.h
Executable 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
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
339
simulators/bochs/fpu/softfloat.h
Executable 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
|
||||
363
simulators/bochs/fpu/softfloatx80.cc
Executable file
363
simulators/bochs/fpu/softfloatx80.cc
Executable 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;
|
||||
}
|
||||
100
simulators/bochs/fpu/softfloatx80.h
Executable file
100
simulators/bochs/fpu/softfloatx80.h
Executable 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.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.exp ^= 0x8000;
|
||||
return reg;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
| Commonly used extended double-precision floating-point constants.
|
||||
*----------------------------------------------------------------------------*/
|
||||
|
||||
extern const floatx80 Const_Z;
|
||||
extern const floatx80 Const_1;
|
||||
|
||||
#endif
|
||||
69
simulators/bochs/fpu/status_w.h
Normal file
69
simulators/bochs/fpu/status_w.h
Normal 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
33
simulators/bochs/fpu/tag_w.h
Executable 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
7
simulators/bochs/fpu/todo
Executable 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.
|
||||
Reference in New Issue
Block a user