2004-04-09 19:34:59 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2011-02-25 01:05:47 +03:00
|
|
|
// $Id$
|
2005-03-21 00:19:38 +03:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2004-04-09 19:34:59 +04:00
|
|
|
//
|
2018-02-16 10:57:32 +03:00
|
|
|
// Copyright (c) 2003-2018 Stanislav Shwartsman
|
2007-03-24 00:27:13 +03:00
|
|
|
// Written by Stanislav Shwartsman [sshwarts at sourceforge net]
|
2004-04-09 19:34:59 +04:00
|
|
|
//
|
|
|
|
// 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
|
2009-02-08 20:29:34 +03:00
|
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
2005-05-12 22:07:48 +04:00
|
|
|
//
|
2004-06-18 19:14:50 +04:00
|
|
|
/////////////////////////////////////////////////////////////////////////
|
2004-04-09 19:34:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
#define NEED_CPU_REG_SHORTCUTS 1
|
|
|
|
#include "bochs.h"
|
2006-03-07 01:03:16 +03:00
|
|
|
#include "cpu/cpu.h"
|
2004-04-09 19:34:59 +04:00
|
|
|
#define LOG_THIS BX_CPU_THIS_PTR
|
|
|
|
|
2006-03-07 01:03:16 +03:00
|
|
|
#include "iodev/iodev.h"
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
#define CHECK_PENDING_EXCEPTIONS 1
|
|
|
|
|
2004-04-09 19:34:59 +04:00
|
|
|
#if BX_SUPPORT_FPU
|
2021-01-30 11:35:35 +03:00
|
|
|
void BX_CPU_C::prepareFPU(bxInstruction_c *i, bool check_pending_exceptions)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2007-07-09 19:16:14 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_EM() || BX_CPU_THIS_PTR cr0.get_TS())
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_NM_EXCEPTION, 0);
|
2004-06-18 19:14:50 +04:00
|
|
|
|
|
|
|
if (check_pending_exceptions)
|
|
|
|
BX_CPU_THIS_PTR FPU_check_pending_exceptions();
|
2009-04-27 18:00:55 +04:00
|
|
|
}
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2009-04-27 18:00:55 +04:00
|
|
|
void BX_CPU_C::FPU_update_last_instruction(bxInstruction_c *i)
|
|
|
|
{
|
2017-05-05 23:56:13 +03:00
|
|
|
// when FOPCODE deprecation is set, FOPCODE is updated only when unmasked x87 exception occurs
|
|
|
|
if (! is_cpu_extension_supported(BX_ISA_FOPCODE_DEPRECATION))
|
|
|
|
BX_CPU_THIS_PTR the_i387.foo = i->foo();
|
|
|
|
|
2009-04-27 18:00:55 +04:00
|
|
|
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;
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2017-05-05 23:56:13 +03:00
|
|
|
// when FOPCODE deprecation is set, FCS/FDP are updated only when unmasked x87 exception occurs
|
|
|
|
if (! is_cpu_extension_supported(BX_ISA_FDP_DEPRECATION)) {
|
|
|
|
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);
|
|
|
|
}
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BX_CPU_C::FPU_check_pending_exceptions(void)
|
|
|
|
{
|
2004-06-18 19:14:50 +04:00
|
|
|
if(BX_CPU_THIS_PTR the_i387.get_partial_status() & FPU_SW_Summary)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2006-09-08 15:26:04 +04:00
|
|
|
// 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.
|
2005-08-13 21:40:41 +04:00
|
|
|
#if BX_CPU_LEVEL >= 4
|
2007-07-09 19:16:14 +04:00
|
|
|
if (BX_CPU_THIS_PTR cr0.get_NE() != 0) {
|
2010-03-14 18:51:27 +03:00
|
|
|
exception(BX_MF_EXCEPTION, 0);
|
2006-09-08 15:26:04 +04:00
|
|
|
}
|
|
|
|
else
|
2005-08-13 21:40:41 +04:00
|
|
|
#endif
|
2006-09-08 15:26:04 +04:00
|
|
|
{
|
|
|
|
// MSDOS compatibility external interrupt (IRQ13)
|
2010-11-11 18:48:56 +03:00
|
|
|
BX_INFO(("math_abort: MSDOS compatibility FPU exception"));
|
2006-09-08 15:26:04 +04:00
|
|
|
DEV_pic_raise_irq(13);
|
|
|
|
}
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-23 00:21:36 +04:00
|
|
|
Bit16u BX_CPU_C::x87_get_FCS(void)
|
|
|
|
{
|
2014-08-31 23:22:41 +04:00
|
|
|
if (is_cpu_extension_supported(BX_ISA_FCS_FDS_DEPRECATION))
|
2013-08-23 00:21:36 +04:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return BX_CPU_THIS_PTR the_i387.fcs;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bit16u BX_CPU_C::x87_get_FDS(void)
|
|
|
|
{
|
2014-08-31 23:22:41 +04:00
|
|
|
if (is_cpu_extension_supported(BX_ISA_FCS_FDS_DEPRECATION))
|
2013-08-23 00:21:36 +04:00
|
|
|
return 0;
|
|
|
|
else
|
|
|
|
return BX_CPU_THIS_PTR the_i387.fds;
|
|
|
|
}
|
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
bx_address BX_CPU_C::fpu_save_environment(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2008-09-13 00:59:31 +04:00
|
|
|
unsigned offset;
|
|
|
|
|
2008-05-06 01:23:33 +04:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-17 00:06:59 +03:00
|
|
|
bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
bx_address asize_mask = i->asize_mask();
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
if (protected_mode()) /* Protected Mode */
|
|
|
|
{
|
|
|
|
if (i->os32L() || i->os64L())
|
|
|
|
{
|
|
|
|
Bit32u tmp;
|
|
|
|
|
|
|
|
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
|
2008-09-13 00:59:31 +04:00
|
|
|
write_virtual_dword(i->seg(), eaddr, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
|
2008-04-26 16:14:58 +04:00
|
|
|
tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
|
2013-08-23 00:21:36 +04:00
|
|
|
tmp = x87_get_FCS() | ((Bit32u)(BX_CPU_THIS_PTR the_i387.foo)) << 16;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask, tmp);
|
2008-04-26 16:14:58 +04:00
|
|
|
tmp = (Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask, tmp);
|
2013-08-23 00:21:36 +04:00
|
|
|
tmp = 0xffff0000 | x87_get_FDS();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
offset = 0x1c;
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
|
|
|
else /* Protected Mode - 16 bit */
|
|
|
|
{
|
|
|
|
Bit16u tmp;
|
|
|
|
|
|
|
|
tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
|
2008-09-13 00:59:31 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
|
2007-12-26 21:39:15 +03:00
|
|
|
tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fip) & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask, tmp);
|
2013-08-23 00:21:36 +04:00
|
|
|
tmp = x87_get_FCS();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
|
2007-12-26 21:39:15 +03:00
|
|
|
tmp = (Bit16u)(BX_CPU_THIS_PTR the_i387.fdp) & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask, tmp);
|
2013-08-23 00:21:36 +04:00
|
|
|
tmp = x87_get_FDS();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2008-09-18 23:10:23 +04:00
|
|
|
offset = 0x0e;
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* Real or V86 Mode */
|
|
|
|
{
|
2013-08-23 00:21:36 +04:00
|
|
|
Bit32u fp_ip = ((Bit32u) x87_get_FCS() << 4) +
|
2007-12-23 20:21:28 +03:00
|
|
|
(Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
|
2013-08-23 00:21:36 +04:00
|
|
|
Bit32u fp_dp = ((Bit32u) x87_get_FDS() << 4) +
|
2007-12-23 20:21:28 +03:00
|
|
|
(Bit32u)(BX_CPU_THIS_PTR the_i387.fdp);
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
if (i->os32L())
|
2004-06-18 19:14:50 +04:00
|
|
|
{
|
|
|
|
Bit32u tmp;
|
2008-02-06 01:33:35 +03:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_control_word();
|
2008-09-13 00:59:31 +04:00
|
|
|
write_virtual_dword(i->seg(), eaddr, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_status_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | BX_CPU_THIS_PTR the_i387.get_tag_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | (fp_ip & 0xffff);
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
|
2008-04-26 16:14:58 +04:00
|
|
|
tmp = ((fp_ip & 0xffff0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = 0xffff0000 | (fp_dp & 0xffff);
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = (fp_dp & 0xffff0000) >> 4;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
offset = 0x1c;
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
|
|
|
else /* Real or V86 Mode - 16 bit */
|
|
|
|
{
|
|
|
|
Bit16u tmp;
|
|
|
|
|
|
|
|
tmp = BX_CPU_THIS_PTR the_i387.get_control_word();
|
2008-09-13 00:59:31 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = BX_CPU_THIS_PTR the_i387.get_status_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = BX_CPU_THIS_PTR the_i387.get_tag_word();
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = fp_ip & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask, tmp);
|
2008-04-26 16:14:58 +04:00
|
|
|
tmp = (Bit16u)((fp_ip & 0xf0000) >> 4) | BX_CPU_THIS_PTR the_i387.foo;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = fp_dp & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
tmp = (Bit16u)((fp_dp & 0xf0000) >> 4);
|
2010-10-19 02:19:45 +04:00
|
|
|
write_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask, tmp);
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
offset = 0x0e;
|
2008-02-06 01:33:35 +03:00
|
|
|
}
|
|
|
|
}
|
2008-09-13 00:59:31 +04:00
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
return (eaddr + offset) & asize_mask;
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
bx_address BX_CPU_C::fpu_load_environment(bxInstruction_c *i)
|
2004-06-18 19:14:50 +04:00
|
|
|
{
|
2008-09-13 00:59:31 +04:00
|
|
|
unsigned offset;
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2015-05-17 00:06:59 +03:00
|
|
|
bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
bx_address asize_mask = i->asize_mask();
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
if (protected_mode()) /* Protected Mode */
|
|
|
|
{
|
|
|
|
if (i->os32L() || i->os64L())
|
|
|
|
{
|
|
|
|
Bit32u tmp;
|
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fds = tmp & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fdp = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask);
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.fcs = tmp & 0xffff;
|
|
|
|
BX_CPU_THIS_PTR the_i387.foo = (tmp >> 16) & 0x07ff;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fip = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
|
2010-10-17 20:24:33 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
|
2009-11-17 23:43:41 +03:00
|
|
|
tmp = read_virtual_dword(i->seg(), eaddr);
|
|
|
|
BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
|
2004-06-18 19:14:50 +04:00
|
|
|
offset = 0x1c;
|
|
|
|
}
|
|
|
|
else /* Protected Mode - 16 bit */
|
|
|
|
{
|
|
|
|
Bit16u tmp;
|
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fds = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fdp = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fcs = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fip = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask);
|
2009-11-17 23:43:41 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.twd = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask);
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.swd = tmp;
|
2010-10-17 20:24:33 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
|
2009-11-17 23:43:41 +03:00
|
|
|
tmp = read_virtual_word(i->seg(), eaddr);
|
|
|
|
BX_CPU_THIS_PTR the_i387.cwd = tmp;
|
2004-06-18 19:14:50 +04:00
|
|
|
/* opcode is defined to be zero */
|
|
|
|
BX_CPU_THIS_PTR the_i387.foo = 0;
|
|
|
|
offset = 0x0e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* Real or V86 Mode */
|
|
|
|
{
|
2009-11-17 23:57:15 +03:00
|
|
|
Bit32u fp_ip, fp_dp;
|
2004-06-18 19:14:50 +04:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
if (i->os32L())
|
2004-06-18 19:14:50 +04:00
|
|
|
{
|
|
|
|
Bit32u tmp;
|
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x18) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
fp_dp = (tmp & 0x0ffff000) << 4;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x14) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
fp_dp |= tmp & 0xffff;
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.fdp = fp_dp;
|
|
|
|
BX_CPU_THIS_PTR the_i387.fds = 0;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x10) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
|
|
|
|
fp_ip = (tmp & 0x0ffff000) << 4;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x0c) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
fp_ip |= tmp & 0xffff;
|
|
|
|
BX_CPU_THIS_PTR the_i387.fip = fp_ip;
|
|
|
|
BX_CPU_THIS_PTR the_i387.fcs = 0;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x08) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.twd = tmp & 0xffff;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_dword(i->seg(), (eaddr + 0x04) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.swd = tmp & 0xffff;
|
2010-10-17 20:24:33 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
|
2009-11-17 23:57:15 +03:00
|
|
|
tmp = read_virtual_dword(i->seg(), eaddr);
|
|
|
|
BX_CPU_THIS_PTR the_i387.cwd = tmp & 0xffff;
|
2004-06-18 19:14:50 +04:00
|
|
|
offset = 0x1c;
|
|
|
|
}
|
|
|
|
else /* Real or V86 Mode - 16 bit */
|
|
|
|
{
|
|
|
|
Bit16u tmp;
|
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x0c) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
fp_dp = (tmp & 0xf000) << 4;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x0a) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fdp = fp_dp | tmp;
|
|
|
|
BX_CPU_THIS_PTR the_i387.fds = 0;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x08) & asize_mask);
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.foo = tmp & 0x07ff;
|
2009-11-17 23:57:15 +03:00
|
|
|
fp_ip = (tmp & 0xf000) << 4;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x06) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.fip = fp_ip | tmp;
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.fcs = 0;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x04) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.twd = tmp;
|
2010-10-19 02:19:45 +04:00
|
|
|
tmp = read_virtual_word(i->seg(), (eaddr + 0x02) & asize_mask);
|
2009-11-17 23:57:15 +03:00
|
|
|
BX_CPU_THIS_PTR the_i387.swd = tmp;
|
2010-10-17 20:24:33 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.tos = (tmp >> 11) & 0x7;
|
2009-11-17 23:57:15 +03:00
|
|
|
tmp = read_virtual_word(i->seg(), eaddr);
|
|
|
|
BX_CPU_THIS_PTR the_i387.cwd = tmp;
|
2004-06-18 19:14:50 +04:00
|
|
|
offset = 0x0e;
|
|
|
|
}
|
|
|
|
}
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2008-05-06 01:23:33 +04:00
|
|
|
/* 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;
|
2008-04-27 00:24:20 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* 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;
|
|
|
|
}
|
2009-10-27 23:03:35 +03:00
|
|
|
else {
|
2004-06-18 19:14:50 +04:00
|
|
|
/* clear the B and ES bits in the status-word */
|
|
|
|
FPU_PARTIAL_STATUS &= ~(FPU_SW_Summary | FPU_SW_Backward);
|
|
|
|
}
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2010-10-19 02:19:45 +04:00
|
|
|
return (eaddr + offset) & asize_mask;
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* D9 /5 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDCW(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2015-05-17 00:06:59 +03:00
|
|
|
bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
Bit16u cwd = read_virtual_word(i->seg(), eaddr);
|
2008-05-06 01:23:33 +04:00
|
|
|
FPU_CONTROL_WORD = (cwd & ~FPU_CW_Reserved_Bits) | 0x0040; // bit 6 is reserved as '1
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* 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);
|
|
|
|
}
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* D9 /7 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTCW(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
Bit16u cwd = BX_CPU_THIS_PTR the_i387.get_control_word();
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2015-05-17 00:06:59 +03:00
|
|
|
bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, cwd);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* DD /7 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
Bit16u swd = BX_CPU_THIS_PTR the_i387.get_status_word();
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2015-05-17 00:06:59 +03:00
|
|
|
bx_address eaddr = BX_CPU_RESOLVE_ADDR(i);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-08-08 13:22:49 +04:00
|
|
|
write_virtual_word(i->seg(), eaddr, swd);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* DF E0 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTSW_AX(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2004-06-18 19:14:50 +04:00
|
|
|
AX = BX_CPU_THIS_PTR the_i387.get_status_word();
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* DD /4 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FRSTOR(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-11-17 23:57:15 +03:00
|
|
|
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
|
2008-01-10 22:37:56 +03:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
bx_address offset = fpu_load_environment(i);
|
2008-04-28 00:43:38 +04:00
|
|
|
floatx80 tmp;
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2008-04-28 00:43:38 +04:00
|
|
|
/* read all registers in stack order */
|
2004-06-18 19:14:50 +04:00
|
|
|
for(int n=0;n<8;n++)
|
|
|
|
{
|
2010-10-19 02:19:45 +04:00
|
|
|
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());
|
2008-06-12 23:14:40 +04:00
|
|
|
|
2008-04-28 00:43:38 +04:00
|
|
|
// 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);
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* DD /6 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSAVE(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2008-09-13 00:59:31 +04:00
|
|
|
bx_address offset = fpu_save_environment(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* save all registers in stack order. */
|
|
|
|
for(int n=0;n<8;n++)
|
|
|
|
{
|
|
|
|
floatx80 stn = BX_READ_FPU_REG(n);
|
2010-10-19 02:19:45 +04:00
|
|
|
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);
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.init();
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* 9B E2 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNCLEX(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
FPU_PARTIAL_STATUS &= ~(FPU_SW_Backward|FPU_SW_Summary|FPU_SW_Stack_Fault|FPU_SW_Precision|
|
2009-03-11 00:43:11 +03:00
|
|
|
FPU_SW_Underflow|FPU_SW_Overflow|FPU_SW_Zero_Div|FPU_SW_Denormal_Op|
|
|
|
|
FPU_SW_Invalid);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
// do not update last fpu instruction pointer
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* DB E3 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNINIT(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2004-06-18 19:14:50 +04:00
|
|
|
BX_CPU_THIS_PTR the_i387.init();
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* D9 /4 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FLDENV(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
|
2006-01-29 00:31:20 +03:00
|
|
|
fpu_load_environment(i);
|
2008-04-27 00:24:20 +04:00
|
|
|
|
2008-05-06 01:23:33 +04:00
|
|
|
/* read all registers in stack order and update x87 tag word */
|
|
|
|
for(int n=0;n<8;n++) {
|
2008-04-27 00:24:20 +04:00
|
|
|
// update tag only if it is not empty
|
2008-05-06 01:23:33 +04:00
|
|
|
if (! IS_TAG_EMPTY(n)) {
|
2008-04-27 00:24:20 +04:00
|
|
|
int tag = FPU_tagof(BX_READ_FPU_REG(n));
|
|
|
|
BX_CPU_THIS_PTR the_i387.FPU_settagi(tag, n);
|
|
|
|
}
|
|
|
|
}
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* D9 /6 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNSTENV(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2004-06-18 19:14:50 +04:00
|
|
|
fpu_save_environment(i);
|
2006-01-29 20:37:23 +03:00
|
|
|
/* 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);
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
/* D9 D0 */
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FNOP(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, CHECK_PENDING_EXCEPTIONS);
|
|
|
|
FPU_update_last_instruction(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
// 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.
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2018-02-16 10:57:32 +03:00
|
|
|
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPLEGACY(bxInstruction_c *i)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2009-08-22 19:53:06 +04:00
|
|
|
prepareFPU(i, !CHECK_PENDING_EXCEPTIONS);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
// FPU performs no specific operation and no internal x87 states
|
|
|
|
// are affected
|
2011-07-07 00:01:18 +04:00
|
|
|
|
|
|
|
BX_NEXT_INSTR(i);
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
|
|
|
|
2008-04-05 01:05:37 +04:00
|
|
|
#endif
|
2004-04-09 19:34:59 +04:00
|
|
|
|
|
|
|
#if BX_SUPPORT_FPU
|
|
|
|
|
2009-04-12 20:13:49 +04:00
|
|
|
#include "softfloatx80.h"
|
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
#include <math.h>
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2008-03-23 00:29:41 +03:00
|
|
|
void BX_CPU_C::print_state_FPU(void)
|
2004-04-09 19:34:59 +04:00
|
|
|
{
|
2004-06-18 19:14:50 +04:00
|
|
|
static double scale_factor = pow(2.0, -63.0);
|
2009-01-31 00:05:01 +03:00
|
|
|
static const char* cw_round_control[] = {
|
2008-05-06 01:23:33 +04:00
|
|
|
"NEAREST", "DOWN", "UP", "CHOP"
|
|
|
|
};
|
2009-01-31 00:05:01 +03:00
|
|
|
static const char* cw_precision_control[] = {
|
2008-05-06 01:23:33 +04:00
|
|
|
"32", "RES", "64", "80"
|
|
|
|
};
|
2009-04-12 20:13:49 +04:00
|
|
|
static const char* fp_class[] = {
|
2014-03-10 01:42:11 +04:00
|
|
|
"ZERO", "SNAN", "QNAN", "-INF", "+INF", "DENORMAL", "NORMAL"
|
2009-04-12 20:13:49 +04:00
|
|
|
};
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
Bit32u reg;
|
2005-06-19 00:46:08 +04:00
|
|
|
reg = BX_CPU_THIS_PTR the_i387.get_status_word();
|
2008-05-06 01:23:33 +04:00
|
|
|
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");
|
2008-05-20 00:00:42 +04:00
|
|
|
|
|
|
|
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");
|
|
|
|
|
2005-06-19 00:46:08 +04:00
|
|
|
reg = BX_CPU_THIS_PTR the_i387.get_tag_word();
|
2004-06-18 19:14:50 +04:00
|
|
|
fprintf(stderr, "tag word: 0x%04x\n", reg);
|
|
|
|
reg = BX_CPU_THIS_PTR the_i387.foo;
|
|
|
|
fprintf(stderr, "operand: 0x%04x\n", reg);
|
2009-10-27 23:03:35 +03:00
|
|
|
fprintf(stderr, "fip: 0x" FMT_ADDRX "\n",
|
|
|
|
BX_CPU_THIS_PTR the_i387.fip);
|
2004-06-18 19:14:50 +04:00
|
|
|
reg = BX_CPU_THIS_PTR the_i387.fcs;
|
|
|
|
fprintf(stderr, "fcs: 0x%04x\n", reg);
|
2009-10-27 23:03:35 +03:00
|
|
|
fprintf(stderr, "fdp: 0x" FMT_ADDRX "\n",
|
|
|
|
BX_CPU_THIS_PTR the_i387.fdp);
|
2004-06-18 19:14:50 +04:00
|
|
|
reg = BX_CPU_THIS_PTR the_i387.fds;
|
|
|
|
fprintf(stderr, "fds: 0x%04x\n", reg);
|
2004-04-09 19:34:59 +04:00
|
|
|
|
2004-06-18 19:14:50 +04:00
|
|
|
// print stack too
|
2006-01-21 03:05:30 +03:00
|
|
|
int tos = FPU_TOS & 7;
|
2004-06-18 19:14:50 +04:00
|
|
|
for (int i=0; i<8; i++) {
|
|
|
|
const floatx80 &fp = BX_FPU_REG(i);
|
2008-05-10 17:34:01 +04:00
|
|
|
unsigned tag = BX_CPU_THIS_PTR the_i387.FPU_gettagi((i-tos)&7);
|
|
|
|
if (tag != FPU_Tag_Empty) tag = FPU_tagof(fp);
|
2004-06-18 19:14:50 +04:00
|
|
|
double f = pow(2.0, ((0x7fff & fp.exp) - 0x3fff));
|
|
|
|
if (fp.exp & 0x8000) f = -f;
|
2005-01-19 21:21:40 +03:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
f *= (double)(signed __int64)(fp.fraction>>1) * scale_factor * 2;
|
|
|
|
#else
|
2004-06-18 19:14:50 +04:00
|
|
|
f *= fp.fraction*scale_factor;
|
2005-01-19 21:21:40 +03:00
|
|
|
#endif
|
2009-04-12 20:13:49 +04:00
|
|
|
float_class_t f_class = floatx80_class(fp);
|
2014-11-05 21:29:35 +03:00
|
|
|
fprintf(stderr, "%sFP%d ST%d(%c): raw 0x%04x:%08x%08x (%.10f) (%s)\n",
|
2008-05-20 00:00:42 +04:00
|
|
|
i==tos?"=>":" ", i, (i-tos)&7,
|
2008-05-10 17:34:01 +04:00
|
|
|
"v0se"[tag],
|
2008-05-01 00:41:15 +04:00
|
|
|
fp.exp & 0xffff, GET32H(fp.fraction), GET32L(fp.fraction),
|
2014-03-10 01:42:11 +04:00
|
|
|
f, fp_class[f_class]);
|
2004-06-18 19:14:50 +04:00
|
|
|
}
|
2004-04-09 19:34:59 +04:00
|
|
|
}
|
2009-04-12 20:13:49 +04:00
|
|
|
|
2012-02-01 16:07:53 +04:00
|
|
|
#include "softfloat-specialize.h"
|
|
|
|
|
|
|
|
/* -----------------------------------------------------------
|
|
|
|
* Slimmed down version used to compile against a CPU simulator
|
|
|
|
* rather than a kernel (ported by Kevin Lawton)
|
|
|
|
* ------------------------------------------------------------ */
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-04-09 19:34:59 +04:00
|
|
|
#endif
|