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:
291
simulators/bochs/cpu/3dnow.cc
Executable file
291
simulators/bochs/cpu/3dnow.cc
Executable file
@ -0,0 +1,291 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2002-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_3DNOW
|
||||
|
||||
BX_CPP_INLINE void prepare_softfloat_status_word(float_status_t &status, int rounding_mode)
|
||||
{
|
||||
status.float_exception_flags = 0; // clear exceptions before execution
|
||||
status.float_nan_handling_mode = float_first_operand_nan;
|
||||
status.float_rounding_mode = rounding_mode;
|
||||
status.flush_underflow_to_zero = 0;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFPNACC_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFPNACC_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
/* 0F 0F /r 0C */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PI2FW_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
BxPackedMmxRegister result, op;
|
||||
|
||||
BX_CPU_THIS_PTR prepareMMX();
|
||||
|
||||
/* op is a register or memory reference */
|
||||
if (i->modC0()) {
|
||||
op = BX_READ_MMX_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
|
||||
|
||||
float_status_t status_word;
|
||||
prepare_softfloat_status_word(status_word, float_round_to_zero);
|
||||
|
||||
MMXUD0(result) =
|
||||
int32_to_float32((Bit32s)(MMXSW0(op)), status_word);
|
||||
MMXUD1(result) =
|
||||
int32_to_float32((Bit32s)(MMXSW2(op)), status_word);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_MMX_REG(i->nnn(), result);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 0F 0F /r 0D */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PI2FD_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
BxPackedMmxRegister result, op;
|
||||
|
||||
BX_CPU_THIS_PTR prepareMMX();
|
||||
|
||||
/* op is a register or memory reference */
|
||||
if (i->modC0()) {
|
||||
op = BX_READ_MMX_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
|
||||
|
||||
float_status_t status_word;
|
||||
prepare_softfloat_status_word(status_word, float_round_to_zero);
|
||||
|
||||
MMXUD0(result) =
|
||||
int32_to_float32(MMXSD0(op), status_word);
|
||||
MMXUD1(result) =
|
||||
int32_to_float32(MMXSD1(op), status_word);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_MMX_REG(i->nnn(), result);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PF2IW_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PF2IW_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
/* 0F 0F /r 1D */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PF2ID_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
BxPackedMmxRegister result, op;
|
||||
|
||||
BX_CPU_THIS_PTR prepareMMX();
|
||||
|
||||
/* op is a register or memory reference */
|
||||
if (i->modC0()) {
|
||||
op = BX_READ_MMX_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
|
||||
|
||||
float_status_t status_word;
|
||||
prepare_softfloat_status_word(status_word, float_round_to_zero);
|
||||
|
||||
MMXSD0(result) =
|
||||
float32_to_int32_round_to_zero(MMXUD0(op), status_word);
|
||||
MMXSD1(result) =
|
||||
float32_to_int32_round_to_zero(MMXUD1(op), status_word);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_MMX_REG(i->nnn(), result);
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFNACC_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFNACC_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFCMPGE_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFCMPGE_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFMIN_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFMIN_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRCP_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFRCP_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRSQRT_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFRSQRT_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFSUB_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFSUB_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFADD_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFADD_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFCMPGT_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFCMPGT_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFMAX_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFMAX_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRCPIT1_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFRCPIT1_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRSQIT1_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFRSQIT1_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFSUBR_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFSUBR_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFACC_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFACC_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFCMPEQ_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFCMPEQ_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFMUL_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFMUL_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PFRCPIT2_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
BX_PANIC(("PFRCPIT2_PqQq: 3DNow! instruction still not implemented"));
|
||||
}
|
||||
|
||||
/* 0F 0F /r B7 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PMULHRW_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
BX_CPU_THIS_PTR prepareMMX();
|
||||
|
||||
BxPackedMmxRegister op1 = BX_READ_MMX_REG(i->nnn()), op2, result;
|
||||
|
||||
/* op2 is a register or memory reference */
|
||||
if (i->modC0()) {
|
||||
op2 = BX_READ_MMX_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
MMXUQ(op2) = read_virtual_qword(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
|
||||
|
||||
Bit32s product1 = Bit32s(MMXSW0(op1)) * Bit32s(MMXSW0(op2)) + 0x8000;
|
||||
Bit32s product2 = Bit32s(MMXSW1(op1)) * Bit32s(MMXSW1(op2)) + 0x8000;
|
||||
Bit32s product3 = Bit32s(MMXSW2(op1)) * Bit32s(MMXSW2(op2)) + 0x8000;
|
||||
Bit32s product4 = Bit32s(MMXSW3(op1)) * Bit32s(MMXSW3(op2)) + 0x8000;
|
||||
|
||||
MMXUW0(result) = Bit16u(product1 >> 16);
|
||||
MMXUW1(result) = Bit16u(product2 >> 16);
|
||||
MMXUW2(result) = Bit16u(product3 >> 16);
|
||||
MMXUW3(result) = Bit16u(product4 >> 16);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_MMX_REG(i->nnn(), result);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 0F 0F /r BB */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PSWAPD_PqQq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
BX_CPU_THIS_PTR prepareMMX();
|
||||
|
||||
BxPackedMmxRegister result, op;
|
||||
|
||||
/* op is a register or memory reference */
|
||||
if (i->modC0()) {
|
||||
op = BX_READ_MMX_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
MMXUQ(op) = read_virtual_qword(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR prepareFPU2MMX(); /* FPU2MMX transition */
|
||||
|
||||
MMXUD0(result) = MMXUD1(op);
|
||||
MMXUD1(result) = MMXUD0(op);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_MMX_REG(i->nnn(), result);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
773
simulators/bochs/cpu/Makefile.in
Normal file
773
simulators/bochs/cpu/Makefile.in
Normal file
@ -0,0 +1,773 @@
|
||||
# Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
|
||||
|
||||
@SUFFIX_LINE@
|
||||
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
top_builddir = ..
|
||||
top_srcdir = @top_srcdir@
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
CXX = @CXX@
|
||||
CXXFLAGS = @CXXFLAGS@ @GUI_CXXFLAGS@
|
||||
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBS = @LIBS@
|
||||
X_LIBS = @X_LIBS@
|
||||
X_PRE_LIBS = @X_PRE_LIBS@
|
||||
RANLIB = @RANLIB@
|
||||
|
||||
|
||||
|
||||
BX_INCDIRS = -I.. -I$(srcdir)/.. -I../@INSTRUMENT_DIR@ -I$(srcdir)/../@INSTRUMENT_DIR@
|
||||
|
||||
# Objects which are synced between the cpu and cpu64 code and
|
||||
# are used for either compile.
|
||||
OBJS = \
|
||||
init.o \
|
||||
cpu.o \
|
||||
icache.o \
|
||||
resolver.o \
|
||||
fetchdecode.o \
|
||||
access.o \
|
||||
access32.o \
|
||||
shift16.o \
|
||||
logical16.o \
|
||||
ctrl_xfer32.o \
|
||||
ctrl_xfer16.o \
|
||||
mmx.o \
|
||||
3dnow.o \
|
||||
fpu_emu.o \
|
||||
sse.o \
|
||||
sse_move.o \
|
||||
sse_pfp.o \
|
||||
sse_rcp.o \
|
||||
sse_string.o \
|
||||
xsave.o \
|
||||
aes.o \
|
||||
vmx.o \
|
||||
vmcs.o \
|
||||
vmexit.o \
|
||||
soft_int.o \
|
||||
apic.o \
|
||||
bcd.o \
|
||||
mult16.o \
|
||||
tasking.o \
|
||||
shift32.o \
|
||||
shift8.o \
|
||||
arith8.o \
|
||||
stack16.o \
|
||||
protect_ctrl.o \
|
||||
mult8.o \
|
||||
load.o \
|
||||
data_xfer8.o \
|
||||
vm8086.o \
|
||||
logical8.o \
|
||||
logical32.o \
|
||||
arith16.o \
|
||||
segment_ctrl.o \
|
||||
data_xfer16.o \
|
||||
data_xfer32.o \
|
||||
exception.o \
|
||||
cpuid.o \
|
||||
proc_ctrl.o \
|
||||
crregs.o \
|
||||
msr.o \
|
||||
smm.o \
|
||||
lazy_flags.o \
|
||||
flag_ctrl_pro.o \
|
||||
stack32.o \
|
||||
debugstuff.o \
|
||||
flag_ctrl.o \
|
||||
mult32.o \
|
||||
arith32.o \
|
||||
jmp_far.o \
|
||||
call_far.o \
|
||||
ret_far.o \
|
||||
iret.o \
|
||||
ctrl_xfer_pro.o \
|
||||
segment_ctrl_pro.o \
|
||||
io.o \
|
||||
crc32.o \
|
||||
bit.o \
|
||||
bit16.o \
|
||||
bit32.o \
|
||||
string.o \
|
||||
paging.o
|
||||
|
||||
# Objects which are only used for x86-64 code
|
||||
OBJS64 = \
|
||||
access64.o \
|
||||
arith64.o \
|
||||
ctrl_xfer64.o \
|
||||
data_xfer64.o \
|
||||
fetchdecode64.o \
|
||||
logical64.o \
|
||||
mult64.o \
|
||||
shift64.o \
|
||||
bit64.o \
|
||||
stack64.o
|
||||
|
||||
BX_INCLUDES = ../bochs.h ../config.h
|
||||
|
||||
|
||||
all: libcpu.a
|
||||
|
||||
.@CPP_SUFFIX@.o:
|
||||
$(CXX) @DASH@c $(BX_INCDIRS) $(CXXFLAGS) @CXXFP@$< @OFP@$@
|
||||
|
||||
|
||||
libcpu.a: $(OBJS) @OBJS64@
|
||||
@RMCOMMAND@ libcpu.a
|
||||
@MAKELIB@ $(OBJS) @OBJS64@
|
||||
$(RANLIB) libcpu.a
|
||||
|
||||
$(OBJS): $(BX_INCLUDES)
|
||||
|
||||
$(OBJS64): $(BX_INCLUDES)
|
||||
|
||||
clean:
|
||||
@RMCOMMAND@ *.o
|
||||
@RMCOMMAND@ *.a
|
||||
|
||||
dist-clean: clean
|
||||
@RMCOMMAND@ Makefile
|
||||
|
||||
###########################################
|
||||
# dependencies generated by
|
||||
# gcc -MM -I.. -I../instrument/stubs *.cc | sed 's/\.cc/.@CPP_SUFFIX@/g'
|
||||
###########################################
|
||||
3dnow.o: 3dnow.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
access.o: access.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
access32.o: access32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
access64.o: access64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
aes.o: aes.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
apic.o: apic.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../iodev/iodev.h ../param_names.h
|
||||
arith16.o: arith16.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
arith32.o: arith32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
arith64.o: arith64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
arith8.o: arith8.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
bcd.o: bcd.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
bit.o: bit.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
bit16.o: bit16.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
bit32.o: bit32.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
bit64.o: bit64.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
call_far.o: call_far.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
cpu.o: cpu.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../iodev/iodev.h ../param_names.h
|
||||
cpuid.o: cpuid.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../param_names.h
|
||||
crc32.o: crc32.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
crregs.o: crregs.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
ctrl_xfer16.o: ctrl_xfer16.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
ctrl_xfer32.o: ctrl_xfer32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
ctrl_xfer64.o: ctrl_xfer64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
ctrl_xfer_pro.o: ctrl_xfer_pro.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
data_xfer16.o: data_xfer16.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
data_xfer32.o: data_xfer32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
data_xfer64.o: data_xfer64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
data_xfer8.o: data_xfer8.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
debugstuff.o: debugstuff.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h ../disasm/disasm.h
|
||||
exception.o: exception.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h ../param_names.h \
|
||||
../iodev/iodev.h
|
||||
fetchdecode.o: fetchdecode.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h fetchdecode.h \
|
||||
fetchdecode_x87.h fetchdecode_sse.h
|
||||
fetchdecode64.o: fetchdecode64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h fetchdecode.h \
|
||||
fetchdecode_x87.h fetchdecode_sse.h
|
||||
flag_ctrl.o: flag_ctrl.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
flag_ctrl_pro.o: flag_ctrl_pro.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
fpu_emu.o: fpu_emu.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
icache.o: icache.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
init.o: init.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../param_names.h
|
||||
io.o: io.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../iodev/iodev.h ../param_names.h
|
||||
iret.o: iret.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
jmp_far.o: jmp_far.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
lazy_flags.o: lazy_flags.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
load.o: load.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
logical16.o: logical16.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
logical32.o: logical32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
logical64.o: logical64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
logical8.o: logical8.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
mmx.o: mmx.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
msr.o: msr.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
mult16.o: mult16.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
mult32.o: mult32.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
mult64.o: mult64.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
mult8.o: mult8.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
paging.o: paging.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
proc_ctrl.o: proc_ctrl.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h ../param_names.h cpu.h model_specific.h \
|
||||
crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
protect_ctrl.o: protect_ctrl.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
resolver.o: resolver.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
ret_far.o: ret_far.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
segment_ctrl.o: segment_ctrl.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
segment_ctrl_pro.o: segment_ctrl_pro.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
shift16.o: shift16.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
shift32.o: shift32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
shift64.o: shift64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
shift8.o: shift8.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
smm.o: smm.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h smm.h
|
||||
soft_int.o: soft_int.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
sse.o: sse.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
sse_move.o: sse_move.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
sse_pfp.o: sse_pfp.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h ../fpu/softfloat-compare.h \
|
||||
../fpu/softfloat.h ../fpu/softfloat-specialize.h
|
||||
sse_rcp.o: sse_rcp.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../fpu/softfloat-specialize.h ../fpu/softfloat.h
|
||||
sse_string.o: sse_string.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
stack16.o: stack16.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
stack32.o: stack32.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
stack64.o: stack64.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
string.o: string.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
tasking.o: tasking.@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 ../gui/gui.h \
|
||||
../instrument/stubs/instrument.h cpu.h model_specific.h crregs.h \
|
||||
descriptor.h instr.h ia_opcodes.h lazy_flags.h icache.h apic.h \
|
||||
../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h ../fpu/status_w.h \
|
||||
../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
vm8086.o: vm8086.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
vmcs.o: vmcs.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
vmexit.o: vmexit.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
vmx.o: vmx.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h \
|
||||
../iodev/iodev.h ../param_names.h
|
||||
xsave.o: xsave.@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 ../gui/gui.h ../instrument/stubs/instrument.h cpu.h \
|
||||
model_specific.h crregs.h descriptor.h instr.h ia_opcodes.h lazy_flags.h \
|
||||
icache.h apic.h ../cpu/i387.h ../fpu/softfloat.h ../fpu/tag_w.h \
|
||||
../fpu/status_w.h ../fpu/control_w.h ../cpu/xmm.h vmx.h stack.h
|
||||
503
simulators/bochs/cpu/access.cc
Normal file
503
simulators/bochs/cpu/access.cc
Normal file
@ -0,0 +1,503 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2005-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
bx_address bx_asize_mask[] = {
|
||||
0xffff, // as16 (asize = '00)
|
||||
0xffffffff, // as32 (asize = '01)
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CONST64(0xffffffffffffffff), // as64 (asize = '10)
|
||||
BX_CONST64(0xffffffffffffffff) // as64 (asize = '11)
|
||||
#endif
|
||||
};
|
||||
|
||||
bx_bool BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned length)
|
||||
{
|
||||
Bit32u upper_limit;
|
||||
|
||||
if (seg->cache.valid==0) {
|
||||
BX_DEBUG(("write_virtual_checks(): segment descriptor not valid"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->cache.p == 0) { /* not present */
|
||||
BX_ERROR(("write_virtual_checks(): segment not present"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (seg->cache.type) {
|
||||
case 0: case 1: // read only
|
||||
case 4: case 5: // read only, expand down
|
||||
case 8: case 9: // execute only
|
||||
case 10: case 11: // execute/read
|
||||
case 12: case 13: // execute only, conforming
|
||||
case 14: case 15: // execute/read-only, conforming
|
||||
BX_ERROR(("write_virtual_checks(): no write access to seg"));
|
||||
return 0;
|
||||
|
||||
case 2: case 3: /* read/write */
|
||||
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
||||
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
||||
{
|
||||
BX_ERROR(("write_virtual_checks(): write beyond limit, r/w"));
|
||||
return 0;
|
||||
}
|
||||
if (seg->cache.u.segment.limit_scaled >= 15) {
|
||||
// Mark cache as being OK type for succeeding read/writes. The limit
|
||||
// checks still needs to be done though, but is more simple. We
|
||||
// could probably also optimize that out with a flag for the case
|
||||
// when limit is the maximum 32bit value. Limit should accomodate
|
||||
// at least a dword, since we subtract from it in the simple
|
||||
// limit check in other functions, and we don't want the value to roll.
|
||||
// Only normal segments (not expand down) are handled this way.
|
||||
seg->cache.valid |= SegAccessROK | SegAccessWOK;
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: case 7: /* read/write, expand down */
|
||||
if (seg->cache.u.segment.d_b)
|
||||
upper_limit = 0xffffffff;
|
||||
else
|
||||
upper_limit = 0x0000ffff;
|
||||
if ((offset <= seg->cache.u.segment.limit_scaled) ||
|
||||
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
|
||||
{
|
||||
BX_ERROR(("write_virtual_checks(): write beyond limit, r/w ED"));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("write_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bx_bool BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::read_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned length)
|
||||
{
|
||||
Bit32u upper_limit;
|
||||
|
||||
if (seg->cache.valid==0) {
|
||||
BX_DEBUG(("read_virtual_checks(): segment descriptor not valid"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->cache.p == 0) { /* not present */
|
||||
BX_ERROR(("read_virtual_checks(): segment not present"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (seg->cache.type) {
|
||||
case 0: case 1: /* read only */
|
||||
case 2: case 3: /* read/write */
|
||||
case 10: case 11: /* execute/read */
|
||||
case 14: case 15: /* execute/read-only, conforming */
|
||||
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
||||
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
||||
{
|
||||
BX_ERROR(("read_virtual_checks(): read beyond limit"));
|
||||
return 0;
|
||||
}
|
||||
if (seg->cache.u.segment.limit_scaled >= 15) {
|
||||
// Mark cache as being OK type for succeeding reads. See notes for
|
||||
// write checks; similar code.
|
||||
seg->cache.valid |= SegAccessROK;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: case 5: /* read only, expand down */
|
||||
case 6: case 7: /* read/write, expand down */
|
||||
if (seg->cache.u.segment.d_b)
|
||||
upper_limit = 0xffffffff;
|
||||
else
|
||||
upper_limit = 0x0000ffff;
|
||||
if ((offset <= seg->cache.u.segment.limit_scaled) ||
|
||||
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
|
||||
{
|
||||
BX_ERROR(("read_virtual_checks(): read beyond limit ED"));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8: case 9: /* execute only */
|
||||
case 12: case 13: /* execute only, conforming */
|
||||
/* can't read or write an execute-only segment */
|
||||
BX_ERROR(("read_virtual_checks(): execute only"));
|
||||
return 0;
|
||||
|
||||
default:
|
||||
BX_PANIC(("read_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bx_bool BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::execute_virtual_checks(bx_segment_reg_t *seg, Bit32u offset, unsigned length)
|
||||
{
|
||||
Bit32u upper_limit;
|
||||
|
||||
if (seg->cache.valid==0) {
|
||||
BX_DEBUG(("execute_virtual_checks(): segment descriptor not valid"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (seg->cache.p == 0) { /* not present */
|
||||
BX_ERROR(("execute_virtual_checks(): segment not present"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (seg->cache.type) {
|
||||
case 0: case 1: /* read only */
|
||||
case 2: case 3: /* read/write */
|
||||
case 10: case 11: /* execute/read */
|
||||
case 14: case 15: /* execute/read-only, conforming */
|
||||
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
||||
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
||||
{
|
||||
BX_ERROR(("execute_virtual_checks(): read beyond limit"));
|
||||
return 0;
|
||||
}
|
||||
if (seg->cache.u.segment.limit_scaled >= 15) {
|
||||
// Mark cache as being OK type for succeeding reads. See notes for
|
||||
// write checks; similar code.
|
||||
seg->cache.valid |= SegAccessROK;
|
||||
}
|
||||
break;
|
||||
|
||||
case 8: case 9: /* execute only */
|
||||
case 12: case 13: /* execute only, conforming */
|
||||
if (offset > (seg->cache.u.segment.limit_scaled - length + 1)
|
||||
|| (length-1 > seg->cache.u.segment.limit_scaled))
|
||||
{
|
||||
BX_ERROR(("execute_virtual_checks(): read beyond limit execute only"));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: case 5: /* read only, expand down */
|
||||
case 6: case 7: /* read/write, expand down */
|
||||
if (seg->cache.u.segment.d_b)
|
||||
upper_limit = 0xffffffff;
|
||||
else
|
||||
upper_limit = 0x0000ffff;
|
||||
if ((offset <= seg->cache.u.segment.limit_scaled) ||
|
||||
(offset > upper_limit) || ((upper_limit - offset) < (length - 1)))
|
||||
{
|
||||
BX_ERROR(("execute_virtual_checks(): read beyond limit ED"));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("execute_virtual_checks(): unknown descriptor type=%d", seg->cache.type));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *BX_CPU_C::strseg(bx_segment_reg_t *seg)
|
||||
{
|
||||
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES]) return("ES");
|
||||
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS]) return("CS");
|
||||
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS]) return("SS");
|
||||
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS]) return("DS");
|
||||
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS]) return("FS");
|
||||
else if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS]) return("GS");
|
||||
else {
|
||||
BX_PANIC(("undefined segment passed to strseg()!"));
|
||||
return("??");
|
||||
}
|
||||
}
|
||||
|
||||
int BX_CPU_C::int_number(unsigned s)
|
||||
{
|
||||
if (s == BX_SEG_REG_SS)
|
||||
return BX_SS_EXCEPTION;
|
||||
else
|
||||
return BX_GP_EXCEPTION;
|
||||
}
|
||||
|
||||
Bit8u BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::system_read_byte(bx_address laddr)
|
||||
{
|
||||
Bit8u data;
|
||||
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
bx_address lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_READ);
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
data = *hostAddr;
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 1, 0, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("system_read_byte(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_read_linear(laddr, 1, 0, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit16u BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::system_read_word(bx_address laddr)
|
||||
{
|
||||
Bit16u data;
|
||||
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
|
||||
bx_address lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_READ);
|
||||
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
||||
ReadHostWordFromLittleEndian(hostAddr, data);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 2, 0, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+1)) {
|
||||
BX_ERROR(("system_read_word(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_read_linear(laddr, 2, 0, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit32u BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::system_read_dword(bx_address laddr)
|
||||
{
|
||||
Bit32u data;
|
||||
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
|
||||
bx_address lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_READ);
|
||||
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
||||
ReadHostDWordFromLittleEndian(hostAddr, data);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 4, 0, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+3)) {
|
||||
BX_ERROR(("system_read_dword(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_read_linear(laddr, 4, 0, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit64u BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::system_read_qword(bx_address laddr)
|
||||
{
|
||||
Bit64u data;
|
||||
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
|
||||
bx_address lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_READ);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
ReadHostQWordFromLittleEndian(hostAddr, data);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 8, 0, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+7)) {
|
||||
BX_ERROR(("system_read_qword(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_read_linear(laddr, 8, 0, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::system_write_byte(bx_address laddr, Bit8u data)
|
||||
{
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
Bit32u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & 0x2)) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 1, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 1, 0, BX_WRITE, (Bit8u*) &data);
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 1);
|
||||
*hostAddr = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("system_write_byte(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_write_linear(laddr, 1, 0, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::system_write_word(bx_address laddr, Bit16u data)
|
||||
{
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
|
||||
Bit32u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & 0x2)) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, 0, BX_WRITE, (Bit8u*) &data);
|
||||
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 2);
|
||||
WriteHostWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+1)) {
|
||||
BX_ERROR(("system_write_word(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_write_linear(laddr, 2, 0, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::system_write_dword(bx_address laddr, Bit32u data)
|
||||
{
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
|
||||
Bit32u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & 0x2)) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, 0, BX_WRITE, (Bit8u*) &data);
|
||||
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 4);
|
||||
WriteHostDWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+3)) {
|
||||
BX_ERROR(("system_write_dword(): canonical failure"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
access_write_linear(laddr, 4, 0, (void *) &data);
|
||||
}
|
||||
|
||||
Bit8u* BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::v2h_read_byte(bx_address laddr, bx_bool user)
|
||||
{
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
bx_address lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & user)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
return hostAddr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit8u* BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::v2h_write_byte(bx_address laddr, bx_bool user)
|
||||
{
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
bx_address lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf)
|
||||
{
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | user))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(tlbEntry->ppf);
|
||||
return hostAddr;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
1234
simulators/bochs/cpu/access32.cc
Executable file
1234
simulators/bochs/cpu/access32.cc
Executable file
File diff suppressed because it is too large
Load Diff
920
simulators/bochs/cpu/access64.cc
Executable file
920
simulators/bochs/cpu/access64.cc
Executable file
@ -0,0 +1,920 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_byte_64(unsigned s, Bit64u offset, Bit8u data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 1, BX_WRITE);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 1, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 1, CPL, BX_WRITE, (Bit8u*) &data);
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 1);
|
||||
*hostAddr = data;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_virtual_byte_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 1, CPL, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_word_64(unsigned s, Bit64u offset, Bit16u data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 2, BX_WRITE);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, CPL, BX_WRITE, (Bit8u*) &data);
|
||||
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 2);
|
||||
WriteHostWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_virtual_word_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 1) {
|
||||
BX_ERROR(("write_virtual_word_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+1)) {
|
||||
BX_ERROR(("write_virtual_word_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 2, CPL, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_dword_64(unsigned s, Bit64u offset, Bit32u data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 4, BX_WRITE);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, CPL, BX_WRITE, (Bit8u*) &data);
|
||||
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 4);
|
||||
WriteHostDWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_virtual_dword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 3) {
|
||||
BX_ERROR(("write_virtual_dword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+3)) {
|
||||
BX_ERROR(("write_virtual_dword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 4, CPL, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_qword_64(unsigned s, Bit64u offset, Bit64u data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 8, BX_WRITE);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 8, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 8, CPL, BX_WRITE, (Bit8u*) &data);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 8);
|
||||
WriteHostQWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_virtual_qword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 7) {
|
||||
BX_ERROR(("write_virtual_qword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+7)) {
|
||||
BX_ERROR(("write_virtual_qword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 8, CPL, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_dqword_64(unsigned s, Bit64u offset, const BxPackedXmmRegister *data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_WRITE);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 15);
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 16, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 16, CPL, BX_WRITE, (Bit8u*) data);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 16);
|
||||
WriteHostQWordToLittleEndian(hostAddr, data->xmm64u(0));
|
||||
WriteHostQWordToLittleEndian(hostAddr+1, data->xmm64u(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
|
||||
BX_ERROR(("write_virtual_dqword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 16, CPL, (void *) data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_virtual_dqword_aligned_64(unsigned s, Bit64u offset, const BxPackedXmmRegister *data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_WRITE);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, 15);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 16, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 16, CPL, BX_WRITE, (Bit8u*) data);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 16);
|
||||
WriteHostQWordToLittleEndian(hostAddr, data->xmm64u(0));
|
||||
WriteHostQWordToLittleEndian(hostAddr+1, data->xmm64u(1));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (laddr & 15) {
|
||||
BX_ERROR(("write_virtual_dqword_aligned_64(): #GP misaligned access"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
|
||||
BX_ERROR(("write_virtual_dqword_aligned_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 16, CPL, (void *) data);
|
||||
}
|
||||
|
||||
Bit8u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_virtual_byte_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit8u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 1, BX_READ);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
data = *hostAddr;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 1, BX_READ);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 1, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_virtual_byte_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 1, CPL, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit16u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_virtual_word_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit16u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 2, BX_READ);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
||||
ReadHostWordFromLittleEndian(hostAddr, data);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 2, BX_READ);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 2, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_virtual_word_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 1) {
|
||||
BX_ERROR(("read_virtual_word_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+1)) {
|
||||
BX_ERROR(("read_virtual_word_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 2, CPL, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit32u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_virtual_dword_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit32u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 4, BX_READ);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
||||
ReadHostDWordFromLittleEndian(hostAddr, data);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 4, BX_READ);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 4, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_virtual_dword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 3) {
|
||||
BX_ERROR(("read_virtual_dword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+3)) {
|
||||
BX_ERROR(("read_virtual_dword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 4, CPL, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit64u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_virtual_qword_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit64u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 8, BX_READ);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
ReadHostQWordFromLittleEndian(hostAddr, data);
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 8, BX_READ);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 8, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_virtual_qword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 7) {
|
||||
BX_ERROR(("read_virtual_qword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+7)) {
|
||||
BX_ERROR(("read_virtual_qword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 8, CPL, BX_READ, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::read_virtual_dqword_64(unsigned s, Bit64u offset, BxPackedXmmRegister *data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_READ);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 15);
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
ReadHostQWordFromLittleEndian(hostAddr, data->xmm64u(0));
|
||||
ReadHostQWordFromLittleEndian(hostAddr+1, data->xmm64u(1));
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 16, BX_READ);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 16, CPL, BX_READ, (Bit8u*) data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
|
||||
BX_ERROR(("read_virtual_dqword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 16, CPL, BX_READ, (void *) data);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::read_virtual_dqword_aligned_64(unsigned s, Bit64u offset, BxPackedXmmRegister *data)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 16, BX_READ);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, 15);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us read access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & USER_PL)) { // Read this pl OK.
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
ReadHostQWordFromLittleEndian(hostAddr, data->xmm64u(0));
|
||||
ReadHostQWordFromLittleEndian(hostAddr+1, data->xmm64u(1));
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, tlbEntry->ppf | pageOffset, 16, BX_READ);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr,
|
||||
tlbEntry->ppf | pageOffset, 16, CPL, BX_READ, (Bit8u*) data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (laddr & 15) {
|
||||
BX_ERROR(("read_virtual_dqword_aligned_64(): #GP misaligned access"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr) || ! IsCanonical(laddr+15)) {
|
||||
BX_ERROR(("read_virtual_dqword_aligned_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 16, CPL, BX_READ, (void *) data);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
// special Read-Modify-Write operations //
|
||||
// address translation info is kept across read/write calls //
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
Bit8u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_RMW_virtual_byte_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit8u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 1, BX_RW);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 0);
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
Bit8u *hostAddr = (Bit8u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 1);
|
||||
data = *hostAddr;
|
||||
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 1, BX_RW);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 1, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_RMW_virtual_byte_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 1, CPL, BX_RW, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit16u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_RMW_virtual_word_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit16u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 2, BX_RW);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 2);
|
||||
ReadHostWordFromLittleEndian(hostAddr, data);
|
||||
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_RW);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_RMW_virtual_word_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 1) {
|
||||
BX_ERROR(("read_RMW_virtual_word_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+1)) {
|
||||
BX_ERROR(("read_RMW_virtual_word_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 2, CPL, BX_RW, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit32u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_RMW_virtual_dword_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit32u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 4, BX_RW);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 4);
|
||||
ReadHostDWordFromLittleEndian(hostAddr, data);
|
||||
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_RW);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_RMW_virtual_dword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 3) {
|
||||
BX_ERROR(("read_RMW_virtual_dword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+3)) {
|
||||
BX_ERROR(("read_RMW_virtual_dword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 4, CPL, BX_RW, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
Bit64u BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::read_RMW_virtual_qword_64(unsigned s, Bit64u offset)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
Bit64u data;
|
||||
BX_INSTR_MEM_DATA_ACCESS(BX_CPU_ID, s, offset, 8, BX_RW);
|
||||
|
||||
Bit64u laddr = BX_CPU_THIS_PTR get_laddr64(s, offset);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | USER_PL))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 8);
|
||||
ReadHostQWordFromLittleEndian(hostAddr, data);
|
||||
BX_CPU_THIS_PTR address_xlation.pages = (bx_ptr_equiv_t) hostAddr;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 8, BX_RW);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 8, CPL, BX_READ, (Bit8u*) &data);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("read_RMW_virtual_qword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check()) {
|
||||
if (laddr & 7) {
|
||||
BX_ERROR(("read_RMW_virtual_qword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+7)) {
|
||||
BX_ERROR(("read_RMW_virtual_qword_64(): canonical failure"));
|
||||
exception(int_number(s), 0);
|
||||
}
|
||||
|
||||
access_read_linear(laddr, 8, CPL, BX_RW, (void *) &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void BX_CPU_C::write_new_stack_word_64(Bit64u laddr, unsigned curr_pl, Bit16u data)
|
||||
{
|
||||
bx_bool user = (curr_pl == 3);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 1);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (1 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | user))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 2, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 2, curr_pl, BX_WRITE, (Bit8u*) &data);
|
||||
Bit16u *hostAddr = (Bit16u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 2);
|
||||
WriteHostWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_new_stack_word_64(): canonical failure"));
|
||||
exception(BX_SS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check() && user) {
|
||||
if (laddr & 1) {
|
||||
BX_ERROR(("write_new_stack_word_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+1)) {
|
||||
BX_ERROR(("write_new_stack_word_64(): canonical failure"));
|
||||
exception(BX_SS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 2, curr_pl, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPU_C::write_new_stack_dword_64(Bit64u laddr, unsigned curr_pl, Bit32u data)
|
||||
{
|
||||
bx_bool user = (curr_pl == 3);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 3);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (3 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | user))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 4, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 4, curr_pl, BX_WRITE, (Bit8u*) &data);
|
||||
Bit32u *hostAddr = (Bit32u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 4);
|
||||
WriteHostDWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_new_stack_dword_64(): canonical failure"));
|
||||
exception(BX_SS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check() && user) {
|
||||
if (laddr & 3) {
|
||||
BX_ERROR(("write_new_stack_dword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+3)) {
|
||||
BX_ERROR(("write_new_stack_dword_64(): canonical failure"));
|
||||
exception(BX_SS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 4, curr_pl, (void *) &data);
|
||||
}
|
||||
|
||||
void BX_CPU_C::write_new_stack_qword_64(Bit64u laddr, unsigned curr_pl, Bit64u data)
|
||||
{
|
||||
bx_bool user = (curr_pl == 3);
|
||||
unsigned tlbIndex = BX_TLB_INDEX_OF(laddr, 7);
|
||||
#if BX_SUPPORT_ALIGNMENT_CHECK && BX_CPU_LEVEL >= 4
|
||||
Bit64u lpf = AlignedAccessLPFOf(laddr, (7 & BX_CPU_THIS_PTR alignment_check_mask));
|
||||
#else
|
||||
Bit64u lpf = LPFOf(laddr);
|
||||
#endif
|
||||
bx_TLB_entry *tlbEntry = &BX_CPU_THIS_PTR TLB.entry[tlbIndex];
|
||||
if (tlbEntry->lpf == lpf) {
|
||||
// See if the TLB entry privilege level allows us write access
|
||||
// from this CPL.
|
||||
if (! (tlbEntry->accessBits & (0x2 | user))) {
|
||||
bx_hostpageaddr_t hostPageAddr = tlbEntry->hostPageAddr;
|
||||
Bit32u pageOffset = PAGE_OFFSET(laddr);
|
||||
bx_phy_address pAddr = tlbEntry->ppf | pageOffset;
|
||||
BX_INSTR_LIN_ACCESS(BX_CPU_ID, laddr, pAddr, 8, BX_WRITE);
|
||||
BX_DBG_LIN_MEMORY_ACCESS(BX_CPU_ID, laddr, pAddr, 8, curr_pl, BX_WRITE, (Bit8u*) &data);
|
||||
Bit64u *hostAddr = (Bit64u*) (hostPageAddr | pageOffset);
|
||||
pageWriteStampTable.decWriteStamp(pAddr, 8);
|
||||
WriteHostQWordToLittleEndian(hostAddr, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (! IsCanonical(laddr)) {
|
||||
BX_ERROR(("write_new_stack_qword_64(): canonical failure"));
|
||||
exception(BX_SS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
if (BX_CPU_THIS_PTR alignment_check() && user) {
|
||||
if (laddr & 7) {
|
||||
BX_ERROR(("write_new_stack_qword_64(): #AC misaligned access"));
|
||||
exception(BX_AC_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! IsCanonical(laddr+7)) {
|
||||
BX_ERROR(("write_new_stack_qword_64(): canonical failure"));
|
||||
exception(BX_SS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
access_write_linear(laddr, 8, curr_pl, (void *) &data);
|
||||
}
|
||||
|
||||
#endif
|
||||
422
simulators/bochs/cpu/aes.cc
Executable file
422
simulators/bochs/cpu/aes.cc
Executable file
@ -0,0 +1,422 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
|
||||
//
|
||||
// XMM - Byte Representation of a 128-bit AES State
|
||||
//
|
||||
// F E D C B A
|
||||
// 1 1 1 1 1 1
|
||||
// 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
|
||||
// --+-+-+-+-+-+-+-+-+-+-+-+-+-+-+--
|
||||
// P O N M L K J I H G F E D C B A
|
||||
//
|
||||
//
|
||||
// XMM - Matrix Representation of a 128-bit AES State
|
||||
//
|
||||
// | A E I M | | S(0,0) S(0,1) S(0,2) S(0,3) | | S(0) S(4) S(8) S(C) |
|
||||
// | B F J N | = | S(1,0) S(1,1) S(1,2) S(1,3) | = | S(1) S(5) S(9) S(D) |
|
||||
// | C G K O | | S(2,0) S(2,1) S(2,2) S(2,3) | | S(2) S(6) S(A) S(E) |
|
||||
// | D H L P | | S(3,0) S(3,1) S(2,3) S(3,3) | | S(3) S(7) S(B) S(F) |
|
||||
//
|
||||
|
||||
//
|
||||
// AES ShiftRows transformation
|
||||
//
|
||||
// | A E I M | | A E I M |
|
||||
// | B F J N | => | F J N B |
|
||||
// | C G K O | | K O C G |
|
||||
// | D H L P | | P D H L |
|
||||
//
|
||||
|
||||
BX_CPP_INLINE void AES_ShiftRows(BxPackedXmmRegister &state)
|
||||
{
|
||||
BxPackedXmmRegister tmp = state;
|
||||
|
||||
state.xmmubyte(0x0) = tmp.xmmubyte(0x0); // A => A
|
||||
state.xmmubyte(0x1) = tmp.xmmubyte(0x5);
|
||||
state.xmmubyte(0x2) = tmp.xmmubyte(0xA);
|
||||
state.xmmubyte(0x3) = tmp.xmmubyte(0xF);
|
||||
state.xmmubyte(0x4) = tmp.xmmubyte(0x4); // E => E
|
||||
state.xmmubyte(0x5) = tmp.xmmubyte(0x9);
|
||||
state.xmmubyte(0x6) = tmp.xmmubyte(0xE);
|
||||
state.xmmubyte(0x7) = tmp.xmmubyte(0x3);
|
||||
state.xmmubyte(0x8) = tmp.xmmubyte(0x8); // I => I
|
||||
state.xmmubyte(0x9) = tmp.xmmubyte(0xD);
|
||||
state.xmmubyte(0xA) = tmp.xmmubyte(0x2);
|
||||
state.xmmubyte(0xB) = tmp.xmmubyte(0x7);
|
||||
state.xmmubyte(0xC) = tmp.xmmubyte(0xC); // M => M
|
||||
state.xmmubyte(0xD) = tmp.xmmubyte(0x1);
|
||||
state.xmmubyte(0xE) = tmp.xmmubyte(0x6);
|
||||
state.xmmubyte(0xF) = tmp.xmmubyte(0xB);
|
||||
}
|
||||
|
||||
//
|
||||
// AES InverseShiftRows transformation
|
||||
//
|
||||
// | A E I M | | A E I M |
|
||||
// | B F J N | => | N B F J |
|
||||
// | C G K O | | K O C G |
|
||||
// | D H L P | | H L P D |
|
||||
//
|
||||
|
||||
BX_CPP_INLINE void AES_InverseShiftRows(BxPackedXmmRegister &state)
|
||||
{
|
||||
BxPackedXmmRegister tmp = state;
|
||||
|
||||
state.xmmubyte(0x0) = tmp.xmmubyte(0x0); // A => A
|
||||
state.xmmubyte(0x1) = tmp.xmmubyte(0xD);
|
||||
state.xmmubyte(0x2) = tmp.xmmubyte(0xA);
|
||||
state.xmmubyte(0x3) = tmp.xmmubyte(0x7);
|
||||
state.xmmubyte(0x4) = tmp.xmmubyte(0x4); // E => E
|
||||
state.xmmubyte(0x5) = tmp.xmmubyte(0x1);
|
||||
state.xmmubyte(0x6) = tmp.xmmubyte(0xE);
|
||||
state.xmmubyte(0x7) = tmp.xmmubyte(0xB);
|
||||
state.xmmubyte(0x8) = tmp.xmmubyte(0x8); // I => I
|
||||
state.xmmubyte(0x9) = tmp.xmmubyte(0x5);
|
||||
state.xmmubyte(0xA) = tmp.xmmubyte(0x2);
|
||||
state.xmmubyte(0xB) = tmp.xmmubyte(0xF);
|
||||
state.xmmubyte(0xC) = tmp.xmmubyte(0xC); // M => M
|
||||
state.xmmubyte(0xD) = tmp.xmmubyte(0x9);
|
||||
state.xmmubyte(0xE) = tmp.xmmubyte(0x6);
|
||||
state.xmmubyte(0xF) = tmp.xmmubyte(0x3);
|
||||
}
|
||||
|
||||
static Bit8u sbox_transformation[256] = {
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
|
||||
0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
|
||||
0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
|
||||
0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
|
||||
0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
|
||||
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
|
||||
0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
|
||||
0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
|
||||
0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
|
||||
0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
|
||||
0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
|
||||
0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
|
||||
0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
|
||||
0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
|
||||
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
|
||||
0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
|
||||
0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
static Bit8u inverse_sbox_transformation[256] = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
|
||||
0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
|
||||
0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
|
||||
0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
|
||||
0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
|
||||
0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
|
||||
0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
|
||||
0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
|
||||
0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
|
||||
0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
|
||||
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
|
||||
0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
|
||||
0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
|
||||
0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
|
||||
0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
|
||||
0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
|
||||
0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
BX_CPP_INLINE void AES_SubstituteBytes(BxPackedXmmRegister &state)
|
||||
{
|
||||
for (int i=0; i<16; i++)
|
||||
state.xmmubyte(i) = sbox_transformation[state.xmmubyte(i)];
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void AES_InverseSubstituteBytes(BxPackedXmmRegister &state)
|
||||
{
|
||||
for (int i=0; i<16; i++)
|
||||
state.xmmubyte(i) = inverse_sbox_transformation[state.xmmubyte(i)];
|
||||
}
|
||||
|
||||
/*
|
||||
* Galois Field multiplication of a by b, modulo m.
|
||||
* Just like arithmetic multiplication, except that additions and
|
||||
* subtractions are replaced by XOR.
|
||||
* The code was taken from: http://www.darkside.com.au/ice/index.html
|
||||
*/
|
||||
|
||||
BX_CPP_INLINE unsigned gf_mul(unsigned a, unsigned b)
|
||||
{
|
||||
unsigned res = 0, m = 0x11b;
|
||||
|
||||
while (b) {
|
||||
if (b & 1)
|
||||
res ^= a;
|
||||
|
||||
a <<= 1;
|
||||
b >>= 1;
|
||||
|
||||
if (a >= 256)
|
||||
a ^= m;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#define AES_STATE(s,a,b) (s.xmmubyte((b)*4+(a)))
|
||||
|
||||
static void AES_MixColumns(BxPackedXmmRegister &state)
|
||||
{
|
||||
BxPackedXmmRegister tmp = state;
|
||||
|
||||
for(int j=0; j<4; j++) {
|
||||
AES_STATE(state, 0, j) = gf_mul(0x2, AES_STATE(tmp, 0, j)) ^
|
||||
gf_mul(0x3, AES_STATE(tmp, 1, j)) ^
|
||||
AES_STATE(tmp, 2, j) ^
|
||||
AES_STATE(tmp, 3, j);
|
||||
|
||||
AES_STATE(state, 1, j) = AES_STATE(tmp, 0, j) ^
|
||||
gf_mul(0x2, AES_STATE(tmp, 1, j)) ^
|
||||
gf_mul(0x3, AES_STATE(tmp, 2, j)) ^
|
||||
AES_STATE(tmp, 3, j);
|
||||
|
||||
AES_STATE(state, 2, j) = AES_STATE(tmp, 0, j) ^
|
||||
AES_STATE(tmp, 1, j) ^
|
||||
gf_mul(0x2, AES_STATE(tmp, 2, j)) ^
|
||||
gf_mul(0x3, AES_STATE(tmp, 3, j));
|
||||
|
||||
AES_STATE(state, 3, j) = gf_mul(0x3, AES_STATE(tmp, 0, j)) ^
|
||||
AES_STATE(tmp, 1, j) ^
|
||||
AES_STATE(tmp, 2, j) ^
|
||||
gf_mul(0x2, AES_STATE(tmp, 3, j));
|
||||
}
|
||||
}
|
||||
|
||||
static void AES_InverseMixColumns(BxPackedXmmRegister &state)
|
||||
{
|
||||
BxPackedXmmRegister tmp = state;
|
||||
|
||||
for(int j=0; j<4; j++) {
|
||||
AES_STATE(state, 0, j) = gf_mul(0xE, AES_STATE(tmp, 0, j)) ^
|
||||
gf_mul(0xB, AES_STATE(tmp, 1, j)) ^
|
||||
gf_mul(0xD, AES_STATE(tmp, 2, j)) ^
|
||||
gf_mul(0x9, AES_STATE(tmp, 3, j));
|
||||
|
||||
AES_STATE(state, 1, j) = gf_mul(0x9, AES_STATE(tmp, 0, j)) ^
|
||||
gf_mul(0xE, AES_STATE(tmp, 1, j)) ^
|
||||
gf_mul(0xB, AES_STATE(tmp, 2, j)) ^
|
||||
gf_mul(0xD, AES_STATE(tmp, 3, j));
|
||||
|
||||
AES_STATE(state, 2, j) = gf_mul(0xD, AES_STATE(tmp, 0, j)) ^
|
||||
gf_mul(0x9, AES_STATE(tmp, 1, j)) ^
|
||||
gf_mul(0xE, AES_STATE(tmp, 2, j)) ^
|
||||
gf_mul(0xB, AES_STATE(tmp, 3, j));
|
||||
|
||||
AES_STATE(state, 3, j) = gf_mul(0xB, AES_STATE(tmp, 0, j)) ^
|
||||
gf_mul(0xD, AES_STATE(tmp, 1, j)) ^
|
||||
gf_mul(0x9, AES_STATE(tmp, 2, j)) ^
|
||||
gf_mul(0xE, AES_STATE(tmp, 3, j));
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPP_INLINE Bit32u AES_SubWord(Bit32u x)
|
||||
{
|
||||
Bit8u b0 = sbox_transformation[(x) & 0xff];
|
||||
Bit8u b1 = sbox_transformation[(x>>8) & 0xff];
|
||||
Bit8u b2 = sbox_transformation[(x>>16) & 0xff];
|
||||
Bit8u b3 = sbox_transformation[(x>>24) & 0xff];
|
||||
|
||||
return b0 | ((Bit32u)(b1) << 8) |
|
||||
((Bit32u)(b2) << 16) | ((Bit32u)(b3) << 24);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE Bit32u AES_RotWord(Bit32u x)
|
||||
{
|
||||
return (x >> 8) | (x << 24);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* 66 0F 38 DB */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESIMC_VdqWdqR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
AES_InverseMixColumns(op);
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 38 DC */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESENC_VdqWdqR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
AES_ShiftRows(op1);
|
||||
AES_SubstituteBytes(op1);
|
||||
AES_MixColumns(op1);
|
||||
|
||||
op1.xmm64u(0) ^= op2.xmm64u(0);
|
||||
op1.xmm64u(1) ^= op2.xmm64u(1);
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 38 DD */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESENCLAST_VdqWdqR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
AES_ShiftRows(op1);
|
||||
AES_SubstituteBytes(op1);
|
||||
|
||||
op1.xmm64u(0) ^= op2.xmm64u(0);
|
||||
op1.xmm64u(1) ^= op2.xmm64u(1);
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 38 DE */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESDEC_VdqWdqR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
AES_InverseShiftRows(op1);
|
||||
AES_InverseSubstituteBytes(op1);
|
||||
AES_InverseMixColumns(op1);
|
||||
|
||||
op1.xmm64u(0) ^= op2.xmm64u(0);
|
||||
op1.xmm64u(1) ^= op2.xmm64u(1);
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 38 DF */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESDECLAST_VdqWdqR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
AES_InverseShiftRows(op1);
|
||||
AES_InverseSubstituteBytes(op1);
|
||||
|
||||
op1.xmm64u(0) ^= op2.xmm64u(0);
|
||||
op1.xmm64u(1) ^= op2.xmm64u(1);
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 3A DF */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AESKEYGENASSIST_VdqWdqIbR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm()), result;
|
||||
|
||||
Bit32u rcon32 = i->Ib();
|
||||
|
||||
result.xmm32u(0) = AES_SubWord(op.xmm32u(1));
|
||||
result.xmm32u(1) = AES_RotWord(result.xmm32u(0)) ^ rcon32;
|
||||
result.xmm32u(2) = AES_SubWord(op.xmm32u(3));
|
||||
result.xmm32u(3) = AES_RotWord(result.xmm32u(2)) ^ rcon32;
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), result);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 3A 44 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCLMULQDQ_VdqWdqIbR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
BxPackedXmmRegister r, a;
|
||||
|
||||
Bit8u imm8 = i->Ib();
|
||||
|
||||
//
|
||||
// Initialize sources for Carry Less Multiplication [R = A CLMUL B]
|
||||
//
|
||||
|
||||
// A determined by imm8[0]
|
||||
a.xmm64u(0) = op1.xmm64u(imm8 & 1);
|
||||
a.xmm64u(1) = 0;
|
||||
|
||||
// B determined by imm8[4]
|
||||
Bit64u b = op2.xmm64u((imm8 >> 4) & 1);
|
||||
|
||||
r.xmm64u(0) = 0;
|
||||
r.xmm64u(1) = 0;
|
||||
|
||||
for (int n = 0; b && n < 64; n++) {
|
||||
if (b & 1) {
|
||||
r.xmm64u(0) ^= a.xmm64u(0);
|
||||
r.xmm64u(1) ^= a.xmm64u(1);
|
||||
}
|
||||
a.xmm64u(1) = (a.xmm64u(1) << 1) | (a.xmm64u(0) >> 63);
|
||||
a.xmm64u(0) <<= 1;
|
||||
b >>= 1;
|
||||
}
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), r);
|
||||
#endif
|
||||
}
|
||||
1188
simulators/bochs/cpu/apic.cc
Normal file
1188
simulators/bochs/cpu/apic.cc
Normal file
File diff suppressed because it is too large
Load Diff
169
simulators/bochs/cpu/apic.h
Normal file
169
simulators/bochs/cpu/apic.h
Normal file
@ -0,0 +1,169 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2002-2009 Zwane Mwaikambo, Stanislav Shwartsman
|
||||
//
|
||||
// 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 BX_CPU_APIC_H
|
||||
#define BX_CPU_APIC_H 1
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
|
||||
#define APIC_LEVEL_TRIGGERED 1
|
||||
#define APIC_EDGE_TRIGGERED 0
|
||||
|
||||
#define BX_LAPIC_BASE_ADDR 0xfee00000 // default Local APIC address
|
||||
#define BX_NUM_LOCAL_APICS BX_SMP_PROCESSORS
|
||||
#define BX_LAPIC_MAX_INTS 256
|
||||
|
||||
#define BX_APIC_GLOBALLY_DISABLED 0
|
||||
#define BX_APIC_STATE_INVALID 1
|
||||
#define BX_APIC_XAPIC_MODE 2
|
||||
#define BX_APIC_X2APIC_MODE 3
|
||||
|
||||
typedef Bit32u apic_dest_t; /* same definition in ioapic.h */
|
||||
|
||||
class BOCHSAPI bx_local_apic_c : public logfunctions
|
||||
{
|
||||
bx_phy_address base_addr;
|
||||
unsigned mode;
|
||||
bx_bool xapic;
|
||||
Bit32u apic_id; // 4 bit in legacy mode, 8 bit in XAPIC mode
|
||||
// 32 bit in X2APIC mode
|
||||
Bit32u apic_version_id;
|
||||
|
||||
bx_bool software_enabled;
|
||||
Bit8u spurious_vector;
|
||||
bx_bool focus_disable;
|
||||
|
||||
Bit32u task_priority; // Task priority (TPR)
|
||||
Bit32u ldr; // Logical destination (LDR)
|
||||
Bit32u dest_format; // Destination format (DFR)
|
||||
|
||||
// ISR=in-service register. When an IRR bit is cleared, the corresponding
|
||||
// bit in ISR is set.
|
||||
Bit8u isr[BX_LAPIC_MAX_INTS];
|
||||
// TMR=trigger mode register. Cleared for edge-triggered interrupts
|
||||
// and set for level-triggered interrupts. If set, local APIC must send
|
||||
// EOI message to all other APICs.
|
||||
Bit8u tmr[BX_LAPIC_MAX_INTS];
|
||||
// IRR=interrupt request register. When an interrupt is triggered by
|
||||
// the I/O APIC or another processor, it sets a bit in irr. The bit is
|
||||
// cleared when the interrupt is acknowledged by the processor.
|
||||
Bit8u irr[BX_LAPIC_MAX_INTS];
|
||||
|
||||
#define APIC_ERR_ILLEGAL_ADDR 0x80
|
||||
#define APIC_ERR_RX_ILLEGAL_VEC 0x40
|
||||
#define APIC_ERR_TX_ILLEGAL_VEC 0x20
|
||||
#define X2APIC_ERR_REDIRECTIBLE_IPI 0x08
|
||||
#define APIC_ERR_RX_ACCEPT_ERR 0x08
|
||||
#define APIC_ERR_TX_ACCEPT_ERR 0x04
|
||||
#define APIC_ERR_RX_CHECKSUM 0x02
|
||||
#define APIC_ERR_TX_CHECKSUM 0x01
|
||||
|
||||
// Error status Register (ESR)
|
||||
Bit32u error_status, shadow_error_status;
|
||||
|
||||
Bit32u icr_hi; // Interrupt command register (ICR)
|
||||
Bit32u icr_lo;
|
||||
|
||||
#define APIC_LVT_ENTRIES 6
|
||||
Bit32u lvt[APIC_LVT_ENTRIES];
|
||||
#define APIC_LVT_TIMER 0
|
||||
#define APIC_LVT_THERMAL 1
|
||||
#define APIC_LVT_PERFMON 2
|
||||
#define APIC_LVT_LINT0 3
|
||||
#define APIC_LVT_LINT1 4
|
||||
#define APIC_LVT_ERROR 5
|
||||
|
||||
Bit32u timer_initial; // Initial timer count
|
||||
Bit32u timer_current; // current timer count
|
||||
|
||||
Bit32u timer_divconf; // Timer divide configuration register
|
||||
Bit32u timer_divide_factor;
|
||||
|
||||
// Internal timer state, not accessible from bus
|
||||
bx_bool timer_active;
|
||||
int timer_handle;
|
||||
Bit64u ticksInitial;
|
||||
|
||||
/* APIC delivery modes */
|
||||
#define APIC_DM_FIXED 0
|
||||
#define APIC_DM_LOWPRI 1
|
||||
#define APIC_DM_SMI 2
|
||||
/* RESERVED 3 */
|
||||
#define APIC_DM_NMI 4
|
||||
#define APIC_DM_INIT 5
|
||||
#define APIC_DM_SIPI 6
|
||||
#define APIC_DM_EXTINT 7
|
||||
|
||||
BX_CPU_C *cpu;
|
||||
|
||||
public:
|
||||
bx_bool INTR;
|
||||
bx_local_apic_c(BX_CPU_C *cpu, unsigned id);
|
||||
~bx_local_apic_c() { }
|
||||
void reset(unsigned type);
|
||||
bx_phy_address get_base(void) const { return base_addr; }
|
||||
void set_base(bx_phy_address newbase);
|
||||
Bit32u get_id() const { return apic_id; }
|
||||
bx_bool is_xapic() const { return xapic; }
|
||||
bx_bool is_selected(bx_phy_address addr);
|
||||
void read(bx_phy_address addr, void *data, unsigned len);
|
||||
void write(bx_phy_address addr, void *data, unsigned len);
|
||||
void write_aligned(bx_phy_address addr, Bit32u data);
|
||||
Bit32u read_aligned(bx_phy_address address);
|
||||
#if BX_SUPPORT_X2APIC
|
||||
bx_bool read_x2apic(unsigned index, Bit64u *msr);
|
||||
bx_bool write_x2apic(unsigned index, Bit64u msr);
|
||||
#endif
|
||||
// on local APIC, trigger means raise the CPU's INTR line. For now
|
||||
// I also have to raise pc_system.INTR but that should be replaced
|
||||
// with the cpu-specific INTR signals.
|
||||
void trigger_irq(Bit8u vector, unsigned trigger_mode, bx_bool bypass_irr_isr = 0);
|
||||
void untrigger_irq(Bit8u vector, unsigned trigger_mode);
|
||||
Bit8u acknowledge_int(void); // only the local CPU should call this
|
||||
int highest_priority_int(Bit8u *array);
|
||||
void receive_EOI(Bit32u value);
|
||||
void send_ipi(apic_dest_t dest, Bit32u lo_cmd);
|
||||
void write_spurious_interrupt_register(Bit32u value);
|
||||
void service_local_apic(void);
|
||||
void print_status(void);
|
||||
bx_bool match_logical_addr(apic_dest_t address);
|
||||
bx_bool deliver(Bit8u vector, Bit8u delivery_mode, Bit8u trig_mode);
|
||||
Bit8u get_tpr(void) { return task_priority; }
|
||||
void set_tpr(Bit8u tpr);
|
||||
Bit8u get_ppr(void);
|
||||
Bit8u get_apr(void);
|
||||
bx_bool is_focus(Bit8u vector);
|
||||
static void periodic_smf(void *);
|
||||
void periodic(void);
|
||||
void set_divide_configuration(Bit32u value);
|
||||
void set_initial_timer_count(Bit32u value);
|
||||
void startup_msg(Bit8u vector);
|
||||
void register_state(bx_param_c *parent);
|
||||
};
|
||||
|
||||
int apic_bus_deliver_lowest_priority(Bit8u vector, apic_dest_t dest, bx_bool trig_mode, bx_bool broadcast);
|
||||
int apic_bus_deliver_interrupt(Bit8u vector, apic_dest_t dest, Bit8u delivery_mode, bx_bool logical_dest, bx_bool level, bx_bool trig_mode);
|
||||
int apic_bus_broadcast_interrupt(Bit8u vector, Bit8u delivery_mode, bx_bool trig_mode, int exclude_cpu);
|
||||
|
||||
#endif // if BX_SUPPORT_APIC
|
||||
|
||||
#endif
|
||||
497
simulators/bochs/cpu/arith16.cc
Normal file
497
simulators/bochs/cpu/arith16.cc
Normal file
@ -0,0 +1,497 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_RX(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u rx = ++BX_READ_16BIT_REG(i->rm());
|
||||
SET_FLAGS_OSZAPC_INC_16(rx);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_RX(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u rx = --BX_READ_16BIT_REG(i->rm());
|
||||
SET_FLAGS_OSZAPC_DEC_16(rx);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
sum_16 = op1_16 + op2_16;
|
||||
write_RMW_virtual_word(sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
sum_16 = op1_16 + op2_16;
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
sum_16 = op1_16 + op2_16;
|
||||
AX = sum_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
sum_16 = op1_16 + op2_16 + temp_CF;
|
||||
write_RMW_virtual_word(sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
sum_16 = op1_16 + op2_16 + temp_CF;
|
||||
BX_WRITE_16BIT_REG(i->nnn(), sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
sum_16 = op1_16 + op2_16 + temp_CF;
|
||||
AX = sum_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
diff_16 = op1_16 - (op2_16 + temp_CF);
|
||||
write_RMW_virtual_word(diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = op1_16 - (op2_16 + temp_CF);
|
||||
BX_WRITE_16BIT_REG(i->nnn(), diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
diff_16 = op1_16 - (op2_16 + temp_CF);
|
||||
AX = diff_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
diff_16 = op1_16 - (op2_16 + temp_CF);
|
||||
write_RMW_virtual_word(diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = op1_16 - (op2_16 + temp_CF);
|
||||
BX_WRITE_16BIT_REG(i->rm(), diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, diff_16, BX_LF_INSTR_SUB_SBB16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
diff_16 = op1_16 - op2_16;
|
||||
write_RMW_virtual_word(diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = op1_16 - op2_16;
|
||||
BX_WRITE_16BIT_REG(i->nnn(), diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
diff_16 = op1_16 - op2_16;
|
||||
AX = diff_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
diff_16 = op1_16 - op2_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = op1_16 - op2_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
diff_16 = op1_16 - op2_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CBW(bxInstruction_c *i)
|
||||
{
|
||||
/* CBW: no flags are effected */
|
||||
AX = (Bit8s) AL;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CWD(bxInstruction_c *i)
|
||||
{
|
||||
/* CWD: no flags are affected */
|
||||
if (AX & 0x8000) {
|
||||
DX = 0xFFFF;
|
||||
}
|
||||
else {
|
||||
DX = 0x0000;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
|
||||
/* XADD dst(r/m), src(r)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
sum_16 = op1_16 + op2_16;
|
||||
write_RMW_virtual_word(sum_16);
|
||||
|
||||
/* and write destination into source */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, sum_16;
|
||||
|
||||
/* XADD dst(r/m), src(r)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
sum_16 = op1_16 + op2_16;
|
||||
|
||||
// and write destination into source
|
||||
// Note: if both op1 & op2 are registers, the last one written
|
||||
// should be the sum, as op1 & op2 may be the same register.
|
||||
// For example: XADD AL, AL
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
BX_WRITE_16BIT_REG(i->rm(), sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
sum_16 = op1_16 + op2_16;
|
||||
write_RMW_virtual_word(sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
sum_16 = op1_16 + op2_16;
|
||||
BX_WRITE_16BIT_REG(i->rm(), sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
sum_16 = op1_16 + op2_16 + temp_CF;
|
||||
write_RMW_virtual_word(sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
Bit16u op1_16, op2_16 = i->Iw(), sum_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
sum_16 = op1_16 + op2_16 + temp_CF;
|
||||
BX_WRITE_16BIT_REG(i->rm(), sum_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_16(op1_16, op2_16, sum_16, BX_LF_INSTR_ADD_ADC16(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
diff_16 = op1_16 - op2_16;
|
||||
write_RMW_virtual_word(diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = op1_16 - op2_16;
|
||||
BX_WRITE_16BIT_REG(i->rm(), diff_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_virtual_word(i->seg(), eaddr);
|
||||
diff_16 = op1_16 - op2_16;
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16 = i->Iw(), diff_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = op1_16 - op2_16;
|
||||
SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16 = - (Bit16s)(op1_16);
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_16(op1_16, BX_LF_INSTR_NEG16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 = - (Bit16s)(op1_16);
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_16(op1_16, BX_LF_INSTR_NEG16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16++;
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_INC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16--;
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_DEC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
diff_16 = AX - op1_16;
|
||||
SET_FLAGS_OSZAPC_SUB_16(AX, op1_16, diff_16);
|
||||
|
||||
if (diff_16 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
write_RMW_virtual_word(op2_16);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
AX = op1_16;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, diff_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
diff_16 = AX - op1_16;
|
||||
SET_FLAGS_OSZAPC_SUB_16(AX, op1_16, diff_16);
|
||||
|
||||
if (diff_16 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
BX_WRITE_16BIT_REG(i->rm(), op2_16);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
AX = op1_16;
|
||||
}
|
||||
}
|
||||
570
simulators/bochs/cpu/arith32.cc
Normal file
570
simulators/bochs/cpu/arith32.cc
Normal file
@ -0,0 +1,570 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier for merging cpu64 and cpu code.
|
||||
#define RAX EAX
|
||||
#define RDX EDX
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_ERX(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u erx = ++BX_READ_32BIT_REG(i->rm());
|
||||
SET_FLAGS_OSZAPC_INC_32(erx);
|
||||
BX_CLEAR_64BIT_HIGH(i->rm());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_ERX(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u erx = --BX_READ_32BIT_REG(i->rm());
|
||||
SET_FLAGS_OSZAPC_DEC_32(erx);
|
||||
BX_CLEAR_64BIT_HIGH(i->rm());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
sum_32 = op1_32 + op2_32;
|
||||
write_RMW_virtual_dword(sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
sum_32 = op1_32 + op2_32;
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32 = i->Id(), sum_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
sum_32 = op1_32 + op2_32;
|
||||
RAX = sum_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
sum_32 = op1_32 + op2_32 + temp_CF;
|
||||
write_RMW_virtual_dword(sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
sum_32 = op1_32 + op2_32 + temp_CF;
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32 = i->Id(), sum_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
sum_32 = op1_32 + op2_32 + temp_CF;
|
||||
RAX = sum_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
diff_32 = op1_32 - (op2_32 + temp_CF);
|
||||
write_RMW_virtual_dword(diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
diff_32 = op1_32 - (op2_32 + temp_CF);
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op2_32 = i->Id();
|
||||
diff_32 = op1_32 - (op2_32 + temp_CF);
|
||||
RAX = diff_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32 = i->Id(), diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
diff_32 = op1_32 - (op2_32 + temp_CF);
|
||||
write_RMW_virtual_dword(diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32 = i->Id(), diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
diff_32 = op1_32 - (op2_32 + temp_CF);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, diff_32, BX_LF_INSTR_SUB_SBB32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
diff_32 = op1_32 - op2_32;
|
||||
write_RMW_virtual_dword(diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
diff_32 = op1_32 - op2_32;
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op2_32 = i->Id();
|
||||
diff_32 = op1_32 - op2_32;
|
||||
RAX = diff_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
diff_32 = op1_32 - op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
diff_32 = op1_32 - op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op2_32 = i->Id();
|
||||
diff_32 = op1_32 - op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CWDE(bxInstruction_c *i)
|
||||
{
|
||||
/* CWDE: no flags are effected */
|
||||
Bit32u tmp = (Bit16s) AX;
|
||||
RAX = tmp;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CDQ(bxInstruction_c *i)
|
||||
{
|
||||
/* CDQ: no flags are affected */
|
||||
if (EAX & 0x80000000) {
|
||||
RDX = 0xFFFFFFFF;
|
||||
}
|
||||
else {
|
||||
RDX = 0x00000000;
|
||||
}
|
||||
}
|
||||
|
||||
// Some info on the opcodes at {0F,A6} and {0F,A7}
|
||||
// On 386 steps A0-B0:
|
||||
// {OF,A6} = XBTS
|
||||
// {OF,A7} = IBTS
|
||||
// On 486 steps A0-B0:
|
||||
// {OF,A6} = CMPXCHG 8
|
||||
// {OF,A7} = CMPXCHG 16|32
|
||||
//
|
||||
// On 486 >= B steps, and further processors, the
|
||||
// CMPXCHG instructions were moved to opcodes:
|
||||
// {OF,B0} = CMPXCHG 8
|
||||
// {OF,B1} = CMPXCHG 16|32
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_XBTS(bxInstruction_c *i)
|
||||
{
|
||||
BX_INFO(("CMPXCHG_XBTS: Generate #UD exception"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_IBTS(bxInstruction_c *i)
|
||||
{
|
||||
BX_INFO(("CMPXCHG_IBTS: Generate #UD exception"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
/* XADD dst(r/m), src(r)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
sum_32 = op1_32 + op2_32;
|
||||
write_RMW_virtual_dword(sum_32);
|
||||
|
||||
/* and write destination into source */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
/* XADD dst(r/m), src(r)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
sum_32 = op1_32 + op2_32;
|
||||
|
||||
// and write destination into source
|
||||
// Note: if both op1 & op2 are registers, the last one written
|
||||
// should be the sum, as op1 & op2 may be the same register.
|
||||
// For example: XADD AL, AL
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = i->Id();
|
||||
sum_32 = op1_32 + op2_32;
|
||||
write_RMW_virtual_dword(sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, sum_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = i->Id();
|
||||
sum_32 = op1_32 + op2_32;
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32 = i->Id(), sum_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
sum_32 = op1_32 + op2_32 + temp_CF;
|
||||
write_RMW_virtual_dword(sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit32u op1_32, op2_32 = i->Id(), sum_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
sum_32 = op1_32 + op2_32 + temp_CF;
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), sum_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_32(op1_32, op2_32, sum_32, BX_LF_INSTR_ADD_ADC32(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32 = i->Id(), diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
diff_32 = op1_32 - op2_32;
|
||||
write_RMW_virtual_dword(diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32 = i->Id(), diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
diff_32 = op1_32 - op2_32;
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), diff_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = i->Id();
|
||||
diff_32 = op1_32 - op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = i->Id();
|
||||
diff_32 = op1_32 - op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32 = - (Bit32s)(op1_32);
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_32(op1_32, BX_LF_INSTR_NEG32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 = - (Bit32s)(op1_32);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_32(op1_32, BX_LF_INSTR_NEG32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32++;
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_INC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32--;
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_DEC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
diff_32 = EAX - op1_32;
|
||||
SET_FLAGS_OSZAPC_SUB_32(EAX, op1_32, diff_32);
|
||||
|
||||
if (diff_32 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
write_RMW_virtual_dword(op2_32);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
RAX = op1_32;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, diff_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
diff_32 = EAX - op1_32;
|
||||
SET_FLAGS_OSZAPC_SUB_32(EAX, op1_32, diff_32);
|
||||
|
||||
if (diff_32 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op2_32);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
RAX = op1_32;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG8B(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
// check write permission for following write
|
||||
op1_64 = read_RMW_virtual_qword(i->seg(), eaddr);
|
||||
op2_64 = ((Bit64u) EDX << 32) | EAX;
|
||||
|
||||
if (op1_64 == op2_64) { // if accumulator == dest
|
||||
// dest <-- src (ECX:EBX)
|
||||
op2_64 = ((Bit64u) ECX << 32) | EBX;
|
||||
write_RMW_virtual_qword(op2_64);
|
||||
assert_ZF();
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
RAX = GET32L(op1_64);
|
||||
RDX = GET32H(op1_64);
|
||||
clear_ZF();
|
||||
}
|
||||
}
|
||||
580
simulators/bochs/cpu/arith64.cc
Normal file
580
simulators/bochs/cpu/arith64.cc
Normal file
@ -0,0 +1,580 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
sum_64 = op1_64 + op2_64;
|
||||
write_RMW_virtual_qword(sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
sum_64 = op1_64 + op2_64;
|
||||
BX_WRITE_64BIT_REG(i->nnn(), sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
sum_64 = op1_64 + op2_64;
|
||||
|
||||
/* now write sum back to destination */
|
||||
RAX = sum_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
sum_64 = op1_64 + op2_64 + temp_CF;
|
||||
write_RMW_virtual_qword(sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
sum_64 = op1_64 + op2_64 + temp_CF;
|
||||
|
||||
/* now write sum back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
sum_64 = op1_64 + op2_64 + temp_CF;
|
||||
|
||||
/* now write sum back to destination */
|
||||
RAX = sum_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
diff_64 = op1_64 - (op2_64 + temp_CF);
|
||||
write_RMW_virtual_qword(diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
diff_64 = op1_64 - (op2_64 + temp_CF);
|
||||
|
||||
/* now write diff back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - (op2_64 + temp_CF);
|
||||
|
||||
/* now write diff back to destination */
|
||||
RAX = diff_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - (op2_64 + temp_CF);
|
||||
write_RMW_virtual_qword(diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - (op2_64 + temp_CF);
|
||||
BX_WRITE_64BIT_REG(i->rm(), diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, diff_64, BX_LF_INSTR_SUB_SBB64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
diff_64 = op1_64 - op2_64;
|
||||
write_RMW_virtual_qword(diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
/* now write diff back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
/* now write diff back to destination */
|
||||
RAX = diff_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CDQE(bxInstruction_c *i)
|
||||
{
|
||||
/* CWDE: no flags are affected */
|
||||
RAX = (Bit32s) EAX;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CQO(bxInstruction_c *i)
|
||||
{
|
||||
/* CQO: no flags are affected */
|
||||
|
||||
if (RAX & BX_CONST64(0x8000000000000000))
|
||||
RDX = BX_CONST64(0xffffffffffffffff);
|
||||
else
|
||||
RDX = 0;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
/* XADD dst(r/m), src(r)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
sum_64 = op1_64 + op2_64;
|
||||
write_RMW_virtual_qword(sum_64);
|
||||
|
||||
/* and write destination into source */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
/* XADD dst(r/m), src(r)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
sum_64 = op1_64 + op2_64;
|
||||
|
||||
// and write destination into source
|
||||
// Note: if both op1 & op2 are registers, the last one written
|
||||
// should be the sum, as op1 & op2 may be the same register.
|
||||
// For example: XADD AL, AL
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
BX_WRITE_64BIT_REG(i->rm(), sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
sum_64 = op1_64 + op2_64;
|
||||
write_RMW_virtual_qword(sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
sum_64 = op1_64 + op2_64;
|
||||
BX_WRITE_64BIT_REG(i->rm(), sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
sum_64 = op1_64 + op2_64 + temp_CF;
|
||||
write_RMW_virtual_qword(sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
Bit64u op1_64, op2_64, sum_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
sum_64 = op1_64 + op2_64 + temp_CF;
|
||||
BX_WRITE_64BIT_REG(i->rm(), sum_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_64(op1_64, op2_64, sum_64, BX_LF_INSTR_ADD_ADC64(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - op2_64;
|
||||
write_RMW_virtual_qword(diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - op2_64;
|
||||
BX_WRITE_64BIT_REG(i->rm(), diff_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
diff_64 = op1_64 - op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64 = - (Bit64s)(op1_64);
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_LF_INSTR_NEG64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 = - (Bit64s)(op1_64);
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_LF_INSTR_NEG64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64++;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_INC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u rrx = ++BX_READ_64BIT_REG(i->rm());
|
||||
SET_FLAGS_OSZAPC_INC_64(rrx);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64--;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_DEC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u rrx = --BX_READ_64BIT_REG(i->rm());
|
||||
SET_FLAGS_OSZAPC_INC_64(rrx);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
diff_64 = RAX - op1_64;
|
||||
SET_FLAGS_OSZAPC_SUB_64(RAX, op1_64, diff_64);
|
||||
|
||||
if (diff_64 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
write_RMW_virtual_qword(op2_64);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
RAX = op1_64;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, diff_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
diff_64 = RAX - op1_64;
|
||||
SET_FLAGS_OSZAPC_SUB_64(RAX, op1_64, diff_64);
|
||||
|
||||
if (diff_64 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
BX_WRITE_64BIT_REG(i->rm(), op2_64);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
RAX = op1_64;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG16B(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64_lo, op1_64_hi, diff;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
bx_address laddr = get_laddr64(i->seg(), eaddr);
|
||||
|
||||
if (laddr & 0xf) {
|
||||
BX_ERROR(("CMPXCHG16B: not aligned memory location (#GP)"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// check write permission for following write
|
||||
op1_64_lo = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64_hi = read_RMW_virtual_qword_64(i->seg(), (eaddr + 8) & i->asize_mask());
|
||||
|
||||
diff = RAX - op1_64_lo;
|
||||
diff |= RDX - op1_64_hi;
|
||||
|
||||
if (diff == 0) { // if accumulator == dest
|
||||
// dest <-- src (RCX:RBX)
|
||||
write_RMW_virtual_qword(RCX);
|
||||
// write permissions already checked by read_RMW_virtual_qword_64
|
||||
write_virtual_qword_64(i->seg(), eaddr, RBX);
|
||||
assert_ZF();
|
||||
}
|
||||
else {
|
||||
clear_ZF();
|
||||
// accumulator <-- dest
|
||||
RAX = op1_64_lo;
|
||||
RDX = op1_64_hi;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
487
simulators/bochs/cpu/arith8.cc
Normal file
487
simulators/bochs/cpu/arith8.cc
Normal file
@ -0,0 +1,487 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
sum = op1 + op2;
|
||||
write_RMW_virtual_byte(sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
sum = op1 + op2;
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
|
||||
op1 = AL;
|
||||
op2 = i->Ib();
|
||||
sum = op1 + op2;
|
||||
AL = sum;
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
sum = op1 + op2 + temp_CF;
|
||||
write_RMW_virtual_byte(sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
sum = op1 + op2 + temp_CF;
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1 = AL;
|
||||
op2 = i->Ib();
|
||||
sum = op1 + op2 + temp_CF;
|
||||
AL = sum;
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
diff_8 = op1_8 - (op2_8 + temp_CF);
|
||||
write_RMW_virtual_byte(diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = op1_8 - (op2_8 + temp_CF);
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1_8 = AL;
|
||||
op2_8 = i->Ib();
|
||||
diff_8 = op1_8 - (op2_8 + temp_CF);
|
||||
AL = diff_8;
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
diff_8 = op1_8 - (op2_8 + temp_CF);
|
||||
write_RMW_virtual_byte(diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SBB_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = op1_8 - (op2_8 + temp_CF);
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1_8, op2_8, diff_8, BX_LF_INSTR_SUB_SBB8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
diff_8 = op1_8 - op2_8;
|
||||
write_RMW_virtual_byte(diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = op1_8 - op2_8;
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
op1_8 = AL;
|
||||
op2_8 = i->Ib();
|
||||
diff_8 = op1_8 - op2_8;
|
||||
AL = diff_8;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_virtual_byte(i->seg(), eaddr);
|
||||
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
diff_8 = op1_8 - op2_8;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = op1_8 - op2_8;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
op1_8 = AL;
|
||||
op2_8 = i->Ib();
|
||||
diff_8 = op1_8 - op2_8;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
|
||||
/* XADD dst(r/m8), src(r8)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
sum = op1 + op2;
|
||||
write_RMW_virtual_byte(sum);
|
||||
|
||||
/* and write destination into source */
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XADD_EbGbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2, sum;
|
||||
|
||||
/* XADD dst(r/m8), src(r8)
|
||||
* temp <-- src + dst | sum = op2 + op1
|
||||
* src <-- dst | op2 = op1
|
||||
* dst <-- tmp | op1 = sum
|
||||
*/
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
sum = op1 + op2;
|
||||
|
||||
// and write destination into source
|
||||
// Note: if both op1 & op2 are registers, the last one written
|
||||
// should be the sum, as op1 & op2 may be the same register.
|
||||
// For example: XADD AL, AL
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib(), sum;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
sum = op1 + op2;
|
||||
write_RMW_virtual_byte(sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADD_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib(), sum;
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
sum = op1 + op2;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_ADD_8(op1, op2, sum);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib(), sum;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
sum = op1 + op2 + temp_CF;
|
||||
write_RMW_virtual_byte(sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ADC_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib(), sum;
|
||||
bx_bool temp_CF = getB_CF();
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
sum = op1 + op2 + temp_CF;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), sum);
|
||||
|
||||
SET_FLAGS_OSZAPC_8(op1, op2, sum, BX_LF_INSTR_ADD_ADC8(temp_CF));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
diff_8 = op1_8 - op2_8;
|
||||
write_RMW_virtual_byte(diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SUB_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = op1_8 - op2_8;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), diff_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
diff_8 = op1_8 - op2_8;
|
||||
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMP_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8 = i->Ib(), diff_8;
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = op1_8 - op2_8;
|
||||
SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1_8 = - (Bit8s)(op1_8);
|
||||
write_RMW_virtual_byte(op1_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_8(op1_8, BX_LF_INSTR_NEG8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NEG_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1_8 = - (Bit8s)(op1_8);
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_RESULT_8(op1_8, BX_LF_INSTR_NEG8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1_8++;
|
||||
write_RMW_virtual_byte(op1_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_INC_8(op1_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INC_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1_8++;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_INC_8(op1_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1_8--;
|
||||
write_RMW_virtual_byte(op1_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_DEC_8(op1_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DEC_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1_8--;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_DEC_8(op1_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
diff_8 = AL - op1_8;
|
||||
SET_FLAGS_OSZAPC_SUB_8(AL, op1_8, diff_8);
|
||||
|
||||
if (diff_8 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
write_RMW_virtual_byte(op2_8);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
AL = op1_8;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMPXCHG_EbGbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8, op2_8, diff_8;
|
||||
|
||||
op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
diff_8 = AL - op1_8;
|
||||
SET_FLAGS_OSZAPC_SUB_8(AL, op1_8, diff_8);
|
||||
|
||||
if (diff_8 == 0) { // if accumulator == dest
|
||||
// dest <-- src
|
||||
op2_8 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op2_8);
|
||||
}
|
||||
else {
|
||||
// accumulator <-- dest
|
||||
AL = op1_8;
|
||||
}
|
||||
}
|
||||
202
simulators/bochs/cpu/bcd.cc
Normal file
202
simulators/bochs/cpu/bcd.cc
Normal file
@ -0,0 +1,202 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAA(bxInstruction_c *i)
|
||||
{
|
||||
/*
|
||||
* Note: This instruction incorrectly documented in Intel's materials.
|
||||
* The right description is:
|
||||
*
|
||||
* IF (((AL and 0FH) > 9) or (AF==1)
|
||||
* THEN
|
||||
* IF CPU<286 THEN { AL <- AL+6 }
|
||||
* ELSE { AX <- AX+6 }
|
||||
* AH <- AH+1
|
||||
* CF <- 1
|
||||
* AF <- 1
|
||||
* ELSE
|
||||
* CF <- 0
|
||||
* AF <- 0
|
||||
* ENDIF
|
||||
* AL <- AL and 0Fh
|
||||
*/
|
||||
|
||||
/* Validated against Intel Pentium family hardware. */
|
||||
|
||||
/* AAA affects the following flags: A,C */
|
||||
|
||||
if (((AL & 0x0f) > 9) || get_AF())
|
||||
{
|
||||
AX = AX + 0x106;
|
||||
assert_AF();
|
||||
assert_CF();
|
||||
}
|
||||
else {
|
||||
clear_AF();
|
||||
clear_CF();
|
||||
}
|
||||
|
||||
AL = AL & 0x0f;
|
||||
|
||||
/* AAA affects also the following flags: Z,S,O,P */
|
||||
/* modification of the flags is undocumented */
|
||||
|
||||
/* The following behaviour seems to match the P6 and
|
||||
its derived processors. */
|
||||
clear_OF();
|
||||
clear_SF(); /* sign is always 0 because bits 4-7 of AL are zeroed */
|
||||
set_ZF(AL == 0);
|
||||
set_PF_base(AL);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAS(bxInstruction_c *i)
|
||||
{
|
||||
/* AAS affects the following flags: A,C */
|
||||
|
||||
if (((AL & 0x0F) > 0x09) || get_AF())
|
||||
{
|
||||
AX = AX - 0x106;
|
||||
assert_AF();
|
||||
assert_CF();
|
||||
}
|
||||
else {
|
||||
clear_CF();
|
||||
clear_AF();
|
||||
}
|
||||
|
||||
AL = AL & 0x0f;
|
||||
|
||||
/* AAS affects also the following flags: Z,S,O,P */
|
||||
/* modification of the flags is undocumented */
|
||||
|
||||
/* The following behaviour seems to match the P6 and
|
||||
its derived processors. */
|
||||
clear_OF();
|
||||
clear_SF(); /* sign is always 0 because bits 4-7 of AL are zeroed */
|
||||
set_ZF(AL == 0);
|
||||
set_PF_base(AL);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u al, imm8 = i->Ib();
|
||||
|
||||
if (imm8 == 0)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
al = AL;
|
||||
AH = al / imm8;
|
||||
AL = al % imm8;
|
||||
|
||||
/* modification of flags A,C,O is undocumented */
|
||||
/* The following behaviour seems to match the P6 and
|
||||
its derived processors. */
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(AL);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AAD(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u tmp = AH;
|
||||
tmp *= i->Ib();
|
||||
tmp += AL;
|
||||
|
||||
AX = (tmp & 0xff);
|
||||
|
||||
/* modification of flags A,C,O is undocumented */
|
||||
/* The following behaviour seems to match the P6 and
|
||||
its derived processors. */
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(AL);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DAA(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u tmpAL = AL;
|
||||
int tmpCF = 0;
|
||||
|
||||
/* Validated against Intel Pentium family hardware. */
|
||||
|
||||
// DAA affects the following flags: S,Z,A,P,C
|
||||
|
||||
if (((tmpAL & 0x0F) > 0x09) || get_AF())
|
||||
{
|
||||
tmpCF = ((AL > 0xF9) || get_CF());
|
||||
AL = AL + 0x06;
|
||||
assert_AF();
|
||||
}
|
||||
else
|
||||
clear_AF();
|
||||
|
||||
if ((tmpAL > 0x99) || get_CF())
|
||||
{
|
||||
AL = AL + 0x60;
|
||||
tmpCF = 1;
|
||||
}
|
||||
else
|
||||
tmpCF = 0;
|
||||
|
||||
clear_OF(); /* undocumented flag modification */
|
||||
set_SF(AL >= 0x80);
|
||||
set_ZF(AL==0);
|
||||
set_PF_base(AL);
|
||||
set_CF(tmpCF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DAS(bxInstruction_c *i)
|
||||
{
|
||||
/* The algorithm for DAS is fashioned after the pseudo code in the
|
||||
* Pentium Processor Family Developer's Manual, volume 3. It seems
|
||||
* to have changed from earlier processor's manuals. I'm not sure
|
||||
* if this is a correction in the algorithm printed, or Intel has
|
||||
* changed the handling of instruction. Validated against Intel
|
||||
* Pentium family hardware.
|
||||
*/
|
||||
|
||||
Bit8u tmpAL = AL;
|
||||
int tmpCF = 0;
|
||||
|
||||
/* DAS effect the following flags: A,C,S,Z,P */
|
||||
|
||||
if (((tmpAL & 0x0F) > 0x09) || get_AF())
|
||||
{
|
||||
tmpCF = (AL < 0x06) || get_CF();
|
||||
AL = AL - 0x06;
|
||||
assert_AF();
|
||||
}
|
||||
else
|
||||
clear_AF();
|
||||
|
||||
if ((tmpAL > 0x99) || get_CF())
|
||||
{
|
||||
AL = AL - 0x60;
|
||||
tmpCF = 1;
|
||||
}
|
||||
|
||||
clear_OF(); /* undocumented flag modification */
|
||||
set_SF(AL >= 0x80);
|
||||
set_ZF(AL==0);
|
||||
set_PF_base(AL);
|
||||
set_CF(tmpCF);
|
||||
}
|
||||
337
simulators/bochs/cpu/bit.cc
Normal file
337
simulators/bochs/cpu/bit.cc
Normal file
@ -0,0 +1,337 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETO_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = getB_OF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETO_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_OF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNO_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !getB_OF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNO_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_OF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETB_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = getB_CF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETB_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_CF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNB_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !getB_CF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNB_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_CF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETZ_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = getB_ZF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETZ_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_ZF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNZ_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !getB_ZF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNZ_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_ZF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETBE_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = (getB_CF() | getB_ZF());
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETBE_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), (getB_CF() | getB_ZF()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNBE_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !(getB_CF() | getB_ZF());
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNBE_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !(getB_CF() | getB_ZF()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETS_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = getB_SF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETS_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_SF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNS_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !getB_SF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNS_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_SF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETP_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = getB_PF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETP_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), getB_PF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNP_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !getB_PF();
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNP_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !getB_PF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETL_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = (getB_SF() ^ getB_OF());
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETL_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), (getB_SF() ^ getB_OF()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNL_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !(getB_SF() ^ getB_OF());
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNL_EbR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), !(getB_SF() ^ getB_OF()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETLE_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = getB_ZF() | (getB_SF() ^ getB_OF());
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETLE_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u result_8 = getB_ZF() | (getB_SF() ^ getB_OF());
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNLE_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u result_8 = !(getB_ZF() | (getB_SF() ^ getB_OF()));
|
||||
write_virtual_byte(i->seg(), eaddr, result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SETNLE_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u result_8 = !(getB_ZF() | (getB_SF() ^ getB_OF()));
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSWAP_RX(bxInstruction_c *i)
|
||||
{
|
||||
BX_ERROR(("BSWAP with 16-bit opsize: undefined behavior !"));
|
||||
BX_WRITE_16BIT_REG(i->rm(), 0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSWAP_ERX(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u val32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), bx_bswap32(val32));
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSWAP_RRX(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u val64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), bx_bswap64(val64));
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val16 = BX_READ_16BIT_REG(i->rm()), b0, b1;
|
||||
|
||||
b0 = val16 & 0xff; val16 >>= 8;
|
||||
b1 = val16;
|
||||
val16 = (b0<<8) | b1;
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), val16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_EwGw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val16 = BX_READ_16BIT_REG(i->nnn()), b0, b1;
|
||||
|
||||
b0 = val16 & 0xff; val16 >>= 8;
|
||||
b1 = val16;
|
||||
val16 = (b0<<8) | b1;
|
||||
|
||||
if (i->modC0()) {
|
||||
BX_WRITE_16BIT_REG(i->rm(), val16);
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
write_virtual_word(i->seg(), eaddr, val16);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u val32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), bx_bswap32(val32));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_EdGd(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u val32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
val32 = bx_bswap32(val32);
|
||||
|
||||
if (i->modC0()) {
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), val32);
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
write_virtual_dword(i->seg(), eaddr, val32);
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u val64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
BX_WRITE_64BIT_REG(i->nnn(), bx_bswap64(val64));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVBE_EqGq(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u val64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
val64 = bx_bswap64(val64);
|
||||
|
||||
if (i->modC0()) {
|
||||
BX_WRITE_64BIT_REG(i->rm(), val64);
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
write_virtual_qword_64(i->seg(), eaddr, val64);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
|
||||
#endif // BX_CPU_LEVEL >= 3
|
||||
327
simulators/bochs/cpu/bit16.cc
Executable file
327
simulators/bochs/cpu/bit16.cc
Executable file
@ -0,0 +1,327 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSF_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if (op2_16 == 0) {
|
||||
assert_ZF(); /* op1_16 undefined */
|
||||
}
|
||||
else {
|
||||
Bit16u op1_16 = 0;
|
||||
while ((op2_16 & 0x01) == 0) {
|
||||
op1_16++;
|
||||
op2_16 >>= 1;
|
||||
}
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
clear_ZF();
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSR_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if (op2_16 == 0) {
|
||||
assert_ZF(); /* op1_16 undefined */
|
||||
}
|
||||
else {
|
||||
Bit16u op1_16 = 15;
|
||||
while ((op2_16 & 0x8000) == 0) {
|
||||
op1_16--;
|
||||
op2_16 <<= 1;
|
||||
}
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
clear_ZF();
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit16u op1_16, op2_16, index;
|
||||
Bit32s displacement32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
index = op2_16 & 0x0f;
|
||||
displacement32 = ((Bit16s) (op2_16&0xfff0)) / 16;
|
||||
op1_addr = eaddr + 2 * displacement32;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_16 = read_virtual_word(i->seg(), op1_addr & i->asize_mask());
|
||||
|
||||
set_CF((op1_16 >> index) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 &= 0x0f;
|
||||
set_CF((op1_16 >> op2_16) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit16u op1_16, op2_16, index;
|
||||
Bit32s displacement32;
|
||||
bx_bool bit_i;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
index = op2_16 & 0x0f;
|
||||
displacement32 = ((Bit16s) (op2_16 & 0xfff0)) / 16;
|
||||
op1_addr = eaddr + 2 * displacement32;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), op1_addr & i->asize_mask());
|
||||
bit_i = (op1_16 >> index) & 0x01;
|
||||
op1_16 |= (((Bit16u) 1) << index);
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
set_CF(bit_i);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 &= 0x0f;
|
||||
set_CF((op1_16 >> op2_16) & 0x01);
|
||||
op1_16 |= (((Bit16u) 1) << op2_16);
|
||||
|
||||
/* now write result back to the destination */
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit16u op1_16, op2_16, index;
|
||||
Bit32s displacement32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
index = op2_16 & 0x0f;
|
||||
displacement32 = ((Bit16s) (op2_16&0xfff0)) / 16;
|
||||
op1_addr = eaddr + 2 * displacement32;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), op1_addr & i->asize_mask());
|
||||
bx_bool temp_cf = (op1_16 >> index) & 0x01;
|
||||
op1_16 &= ~(((Bit16u) 1) << index);
|
||||
|
||||
/* now write back to destination */
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
set_CF(temp_cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 &= 0x0f;
|
||||
set_CF((op1_16 >> op2_16) & 0x01);
|
||||
op1_16 &= ~(((Bit16u) 1) << op2_16);
|
||||
|
||||
/* now write result back to the destination */
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit16u op1_16, op2_16, index_16;
|
||||
Bit16s displacement16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
index_16 = op2_16 & 0x0f;
|
||||
displacement16 = ((Bit16s) (op2_16 & 0xfff0)) / 16;
|
||||
op1_addr = eaddr + 2 * displacement16;
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), op1_addr & i->asize_mask());
|
||||
bx_bool temp_CF = (op1_16 >> index_16) & 0x01;
|
||||
op1_16 ^= (((Bit16u) 1) << index_16); /* toggle bit */
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 &= 0x0f;
|
||||
|
||||
bx_bool temp_CF = (op1_16 >> op2_16) & 0x01;
|
||||
op1_16 ^= (((Bit16u) 1) << op2_16); /* toggle bit */
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwIbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_virtual_word(i->seg(), eaddr);
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
set_CF((op1_16 >> op2_8) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EwIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
set_CF((op1_16 >> op2_8) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
|
||||
op1_16 |= (((Bit16u) 1) << op2_8);
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EwIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
|
||||
op1_16 |= (((Bit16u) 1) << op2_8);
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
|
||||
op1_16 ^= (((Bit16u) 1) << op2_8); /* toggle bit */
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EwIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
|
||||
op1_16 ^= (((Bit16u) 1) << op2_8); /* toggle bit */
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
|
||||
op1_16 &= ~(((Bit16u) 1) << op2_8);
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EwIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0xf;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_16 >> op2_8) & 0x01;
|
||||
op1_16 &= ~(((Bit16u) 1) << op2_8);
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
/* F3 0F B8 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPCNT_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
Bit16u op1_16 = 0;
|
||||
while (op2_16 != 0) {
|
||||
if (op2_16 & 1) op1_16++;
|
||||
op2_16 >>= 1;
|
||||
}
|
||||
|
||||
Bit32u flags = op1_16 ? 0 : EFlagsZFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
}
|
||||
|
||||
#endif // (BX_CPU_LEVEL >= 3)
|
||||
332
simulators/bochs/cpu/bit32.cc
Executable file
332
simulators/bochs/cpu/bit32.cc
Executable file
@ -0,0 +1,332 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSF_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
if (op2_32 == 0) {
|
||||
assert_ZF(); /* op1_32 undefined */
|
||||
}
|
||||
else {
|
||||
Bit32u op1_32 = 0;
|
||||
while ((op2_32 & 0x01) == 0) {
|
||||
op1_32++;
|
||||
op2_32 >>= 1;
|
||||
}
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
clear_ZF();
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSR_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
if (op2_32 == 0) {
|
||||
assert_ZF(); /* op1_32 undefined */
|
||||
}
|
||||
else {
|
||||
Bit32u op1_32 = 31;
|
||||
while ((op2_32 & 0x80000000) == 0) {
|
||||
op1_32--;
|
||||
op2_32 <<= 1;
|
||||
}
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
clear_ZF();
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit32u op1_32, op2_32, index;
|
||||
Bit32s displacement32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
index = op2_32 & 0x1f;
|
||||
displacement32 = ((Bit32s) (op2_32&0xffffffe0)) / 32;
|
||||
op1_addr = eaddr + 4 * displacement32;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_virtual_dword(i->seg(), op1_addr & i->asize_mask());
|
||||
|
||||
set_CF((op1_32 >> index) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 &= 0x1f;
|
||||
|
||||
set_CF((op1_32 >> op2_32) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit32u op1_32, op2_32, index;
|
||||
Bit32s displacement32;
|
||||
bx_bool bit_i;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
index = op2_32 & 0x1f;
|
||||
displacement32 = ((Bit32s) (op2_32&0xffffffe0)) / 32;
|
||||
op1_addr = eaddr + 4 * displacement32;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), op1_addr & i->asize_mask());
|
||||
|
||||
bit_i = (op1_32 >> index) & 0x01;
|
||||
op1_32 |= (((Bit32u) 1) << index);
|
||||
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
set_CF(bit_i);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 &= 0x1f;
|
||||
set_CF((op1_32 >> op2_32) & 0x01);
|
||||
op1_32 |= (((Bit32u) 1) << op2_32);
|
||||
|
||||
/* now write result back to the destination */
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit32u op1_32, op2_32, index;
|
||||
Bit32s displacement32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
index = op2_32 & 0x1f;
|
||||
displacement32 = ((Bit32s) (op2_32&0xffffffe0)) / 32;
|
||||
op1_addr = eaddr + 4 * displacement32;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), op1_addr & i->asize_mask());
|
||||
|
||||
bx_bool temp_cf = (op1_32 >> index) & 0x01;
|
||||
op1_32 &= ~(((Bit32u) 1) << index);
|
||||
|
||||
/* now write back to destination */
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
set_CF(temp_cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 &= 0x1f;
|
||||
set_CF((op1_32 >> op2_32) & 0x01);
|
||||
op1_32 &= ~(((Bit32u) 1) << op2_32);
|
||||
|
||||
/* now write result back to the destination */
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit32u op1_32, op2_32, index_32;
|
||||
Bit32s displacement32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
index_32 = op2_32 & 0x1f;
|
||||
|
||||
displacement32 = ((Bit32s) (op2_32 & 0xffffffe0)) / 32;
|
||||
op1_addr = eaddr + 4 * displacement32;
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), op1_addr & i->asize_mask());
|
||||
bx_bool temp_CF = (op1_32 >> index_32) & 0x01;
|
||||
op1_32 ^= (((Bit32u) 1) << index_32); /* toggle bit */
|
||||
set_CF(temp_CF);
|
||||
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 &= 0x1f;
|
||||
|
||||
bx_bool temp_CF = (op1_32 >> op2_32) & 0x01;
|
||||
op1_32 ^= (((Bit32u) 1) << op2_32); /* toggle bit */
|
||||
set_CF(temp_CF);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdIbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
set_CF((op1_32 >> op2_8) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EdIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
set_CF((op1_32 >> op2_8) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
|
||||
op1_32 |= (((Bit32u) 1) << op2_8);
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EdIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
|
||||
op1_32 |= (((Bit32u) 1) << op2_8);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
|
||||
op1_32 ^= (((Bit32u) 1) << op2_8); /* toggle bit */
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EdIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
|
||||
op1_32 ^= (((Bit32u) 1) << op2_8); /* toggle bit */
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
|
||||
op1_32 &= ~(((Bit32u) 1) << op2_8);
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EdIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x1f;
|
||||
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_32 >> op2_8) & 0x01;
|
||||
op1_32 &= ~(((Bit32u) 1) << op2_8);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
/* F3 0F B8 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPCNT_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
Bit32u op1_32 = 0;
|
||||
while (op2_32 != 0) {
|
||||
if (op2_32 & 1) op1_32++;
|
||||
op2_32 >>= 1;
|
||||
}
|
||||
|
||||
Bit32u flags = op1_32 ? 0 : EFlagsZFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
}
|
||||
|
||||
#endif // (BX_CPU_LEVEL >= 3)
|
||||
336
simulators/bochs/cpu/bit64.cc
Executable file
336
simulators/bochs/cpu/bit64.cc
Executable file
@ -0,0 +1,336 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSF_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
if (op2_64 == 0) {
|
||||
assert_ZF(); /* op1_64 undefined */
|
||||
}
|
||||
else {
|
||||
Bit64u op1_64 = 0;
|
||||
while ((op2_64 & 0x01) == 0) {
|
||||
op1_64++;
|
||||
op2_64 >>= 1;
|
||||
}
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
clear_ZF();
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BSR_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
if (op2_64 == 0) {
|
||||
assert_ZF(); /* op1_64 undefined */
|
||||
}
|
||||
else {
|
||||
Bit64u op1_64 = 63;
|
||||
while ((op2_64 & BX_CONST64(0x8000000000000000)) == 0) {
|
||||
op1_64--;
|
||||
op2_64 <<= 1;
|
||||
}
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
clear_ZF();
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit64u op1_64, op2_64;
|
||||
Bit64s displacement64;
|
||||
Bit64u index;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
index = op2_64 & 0x3f;
|
||||
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
|
||||
op1_addr = eaddr + 8 * displacement64;
|
||||
if (! i->as64L())
|
||||
op1_addr = (Bit32u) op1_addr;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_virtual_qword_64(i->seg(), op1_addr);
|
||||
|
||||
set_CF((op1_64 >> index) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 &= 0x3f;
|
||||
set_CF((op1_64 >> op2_64) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit64u op1_64, op2_64, index;
|
||||
Bit64s displacement64;
|
||||
bx_bool bit_i;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
index = op2_64 & 0x3f;
|
||||
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
|
||||
op1_addr = eaddr + 8 * displacement64;
|
||||
if (! i->as64L())
|
||||
op1_addr = (Bit32u) op1_addr;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), op1_addr);
|
||||
bit_i = (op1_64 >> index) & 0x01;
|
||||
op1_64 |= (((Bit64u) 1) << index);
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
set_CF(bit_i);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 &= 0x3f;
|
||||
set_CF((op1_64 >> op2_64) & 0x01);
|
||||
op1_64 |= (((Bit64u) 1) << op2_64);
|
||||
|
||||
/* now write result back to the destination */
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit64u op1_64, op2_64, index;
|
||||
Bit64s displacement64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
index = op2_64 & 0x3f;
|
||||
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
|
||||
op1_addr = eaddr + 8 * displacement64;
|
||||
if (! i->as64L())
|
||||
op1_addr = (Bit32u) op1_addr;
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), op1_addr);
|
||||
bx_bool temp_cf = (op1_64 >> index) & 0x01;
|
||||
op1_64 &= ~(((Bit64u) 1) << index);
|
||||
/* now write back to destination */
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
set_CF(temp_cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 &= 0x3f;
|
||||
set_CF((op1_64 >> op2_64) & 0x01);
|
||||
op1_64 &= ~(((Bit64u) 1) << op2_64);
|
||||
|
||||
/* now write result back to the destination */
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address op1_addr;
|
||||
Bit64u op1_64, op2_64;
|
||||
Bit64s displacement64;
|
||||
Bit64u index;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
index = op2_64 & 0x3f;
|
||||
displacement64 = ((Bit64s) (op2_64 & BX_CONST64(0xffffffffffffffc0))) / 64;
|
||||
op1_addr = eaddr + 8 * displacement64;
|
||||
if (! i->as64L())
|
||||
op1_addr = (Bit32u) op1_addr;
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), op1_addr);
|
||||
bx_bool temp_CF = (op1_64 >> index) & 0x01;
|
||||
op1_64 ^= (((Bit64u) 1) << index); /* toggle bit */
|
||||
set_CF(temp_CF);
|
||||
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 &= 0x3f;
|
||||
|
||||
bx_bool temp_CF = (op1_64 >> op2_64) & 0x01;
|
||||
op1_64 ^= (((Bit64u) 1) << op2_64); /* toggle bit */
|
||||
set_CF(temp_CF);
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqIbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
set_CF((op1_64 >> op2_8) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BT_EqIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
set_CF((op1_64 >> op2_8) & 0x01);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
|
||||
op1_64 |= (((Bit64u) 1) << op2_8);
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTS_EqIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
|
||||
op1_64 |= (((Bit64u) 1) << op2_8);
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
|
||||
op1_64 ^= (((Bit64u) 1) << op2_8); /* toggle bit */
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTC_EqIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
|
||||
op1_64 ^= (((Bit64u) 1) << op2_8); /* toggle bit */
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
|
||||
op1_64 &= ~(((Bit64u) 1) << op2_8);
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BTR_EqIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = i->Ib() & 0x3f;
|
||||
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
bx_bool temp_CF = (op1_64 >> op2_8) & 0x01;
|
||||
op1_64 &= ~(((Bit64u) 1) << op2_8);
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
set_CF(temp_CF);
|
||||
}
|
||||
|
||||
/* F3 0F B8 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPCNT_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
Bit64u op1_64 = 0;
|
||||
while (op2_64 != 0) {
|
||||
if (op2_64 & 1) op1_64++;
|
||||
op2_64 >>= 1;
|
||||
}
|
||||
|
||||
Bit32u flags = op1_64 ? 0 : EFlagsZFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
570
simulators/bochs/cpu/call_far.cc
Executable file
570
simulators/bochs/cpu/call_far.cc
Executable file
@ -0,0 +1,570 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier merging cpu64 & cpu code.
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::call_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
|
||||
{
|
||||
bx_selector_t cs_selector;
|
||||
Bit32u dword1, dword2;
|
||||
bx_descriptor_t cs_descriptor;
|
||||
|
||||
/* new cs selector must not be null, else #GP(0) */
|
||||
if ((cs_raw & 0xfffc) == 0) {
|
||||
BX_ERROR(("call_protected: CS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(cs_raw, &cs_selector);
|
||||
// check new CS selector index within its descriptor limits,
|
||||
// else #GP(new CS selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// examine AR byte of selected descriptor for various legal values
|
||||
if (cs_descriptor.valid==0) {
|
||||
BX_ERROR(("call_protected: invalid CS descriptor"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
if (cs_descriptor.segment) // normal segment
|
||||
{
|
||||
check_cs(&cs_descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode() && cs_descriptor.u.segment.l) {
|
||||
Bit64u temp_rsp = RSP;
|
||||
// moving to long mode, push return address onto 64-bit stack
|
||||
if (i->os64L()) {
|
||||
write_new_stack_qword_64(temp_rsp - 8, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
write_new_stack_qword_64(temp_rsp - 16, cs_descriptor.dpl, RIP);
|
||||
temp_rsp -= 16;
|
||||
}
|
||||
else if (i->os32L()) {
|
||||
write_new_stack_dword_64(temp_rsp - 4, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
write_new_stack_dword_64(temp_rsp - 8, cs_descriptor.dpl, EIP);
|
||||
temp_rsp -= 8;
|
||||
}
|
||||
else {
|
||||
write_new_stack_word_64(temp_rsp - 2, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
write_new_stack_word_64(temp_rsp - 4, cs_descriptor.dpl, IP);
|
||||
temp_rsp -= 4;
|
||||
}
|
||||
|
||||
// load code segment descriptor into CS cache
|
||||
// load CS with new code segment selector
|
||||
// set RPL of CS to CPL
|
||||
branch_far64(&cs_selector, &cs_descriptor, disp, CPL);
|
||||
|
||||
RSP = temp_rsp;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Bit32u temp_RSP;
|
||||
|
||||
// moving to legacy mode, push return address onto 32-bit stack
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
temp_RSP = ESP;
|
||||
else
|
||||
temp_RSP = SP;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
write_new_stack_qword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
|
||||
temp_RSP - 8, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
write_new_stack_qword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
|
||||
temp_RSP - 16, cs_descriptor.dpl, RIP);
|
||||
temp_RSP -= 16;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->os32L()) {
|
||||
write_new_stack_dword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
|
||||
temp_RSP - 4, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
write_new_stack_dword_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
|
||||
temp_RSP - 8, cs_descriptor.dpl, EIP);
|
||||
temp_RSP -= 8;
|
||||
}
|
||||
else {
|
||||
write_new_stack_word_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
|
||||
temp_RSP - 2, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
write_new_stack_word_32(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS],
|
||||
temp_RSP - 4, cs_descriptor.dpl, IP);
|
||||
temp_RSP -= 4;
|
||||
}
|
||||
|
||||
// load code segment descriptor into CS cache
|
||||
// load CS with new code segment selector
|
||||
// set RPL of CS to CPL
|
||||
branch_far64(&cs_selector, &cs_descriptor, disp, CPL);
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
ESP = (Bit32u) temp_RSP;
|
||||
else
|
||||
SP = (Bit16u) temp_RSP;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else { // gate & special segment
|
||||
bx_descriptor_t gate_descriptor = cs_descriptor;
|
||||
bx_selector_t gate_selector = cs_selector;
|
||||
|
||||
// descriptor DPL must be >= CPL else #GP(gate selector)
|
||||
if (gate_descriptor.dpl < CPL) {
|
||||
BX_ERROR(("call_protected: descriptor.dpl < CPL"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
// descriptor DPL must be >= gate selector RPL else #GP(gate selector)
|
||||
if (gate_descriptor.dpl < gate_selector.rpl) {
|
||||
BX_ERROR(("call_protected: descriptor.dpl < selector.rpl"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
// call gate type is higher priority than non-present bit check
|
||||
if (gate_descriptor.type != BX_386_CALL_GATE) {
|
||||
BX_ERROR(("call_protected: gate type %u unsupported in long mode", (unsigned) gate_descriptor.type));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
// gate descriptor must be present else #NP(gate selector)
|
||||
if (! IS_PRESENT(gate_descriptor)) {
|
||||
BX_ERROR(("call_protected: call gate not present"));
|
||||
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
call_gate64(&gate_selector);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (gate_descriptor.type) {
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
if (gate_descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
|
||||
BX_DEBUG(("call_protected: 16bit available TSS"));
|
||||
else
|
||||
BX_DEBUG(("call_protected: 32bit available TSS"));
|
||||
|
||||
if (gate_descriptor.valid==0 || gate_selector.ti) {
|
||||
BX_ERROR(("call_protected: call bad TSS selector !"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
// TSS must be present, else #NP(TSS selector)
|
||||
if (! IS_PRESENT(gate_descriptor)) {
|
||||
BX_ERROR(("call_protected: call not present TSS !"));
|
||||
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
// SWITCH_TASKS _without_ nesting to TSS
|
||||
task_switch(i, &gate_selector, &gate_descriptor,
|
||||
BX_TASK_FROM_CALL, dword1, dword2);
|
||||
|
||||
// EIP must be in code seg limit, else #GP(0)
|
||||
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("call_protected: EIP not within CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
return;
|
||||
|
||||
case BX_TASK_GATE:
|
||||
task_gate(i, &gate_selector, &gate_descriptor, BX_TASK_FROM_CALL);
|
||||
return;
|
||||
|
||||
case BX_286_CALL_GATE:
|
||||
case BX_386_CALL_GATE:
|
||||
// gate descriptor must be present else #NP(gate selector)
|
||||
if (! IS_PRESENT(gate_descriptor)) {
|
||||
BX_ERROR(("call_protected: gate not present"));
|
||||
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
call_gate(&gate_descriptor);
|
||||
return;
|
||||
|
||||
default: // can't get here
|
||||
BX_ERROR(("call_protected(): gate.type(%u) unsupported", (unsigned) gate_descriptor.type));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::call_gate(bx_descriptor_t *gate_descriptor)
|
||||
{
|
||||
bx_selector_t cs_selector;
|
||||
Bit32u dword1, dword2;
|
||||
bx_descriptor_t cs_descriptor;
|
||||
|
||||
// examine code segment selector in call gate descriptor
|
||||
BX_DEBUG(("call_protected: call gate"));
|
||||
|
||||
Bit16u dest_selector = gate_descriptor->u.gate.dest_selector;
|
||||
Bit32u new_EIP = gate_descriptor->u.gate.dest_offset;
|
||||
|
||||
// selector must not be null else #GP(0)
|
||||
if ((dest_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("call_protected: selector in gate null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(dest_selector, &cs_selector);
|
||||
// selector must be within its descriptor table limits,
|
||||
// else #GP(code segment selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// AR byte of selected descriptor must indicate code segment,
|
||||
// else #GP(code segment selector)
|
||||
// DPL of selected descriptor must be <= CPL,
|
||||
// else #GP(code segment selector)
|
||||
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
|
||||
IS_DATA_SEGMENT(cs_descriptor.type) || cs_descriptor.dpl > CPL)
|
||||
{
|
||||
BX_ERROR(("call_protected: selected descriptor is not code"));
|
||||
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// code segment must be present else #NP(selector)
|
||||
if (! IS_PRESENT(cs_descriptor)) {
|
||||
BX_ERROR(("call_protected: code segment not present !"));
|
||||
exception(BX_NP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// CALL GATE TO MORE PRIVILEGE
|
||||
// if non-conforming code segment and DPL < CPL then
|
||||
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && (cs_descriptor.dpl < CPL))
|
||||
{
|
||||
Bit16u SS_for_cpl_x;
|
||||
Bit32u ESP_for_cpl_x;
|
||||
bx_selector_t ss_selector;
|
||||
bx_descriptor_t ss_descriptor;
|
||||
Bit16u return_SS, return_CS;
|
||||
Bit32u return_ESP, return_EIP;
|
||||
|
||||
BX_DEBUG(("CALL GATE TO MORE PRIVILEGE LEVEL"));
|
||||
|
||||
// get new SS selector for new privilege level from TSS
|
||||
get_SS_ESP_from_TSS(cs_descriptor.dpl, &SS_for_cpl_x, &ESP_for_cpl_x);
|
||||
|
||||
// check selector & descriptor for new SS:
|
||||
// selector must not be null, else #TS(0)
|
||||
if ((SS_for_cpl_x & 0xfffc) == 0) {
|
||||
BX_ERROR(("call_protected: new SS null"));
|
||||
exception(BX_TS_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// selector index must be within its descriptor table limits,
|
||||
// else #TS(SS selector)
|
||||
parse_selector(SS_for_cpl_x, &ss_selector);
|
||||
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_TS_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &ss_descriptor);
|
||||
|
||||
// selector's RPL must equal DPL of code segment,
|
||||
// else #TS(SS selector)
|
||||
if (ss_selector.rpl != cs_descriptor.dpl) {
|
||||
BX_ERROR(("call_protected: SS selector.rpl != CS descr.dpl"));
|
||||
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// stack segment DPL must equal DPL of code segment,
|
||||
// else #TS(SS selector)
|
||||
if (ss_descriptor.dpl != cs_descriptor.dpl) {
|
||||
BX_ERROR(("call_protected: SS descr.rpl != CS descr.dpl"));
|
||||
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// descriptor must indicate writable data segment,
|
||||
// else #TS(SS selector)
|
||||
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
|
||||
IS_CODE_SEGMENT(ss_descriptor.type) || !IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("call_protected: ss descriptor is not writable data seg"));
|
||||
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// segment must be present, else #SS(SS selector)
|
||||
if (! IS_PRESENT(ss_descriptor)) {
|
||||
BX_ERROR(("call_protected: ss descriptor not present"));
|
||||
exception(BX_SS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// get word count from call gate, mask to 5 bits
|
||||
unsigned param_count = gate_descriptor->u.gate.param_count & 0x1f;
|
||||
|
||||
// save return SS:eSP to be pushed on new stack
|
||||
return_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
return_ESP = ESP;
|
||||
else
|
||||
return_ESP = SP;
|
||||
|
||||
// save return CS:eIP to be pushed on new stack
|
||||
return_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
|
||||
if (cs_descriptor.u.segment.d_b)
|
||||
return_EIP = EIP;
|
||||
else
|
||||
return_EIP = IP;
|
||||
|
||||
// Prepare new stack segment
|
||||
bx_segment_reg_t new_stack;
|
||||
new_stack.selector = ss_selector;
|
||||
new_stack.cache = ss_descriptor;
|
||||
new_stack.selector.rpl = cs_descriptor.dpl;
|
||||
// add cpl to the selector value
|
||||
new_stack.selector.value = (0xfffc & new_stack.selector.value) |
|
||||
new_stack.selector.rpl;
|
||||
|
||||
/* load new SS:SP value from TSS */
|
||||
if (ss_descriptor.u.segment.d_b) {
|
||||
Bit32u temp_ESP = ESP_for_cpl_x;
|
||||
|
||||
// push pointer of old stack onto new stack
|
||||
if (gate_descriptor->type==BX_386_CALL_GATE) {
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, return_SS);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, return_ESP);
|
||||
temp_ESP -= 8;
|
||||
|
||||
for (unsigned n=param_count; n>0; n--) {
|
||||
temp_ESP -= 4;
|
||||
Bit32u param = read_virtual_dword_32(BX_SEG_REG_SS, return_ESP + (n-1)*4);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP, cs_descriptor.dpl, param);
|
||||
}
|
||||
// push return address onto new stack
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, return_CS);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, return_EIP);
|
||||
temp_ESP -= 8;
|
||||
}
|
||||
else {
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, return_SS);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) return_ESP);
|
||||
temp_ESP -= 4;
|
||||
|
||||
for (unsigned n=param_count; n>0; n--) {
|
||||
temp_ESP -= 2;
|
||||
Bit16u param = read_virtual_word_32(BX_SEG_REG_SS, return_ESP + (n-1)*2);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP, cs_descriptor.dpl, param);
|
||||
}
|
||||
// push return address onto new stack
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, return_CS);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) return_EIP);
|
||||
temp_ESP -= 4;
|
||||
}
|
||||
|
||||
ESP = temp_ESP;
|
||||
}
|
||||
else {
|
||||
Bit16u temp_SP = (Bit16u) ESP_for_cpl_x;
|
||||
|
||||
// push pointer of old stack onto new stack
|
||||
if (gate_descriptor->type==BX_386_CALL_GATE) {
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, return_SS);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, return_ESP);
|
||||
temp_SP -= 8;
|
||||
|
||||
for (unsigned n=param_count; n>0; n--) {
|
||||
temp_SP -= 4;
|
||||
Bit32u param = read_virtual_dword_32(BX_SEG_REG_SS, return_ESP + (n-1)*4);
|
||||
write_new_stack_dword_32(&new_stack, temp_SP, cs_descriptor.dpl, param);
|
||||
}
|
||||
// push return address onto new stack
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, return_CS);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, return_EIP);
|
||||
temp_SP -= 8;
|
||||
}
|
||||
else {
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, return_SS);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) return_ESP);
|
||||
temp_SP -= 4;
|
||||
|
||||
for (unsigned n=param_count; n>0; n--) {
|
||||
temp_SP -= 2;
|
||||
Bit16u param = read_virtual_word_32(BX_SEG_REG_SS, return_ESP + (n-1)*2);
|
||||
write_new_stack_word_32(&new_stack, temp_SP, cs_descriptor.dpl, param);
|
||||
}
|
||||
// push return address onto new stack
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, return_CS);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) return_EIP);
|
||||
temp_SP -= 4;
|
||||
}
|
||||
|
||||
SP = temp_SP;
|
||||
}
|
||||
|
||||
// new eIP must be in code segment limit else #GP(0)
|
||||
if (new_EIP > cs_descriptor.u.segment.limit_scaled) {
|
||||
BX_ERROR(("call_protected: EIP not within CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* load SS descriptor */
|
||||
load_ss(&ss_selector, &ss_descriptor, cs_descriptor.dpl);
|
||||
|
||||
/* load new CS:IP value from gate */
|
||||
/* load CS descriptor */
|
||||
/* set CPL to stack segment DPL */
|
||||
/* set RPL of CS to CPL */
|
||||
load_cs(&cs_selector, &cs_descriptor, cs_descriptor.dpl);
|
||||
EIP = new_EIP;
|
||||
}
|
||||
else // CALL GATE TO SAME PRIVILEGE
|
||||
{
|
||||
BX_DEBUG(("CALL GATE TO SAME PRIVILEGE"));
|
||||
|
||||
if (gate_descriptor->type == BX_386_CALL_GATE) {
|
||||
// call gate 32bit, push return address onto stack
|
||||
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_32(EIP);
|
||||
}
|
||||
else {
|
||||
// call gate 16bit, push return address onto stack
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_16(IP);
|
||||
}
|
||||
|
||||
// load CS:EIP from gate
|
||||
// load code segment descriptor into CS register
|
||||
// set RPL of CS to CPL
|
||||
branch_far32(&cs_selector, &cs_descriptor, new_EIP, CPL);
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::call_gate64(bx_selector_t *gate_selector)
|
||||
{
|
||||
bx_selector_t cs_selector;
|
||||
Bit32u dword1, dword2, dword3;
|
||||
bx_descriptor_t cs_descriptor;
|
||||
bx_descriptor_t gate_descriptor;
|
||||
|
||||
// examine code segment selector in call gate descriptor
|
||||
BX_DEBUG(("call_gate64: CALL 64bit call gate"));
|
||||
|
||||
fetch_raw_descriptor_64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &gate_descriptor);
|
||||
|
||||
Bit16u dest_selector = gate_descriptor.u.gate.dest_selector;
|
||||
// selector must not be null else #GP(0)
|
||||
if ((dest_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("call_gate64: selector in gate null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(dest_selector, &cs_selector);
|
||||
// selector must be within its descriptor table limits,
|
||||
// else #GP(code segment selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// find the RIP in the gate_descriptor
|
||||
Bit64u new_RIP = gate_descriptor.u.gate.dest_offset;
|
||||
new_RIP |= ((Bit64u)dword3 << 32);
|
||||
|
||||
// AR byte of selected descriptor must indicate code segment,
|
||||
// else #GP(code segment selector)
|
||||
// DPL of selected descriptor must be <= CPL,
|
||||
// else #GP(code segment selector)
|
||||
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
|
||||
IS_DATA_SEGMENT(cs_descriptor.type) ||
|
||||
cs_descriptor.dpl > CPL)
|
||||
{
|
||||
BX_ERROR(("call_gate64: selected descriptor is not code"));
|
||||
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// In long mode, only 64-bit call gates are allowed, and they must point
|
||||
// to 64-bit code segments, else #GP(selector)
|
||||
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
|
||||
{
|
||||
BX_ERROR(("call_gate64: not 64-bit code segment in call gate 64"));
|
||||
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// code segment must be present else #NP(selector)
|
||||
if (! IS_PRESENT(cs_descriptor)) {
|
||||
BX_ERROR(("call_gate64: code segment not present !"));
|
||||
exception(BX_NP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
Bit64u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
|
||||
Bit64u old_RIP = RIP;
|
||||
|
||||
// CALL GATE TO MORE PRIVILEGE
|
||||
// if non-conforming code segment and DPL < CPL then
|
||||
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && (cs_descriptor.dpl < CPL))
|
||||
{
|
||||
BX_DEBUG(("CALL GATE TO MORE PRIVILEGE LEVEL"));
|
||||
|
||||
// get new RSP for new privilege level from TSS
|
||||
Bit64u RSP_for_cpl_x = get_RSP_from_TSS(cs_descriptor.dpl);
|
||||
Bit64u old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
|
||||
Bit64u old_RSP = RSP;
|
||||
|
||||
// push old stack long pointer onto new stack
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
|
||||
// push long pointer to return address onto new stack
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_RIP);
|
||||
RSP_for_cpl_x -= 32;
|
||||
|
||||
// load CS:RIP (guaranteed to be in 64 bit mode)
|
||||
branch_far64(&cs_selector, &cs_descriptor, new_RIP, cs_descriptor.dpl);
|
||||
|
||||
// set up null SS descriptor
|
||||
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], cs_descriptor.dpl);
|
||||
|
||||
RSP = RSP_for_cpl_x;
|
||||
}
|
||||
else
|
||||
{
|
||||
BX_DEBUG(("CALL GATE TO SAME PRIVILEGE"));
|
||||
|
||||
// push to 64-bit stack, switch to long64 guaranteed
|
||||
write_new_stack_qword_64(RSP - 8, CPL, old_CS);
|
||||
write_new_stack_qword_64(RSP - 16, CPL, old_RIP);
|
||||
|
||||
// load CS:RIP (guaranteed to be in 64 bit mode)
|
||||
branch_far64(&cs_selector, &cs_descriptor, new_RIP, CPL);
|
||||
|
||||
RSP -= 16;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
1003
simulators/bochs/cpu/cpu.cc
Normal file
1003
simulators/bochs/cpu/cpu.cc
Normal file
File diff suppressed because it is too large
Load Diff
3972
simulators/bochs/cpu/cpu.h
Normal file
3972
simulators/bochs/cpu/cpu.h
Normal file
File diff suppressed because it is too large
Load Diff
1133
simulators/bochs/cpu/cpuid.cc
Executable file
1133
simulators/bochs/cpu/cpuid.cc
Executable file
File diff suppressed because it is too large
Load Diff
140
simulators/bochs/cpu/crc32.cc
Executable file
140
simulators/bochs/cpu/crc32.cc
Executable file
@ -0,0 +1,140 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// 3-byte opcodes
|
||||
|
||||
#define CRC32_POLYNOMIAL BX_CONST64(0x11edc6f41)
|
||||
|
||||
// primitives for CRC32 usage
|
||||
BX_CPP_INLINE Bit8u BitReflect8(Bit8u val8)
|
||||
{
|
||||
return ((val8 & 0x80) >> 7) |
|
||||
((val8 & 0x40) >> 5) |
|
||||
((val8 & 0x20) >> 3) |
|
||||
((val8 & 0x10) >> 1) |
|
||||
((val8 & 0x08) << 1) |
|
||||
((val8 & 0x04) << 3) |
|
||||
((val8 & 0x02) << 5) |
|
||||
((val8 & 0x01) << 7);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE Bit16u BitReflect16(Bit16u val16)
|
||||
{
|
||||
return ((Bit16u)(BitReflect8(val16 & 0xff)) << 8) | BitReflect8(val16 >> 8);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE Bit32u BitReflect32(Bit32u val32)
|
||||
{
|
||||
return ((Bit32u)(BitReflect16(val32 & 0xffff)) << 16) | BitReflect16(val32 >> 16);
|
||||
}
|
||||
|
||||
static Bit32u mod2_64bit(Bit64u divisor, Bit64u dividend)
|
||||
{
|
||||
Bit64u remainder = dividend >> 32;
|
||||
|
||||
for (int bitpos=31; bitpos>=0; bitpos--) {
|
||||
// copy one more bit from the dividend
|
||||
remainder = (remainder << 1) | ((dividend >> bitpos) & 1);
|
||||
|
||||
// if MSB is set, then XOR divisor and get new remainder
|
||||
if (((remainder >> 32) & 1) == 1) {
|
||||
remainder ^= divisor;
|
||||
}
|
||||
}
|
||||
|
||||
return (Bit32u) remainder;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2 = BitReflect32(op2);
|
||||
|
||||
Bit64u tmp1 = ((Bit64u) BitReflect8 (op1)) << 32;
|
||||
Bit64u tmp2 = ((Bit64u) op2) << 8;
|
||||
Bit64u tmp3 = tmp1 ^ tmp2;
|
||||
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2 = BitReflect32(op2);
|
||||
Bit16u op1 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
Bit64u tmp1 = ((Bit64u) BitReflect16(op1)) << 32;
|
||||
Bit64u tmp2 = ((Bit64u) op2) << 16;
|
||||
Bit64u tmp3 = tmp1 ^ tmp2;
|
||||
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2 = BitReflect32(op2);
|
||||
Bit32u op1 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
Bit64u tmp1 = ((Bit64u) BitReflect32(op1)) << 32;
|
||||
Bit64u tmp2 = ((Bit64u) op2) << 32;
|
||||
Bit64u tmp3 = tmp1 ^ tmp2;
|
||||
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CRC32_GdEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2 = BitReflect32(op2);
|
||||
Bit64u op1 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
Bit64u tmp1 = ((Bit64u) BitReflect32(op1 & 0xffffffff)) << 32;
|
||||
Bit64u tmp2 = ((Bit64u) op2) << 32;
|
||||
Bit64u tmp3 = tmp1 ^ tmp2;
|
||||
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
|
||||
tmp1 = ((Bit64u) BitReflect32(op1 >> 32)) << 32;
|
||||
tmp2 = ((Bit64u) op2) << 32;
|
||||
tmp3 = tmp1 ^ tmp2;
|
||||
op2 = mod2_64bit(CRC32_POLYNOMIAL, tmp3);
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BitReflect32(op2));
|
||||
}
|
||||
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
1282
simulators/bochs/cpu/crregs.cc
Executable file
1282
simulators/bochs/cpu/crregs.cc
Executable file
File diff suppressed because it is too large
Load Diff
222
simulators/bochs/cpu/crregs.h
Executable file
222
simulators/bochs/cpu/crregs.h
Executable file
@ -0,0 +1,222 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_CRREGS
|
||||
#define BX_CRREGS
|
||||
|
||||
struct bx_cr0_t {
|
||||
Bit32u val32; // 32bit value of register
|
||||
|
||||
// Accessors for all cr0 bitfields.
|
||||
#define IMPLEMENT_CRREG_ACCESSORS(name, bitnum) \
|
||||
BX_CPP_INLINE bx_bool get_##name () { \
|
||||
return 1 & (val32 >> bitnum); \
|
||||
} \
|
||||
BX_CPP_INLINE void set_##name (Bit8u val) { \
|
||||
val32 = (val32 & ~(1<<bitnum)) | ((!!val) << bitnum); \
|
||||
}
|
||||
|
||||
// CR0 notes:
|
||||
// Each x86 level has its own quirks regarding how it handles
|
||||
// reserved bits. I used DOS DEBUG.EXE in real mode on the
|
||||
// following processors, tried to clear bits 1..30, then tried
|
||||
// to set bits 1..30, to see how these bits are handled.
|
||||
// I found the following:
|
||||
//
|
||||
// Processor try to clear bits 1..30 try to set bits 1..30
|
||||
// 386 7FFFFFF0 7FFFFFFE
|
||||
// 486DX2 00000010 6005003E
|
||||
// Pentium 00000010 7FFFFFFE
|
||||
// Pentium-II 00000010 6005003E
|
||||
//
|
||||
// My assumptions:
|
||||
// All processors: bit 4 is hardwired to 1 (not true on all clones)
|
||||
// 386: bits 5..30 of CR0 are also hardwired to 1
|
||||
// Pentium: reserved bits retain value set using mov cr0, reg32
|
||||
// 486DX2/Pentium-II: reserved bits are hardwired to 0
|
||||
|
||||
IMPLEMENT_CRREG_ACCESSORS(PE, 0);
|
||||
IMPLEMENT_CRREG_ACCESSORS(MP, 1);
|
||||
IMPLEMENT_CRREG_ACCESSORS(EM, 2);
|
||||
IMPLEMENT_CRREG_ACCESSORS(TS, 3);
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
IMPLEMENT_CRREG_ACCESSORS(ET, 4);
|
||||
IMPLEMENT_CRREG_ACCESSORS(NE, 5);
|
||||
IMPLEMENT_CRREG_ACCESSORS(WP, 16);
|
||||
IMPLEMENT_CRREG_ACCESSORS(AM, 18);
|
||||
IMPLEMENT_CRREG_ACCESSORS(NW, 29);
|
||||
IMPLEMENT_CRREG_ACCESSORS(CD, 30);
|
||||
#endif
|
||||
IMPLEMENT_CRREG_ACCESSORS(PG, 31);
|
||||
|
||||
BX_CPP_INLINE Bit32u get32() { return val32; }
|
||||
// ET is hardwired bit in CR0
|
||||
BX_CPP_INLINE void set32(Bit32u val) { val32 = val | 0x10; }
|
||||
};
|
||||
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
|
||||
#define BX_CR4_VME_MASK (1 << 0)
|
||||
#define BX_CR4_PVI_MASK (1 << 1)
|
||||
#define BX_CR4_TSD_MASK (1 << 2)
|
||||
#define BX_CR4_DE_MASK (1 << 3)
|
||||
#define BX_CR4_PSE_MASK (1 << 4)
|
||||
#define BX_CR4_PAE_MASK (1 << 5)
|
||||
#define BX_CR4_MCE_MASK (1 << 6)
|
||||
#define BX_CR4_PGE_MASK (1 << 7)
|
||||
#define BX_CR4_PCE_MASK (1 << 8)
|
||||
#define BX_CR4_OSFXSR_MASK (1 << 9)
|
||||
#define BX_CR4_OSXMMEXCPT_MASK (1 << 10)
|
||||
#define BX_CR4_VMXE_MASK (1 << 13)
|
||||
#define BX_CR4_SMXE_MASK (1 << 14)
|
||||
#define BX_CR4_FSGSBASE_MASK (1 << 16)
|
||||
#define BX_CR4_PCIDE_MASK (1 << 17)
|
||||
#define BX_CR4_OSXSAVE_MASK (1 << 18)
|
||||
|
||||
struct bx_cr4_t {
|
||||
Bit32u val32; // 32bit value of register
|
||||
|
||||
IMPLEMENT_CRREG_ACCESSORS(VME, 0);
|
||||
IMPLEMENT_CRREG_ACCESSORS(PVI, 1);
|
||||
IMPLEMENT_CRREG_ACCESSORS(TSD, 2);
|
||||
IMPLEMENT_CRREG_ACCESSORS(DE, 3);
|
||||
IMPLEMENT_CRREG_ACCESSORS(PSE, 4);
|
||||
IMPLEMENT_CRREG_ACCESSORS(PAE, 5);
|
||||
IMPLEMENT_CRREG_ACCESSORS(MCE, 6);
|
||||
IMPLEMENT_CRREG_ACCESSORS(PGE, 7);
|
||||
IMPLEMENT_CRREG_ACCESSORS(PCE, 8);
|
||||
IMPLEMENT_CRREG_ACCESSORS(OSFXSR, 9);
|
||||
IMPLEMENT_CRREG_ACCESSORS(OSXMMEXCPT, 10);
|
||||
#if BX_SUPPORT_VMX
|
||||
IMPLEMENT_CRREG_ACCESSORS(VMXE, 13);
|
||||
#endif
|
||||
#if BX_SUPPORT_X86_64
|
||||
IMPLEMENT_CRREG_ACCESSORS(FSGSBASE, 16);
|
||||
IMPLEMENT_CRREG_ACCESSORS(PCIDE, 17);
|
||||
#endif
|
||||
IMPLEMENT_CRREG_ACCESSORS(OSXSAVE, 18);
|
||||
|
||||
BX_CPP_INLINE Bit32u get32() { return val32; }
|
||||
BX_CPP_INLINE void set32(Bit32u val) { val32 = val; }
|
||||
};
|
||||
|
||||
#define BX_CR4_FLUSH_TLB_MASK \
|
||||
(BX_CR4_PSE_MASK | BX_CR4_PAE_MASK | BX_CR4_PGE_MASK | BX_CR4_PCIDE_MASK)
|
||||
|
||||
#endif // #if BX_CPU_LEVEL >= 4
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
#define BX_EFER_SCE_MASK (1 << 0)
|
||||
#define BX_EFER_LME_MASK (1 << 8)
|
||||
#define BX_EFER_LMA_MASK (1 << 10)
|
||||
#define BX_EFER_NXE_MASK (1 << 11)
|
||||
#define BX_EFER_FFXSR_MASK (1 << 14)
|
||||
|
||||
struct bx_efer_t {
|
||||
Bit32u val32; // 32bit value of register
|
||||
|
||||
IMPLEMENT_CRREG_ACCESSORS(SCE, 0);
|
||||
IMPLEMENT_CRREG_ACCESSORS(LME, 8);
|
||||
IMPLEMENT_CRREG_ACCESSORS(LMA, 10);
|
||||
IMPLEMENT_CRREG_ACCESSORS(NXE, 11);
|
||||
IMPLEMENT_CRREG_ACCESSORS(SVME, 12); /* AMD Secure Virtual Machine */
|
||||
IMPLEMENT_CRREG_ACCESSORS(LMSLE, 13); /* AMD Long Mode Segment Limit */
|
||||
IMPLEMENT_CRREG_ACCESSORS(FFXSR, 14);
|
||||
|
||||
BX_CPP_INLINE Bit32u get32() { return val32; }
|
||||
BX_CPP_INLINE void set32(Bit32u val) { val32 = val; }
|
||||
};
|
||||
|
||||
#define BX_EFER_SUPPORTED_BITS \
|
||||
((Bit64u) (BX_EFER_SCE_MASK | BX_EFER_LME_MASK | \
|
||||
BX_EFER_LMA_MASK | BX_EFER_NXE_MASK | BX_EFER_FFXSR_MASK))
|
||||
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
struct xcr0_t {
|
||||
Bit32u val32; // 32bit value of register
|
||||
|
||||
#define BX_XCR0_SUPPORTED_BITS 0x3
|
||||
|
||||
#define BX_XCR0_FPU_BIT 0
|
||||
#define BX_XCR0_FPU_MASK (1<<BX_XCR0_FPU_BIT)
|
||||
#define BX_XCR0_SSE_BIT 1
|
||||
#define BX_XCR0_SSE_MASK (1<<BX_XCR0_SSE_BIT)
|
||||
|
||||
IMPLEMENT_CRREG_ACCESSORS(FPU, BX_XCR0_FPU_BIT);
|
||||
IMPLEMENT_CRREG_ACCESSORS(SSE, BX_XCR0_SSE_BIT);
|
||||
|
||||
BX_CPP_INLINE Bit32u get32() { return val32; }
|
||||
BX_CPP_INLINE void set32(Bit32u val) { val32 = val; }
|
||||
};
|
||||
#endif
|
||||
|
||||
#undef IMPLEMENT_CRREG_ACCESSORS
|
||||
|
||||
typedef struct msr {
|
||||
unsigned index; // MSR index
|
||||
unsigned type; // MSR type: 1 - lin address, 2 - phy address
|
||||
#define BX_LIN_ADDRESS_MSR 1
|
||||
#define BX_PHY_ADDRESS_MSR 2
|
||||
Bit64u val64; // current MSR value
|
||||
Bit64u reset_value; // reset value
|
||||
Bit64u reserved; // r/o bits - fault on write
|
||||
Bit64u ignored; // hardwired bits - ignored on write
|
||||
|
||||
// workaround for an 'index(a,b)' macro definition clash in some system header in conjunction with AspectC++
|
||||
#undef index
|
||||
|
||||
msr(unsigned idx, unsigned msr_type = 0, Bit64u reset_val = 0, Bit64u rsrv = 0, Bit64u ign = 0):
|
||||
index(idx), type(msr_type), val64(reset_val), reset_value(reset_val),
|
||||
reserved(rsrv), ignored(ign) {}
|
||||
|
||||
msr(unsigned idx, Bit64u reset_val = 0, Bit64u rsrv = 0, Bit64u ign = 0):
|
||||
index(idx), type(0), val64(reset_val), reset_value(reset_val),
|
||||
reserved(rsrv), ignored(ign) {}
|
||||
|
||||
BX_CPP_INLINE void reset() { val64 = reset_value; }
|
||||
BX_CPP_INLINE Bit64u get64() { return val64; }
|
||||
|
||||
BX_CPP_INLINE bx_bool set64(Bit64u new_val) {
|
||||
new_val = (new_val & ~ignored) | (val64 & ignored);
|
||||
switch(type) {
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LIN_ADDRESS_MSR:
|
||||
if (! IsCanonical(new_val)) return 0;
|
||||
break;
|
||||
#endif
|
||||
case BX_PHY_ADDRESS_MSR:
|
||||
if (! IsValidPhyAddr(new_val)) return 0;
|
||||
break;
|
||||
default:
|
||||
if ((val64 ^ new_val) & reserved) return 0;
|
||||
break;
|
||||
}
|
||||
val64 = new_val;
|
||||
return 1;
|
||||
}
|
||||
} MSR;
|
||||
|
||||
#endif
|
||||
785
simulators/bochs/cpu/ctrl_xfer16.cc
Normal file
785
simulators/bochs/cpu/ctrl_xfer16.cc
Normal file
@ -0,0 +1,785 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RSP ESP
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near16(Bit16u new_IP)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
// check always, not only in protected mode
|
||||
if (new_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
|
||||
{
|
||||
BX_ERROR(("branch_near16: offset outside of CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
EIP = new_IP;
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE && !defined(BX_TRACE_CACHE_NO_SPECULATIVE_TRACING)
|
||||
// assert magic async_event to stop trace execution
|
||||
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear16_Iw(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u return_IP = pop_16();
|
||||
|
||||
if (return_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
|
||||
{
|
||||
BX_ERROR(("RETnear16_Iw: IP > limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
EIP = return_IP;
|
||||
|
||||
Bit16u imm16 = i->Iw();
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) /* 32bit stack */
|
||||
ESP += imm16;
|
||||
else
|
||||
SP += imm16;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear16(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u return_IP = pop_16();
|
||||
|
||||
if (return_IP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
|
||||
{
|
||||
BX_ERROR(("RETnear16: IP > limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
EIP = return_IP;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar16_Iw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u ip, cs_raw;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
Bit16s imm16 = (Bit16s) i->Iw();
|
||||
|
||||
if (protected_mode()) {
|
||||
return_protected(i, imm16);
|
||||
goto done;
|
||||
}
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
ip = pop_16();
|
||||
cs_raw = pop_16();
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("RETfar16_Iw: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = (Bit32u) ip;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
ESP += imm16;
|
||||
else
|
||||
SP += imm16;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar16(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u ip, cs_raw;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
if (protected_mode()) {
|
||||
return_protected(i, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
ip = pop_16();
|
||||
cs_raw = pop_16();
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("RETfar16: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = (Bit32u) ip;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_Jw(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
/* push 16 bit EA of next instruction */
|
||||
push_16(IP);
|
||||
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL16_Ap(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
Bit16u disp16 = i->Iw();
|
||||
Bit16u cs_raw = i->Iw2();
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (protected_mode()) {
|
||||
call_protected(i, cs_raw, disp16);
|
||||
goto done;
|
||||
}
|
||||
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_16(IP);
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (disp16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("CALL16_Ap: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = (Bit32u) disp16;
|
||||
|
||||
done:
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_EwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u new_IP = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
/* push 16 bit EA of next instruction */
|
||||
push_16(IP);
|
||||
|
||||
branch_near16(new_IP);
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL16_Ep(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u cs_raw;
|
||||
Bit16u op1_16;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_virtual_word(i->seg(), eaddr);
|
||||
cs_raw = read_virtual_word(i->seg(), (eaddr+2) & i->asize_mask());
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (protected_mode()) {
|
||||
call_protected(i, cs_raw, op1_16);
|
||||
goto done;
|
||||
}
|
||||
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_16(IP);
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (op1_16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("CALL16_Ep: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = op1_16;
|
||||
|
||||
done:
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Jw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_IP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_OF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_CF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF() || get_ZF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! (get_CF() || get_ZF())) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_SF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_SF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_PF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_PF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() != getB_OF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() == getB_OF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF() || (getB_SF() != getB_OF())) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jw(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF() && (getB_SF() == getB_OF())) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_EwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u new_IP = BX_READ_16BIT_REG(i->rm());
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_IP);
|
||||
}
|
||||
|
||||
/* Far indirect jump */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP16_Ep(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u cs_raw;
|
||||
Bit16u op1_16;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_virtual_word(i->seg(), eaddr);
|
||||
cs_raw = read_virtual_word(i->seg(), (eaddr+2) & i->asize_mask());
|
||||
|
||||
// jump_protected doesn't affect RSP so it is RSP safe
|
||||
if (protected_mode()) {
|
||||
jump_protected(i, cs_raw, op1_16);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (op1_16 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("JMP16_Ep: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = op1_16;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET16(bxInstruction_c *i)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
|
||||
#endif
|
||||
BX_CPU_THIS_PTR disable_NMI = 0;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_iret;
|
||||
#endif
|
||||
|
||||
if (protected_mode()) {
|
||||
iret_protected(i);
|
||||
goto done;
|
||||
}
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (v8086_mode()) {
|
||||
// IOPL check in stack_return_from_v86()
|
||||
iret16_stack_return_from_v86(i);
|
||||
}
|
||||
else {
|
||||
Bit16u ip = pop_16();
|
||||
Bit16u cs_raw = pop_16(); // #SS has higher priority
|
||||
Bit16u flags = pop_16();
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if(ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("IRET16: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = (Bit32u) ip;
|
||||
write_flags(flags, /* change IOPL? */ 1, /* change IF? */ 1);
|
||||
}
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_IRET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JCXZ_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
Bit32u temp_ECX;
|
||||
|
||||
if (i->as32L())
|
||||
temp_ECX = ECX;
|
||||
else
|
||||
temp_ECX = CX;
|
||||
|
||||
if (temp_ECX == 0) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// There is some weirdness in LOOP instructions definition. If an exception
|
||||
// was generated during the instruction execution (for example #GP fault
|
||||
// because EIP was beyond CS segment limits) CPU state should restore the
|
||||
// state prior to instruction execution.
|
||||
//
|
||||
// The final point that we are not allowed to decrement ECX register before
|
||||
// it is known that no exceptions can happen.
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE16_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
if (i->as32L()) {
|
||||
Bit32u count = ECX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && (get_ZF()==0)) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
ECX = count;
|
||||
}
|
||||
else {
|
||||
Bit16u count = CX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && (get_ZF()==0)) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
CX = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE16_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
if (i->as32L()) {
|
||||
Bit32u count = ECX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && get_ZF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
ECX = count;
|
||||
}
|
||||
else {
|
||||
Bit16u count = CX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && get_ZF()) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
CX = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP16_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
if (i->as32L()) {
|
||||
Bit32u count = ECX;
|
||||
|
||||
count--;
|
||||
if (count != 0) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
ECX = count;
|
||||
}
|
||||
else {
|
||||
Bit16u count = CX;
|
||||
|
||||
count--;
|
||||
if (count != 0) {
|
||||
Bit16u new_IP = IP + i->Iw();
|
||||
branch_near16(new_IP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_IP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
CX = count;
|
||||
}
|
||||
}
|
||||
829
simulators/bochs/cpu/ctrl_xfer32.cc
Normal file
829
simulators/bochs/cpu/ctrl_xfer32.cc
Normal file
@ -0,0 +1,829 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RSP ESP
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near32(Bit32u new_EIP)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
// check always, not only in protected mode
|
||||
if (new_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
|
||||
{
|
||||
BX_ERROR(("branch_near32: offset outside of CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
EIP = new_EIP;
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE && !defined(BX_TRACE_CACHE_NO_SPECULATIVE_TRACING)
|
||||
// assert magic async_event to stop trace execution
|
||||
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear32_Iw(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u imm16 = i->Iw();
|
||||
Bit32u return_EIP = pop_32();
|
||||
if (return_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
|
||||
{
|
||||
BX_ERROR(("RETnear32_Iw: offset outside of CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
EIP = return_EIP;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
ESP += imm16;
|
||||
else
|
||||
SP += imm16;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear32(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit32u return_EIP = pop_32();
|
||||
if (return_EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled)
|
||||
{
|
||||
BX_ERROR(("RETnear32: offset outside of CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
EIP = return_EIP;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar32_Iw(bxInstruction_c *i)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
Bit16u imm16 = i->Iw();
|
||||
Bit16u cs_raw;
|
||||
Bit32u eip;
|
||||
|
||||
if (protected_mode()) {
|
||||
return_protected(i, imm16);
|
||||
goto done;
|
||||
}
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
eip = pop_32();
|
||||
cs_raw = (Bit16u) pop_32(); /* 32bit pop, MSW discarded */
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (eip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("RETfar32_Iw: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = eip;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
ESP += imm16;
|
||||
else
|
||||
SP += imm16;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar32(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u eip;
|
||||
Bit16u cs_raw;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
if (protected_mode()) {
|
||||
return_protected(i, 0);
|
||||
goto done;
|
||||
}
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
eip = pop_32();
|
||||
cs_raw = (Bit16u) pop_32(); /* 32bit pop, MSW discarded */
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (eip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("RETfar32: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = eip;
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_Jd(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
Bit32u new_EIP = EIP + i->Id();
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
/* push 32 bit EA of next instruction */
|
||||
push_32(EIP);
|
||||
|
||||
branch_near32(new_EIP);
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL32_Ap(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit16u cs_raw;
|
||||
Bit32u disp32;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
disp32 = i->Id();
|
||||
cs_raw = i->Iw2();
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (protected_mode()) {
|
||||
call_protected(i, cs_raw, disp32);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (disp32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("CALL32_Ap: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_32(EIP);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = disp32;
|
||||
|
||||
done:
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_EdR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
Bit32u new_EIP = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
/* push 32 bit EA of next instruction */
|
||||
push_32(EIP);
|
||||
|
||||
branch_near32(new_EIP);
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL32_Ep(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u cs_raw;
|
||||
Bit32u op1_32;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
cs_raw = read_virtual_word (i->seg(), (eaddr+4) & i->asize_mask());
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (protected_mode()) {
|
||||
call_protected(i, cs_raw, op1_32);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (op1_32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("CALL32_Ep: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_32(EIP);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = op1_32;
|
||||
|
||||
done:
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Jd(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_CF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF() || get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! (get_CF() || get_ZF())) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_SF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_SF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_PF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_PF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() != getB_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() == getB_OF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF() || (getB_SF() != getB_OF())) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jd(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF() && (getB_SF() == getB_OF())) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Ap(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit32u disp32;
|
||||
Bit16u cs_raw;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
if (i->os32L()) {
|
||||
disp32 = i->Id();
|
||||
}
|
||||
else {
|
||||
disp32 = i->Iw();
|
||||
}
|
||||
cs_raw = i->Iw2();
|
||||
|
||||
// jump_protected doesn't affect ESP so it is ESP safe
|
||||
if (protected_mode()) {
|
||||
jump_protected(i, cs_raw, disp32);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (disp32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("JMP_Ap: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = disp32;
|
||||
|
||||
done:
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u new_EIP = BX_READ_32BIT_REG(i->rm());
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, new_EIP);
|
||||
}
|
||||
|
||||
/* Far indirect jump */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP32_Ep(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u cs_raw;
|
||||
Bit32u op1_32;
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
cs_raw = read_virtual_word (i->seg(), (eaddr+4) & i->asize_mask());
|
||||
|
||||
// jump_protected doesn't affect RSP so it is RSP safe
|
||||
if (protected_mode()) {
|
||||
jump_protected(i, cs_raw, op1_32);
|
||||
goto done;
|
||||
}
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (op1_32 > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("JMP32_Ep: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = op1_32;
|
||||
|
||||
done:
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET32(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
|
||||
#endif
|
||||
BX_CPU_THIS_PTR disable_NMI = 0;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_iret;
|
||||
#endif
|
||||
|
||||
if (protected_mode()) {
|
||||
iret_protected(i);
|
||||
goto done;
|
||||
}
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (v8086_mode()) {
|
||||
// IOPL check in stack_return_from_v86()
|
||||
iret32_stack_return_from_v86(i);
|
||||
}
|
||||
else {
|
||||
Bit32u eip = pop_32();
|
||||
Bit16u cs_raw = (Bit16u) pop_32(); // #SS has higher priority
|
||||
Bit32u eflags32 = pop_32();
|
||||
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (eip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("IRET32: instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = eip;
|
||||
writeEFlags(eflags32, 0x00257fd5); // VIF, VIP, VM unchanged
|
||||
}
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
done:
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_IRET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JECXZ_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
Bit32u temp_ECX;
|
||||
|
||||
if (i->as32L())
|
||||
temp_ECX = ECX;
|
||||
else
|
||||
temp_ECX = CX;
|
||||
|
||||
if (temp_ECX == 0) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// There is some weirdness in LOOP instructions definition. If an exception
|
||||
// was generated during the instruction execution (for example #GP fault
|
||||
// because EIP was beyond CS segment limits) CPU state should restore the
|
||||
// state prior to instruction execution.
|
||||
//
|
||||
// The final point that we are not allowed to decrement ECX register before
|
||||
// it is known that no exceptions can happen.
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE32_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
if (i->as32L()) {
|
||||
Bit32u count = ECX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && (get_ZF()==0)) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
ECX = count;
|
||||
}
|
||||
else {
|
||||
Bit16u count = CX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && (get_ZF()==0)) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
CX = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE32_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
if (i->as32L()) {
|
||||
Bit32u count = ECX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
ECX = count;
|
||||
}
|
||||
else {
|
||||
Bit16u count = CX;
|
||||
|
||||
count--;
|
||||
if (count != 0 && get_ZF()) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
CX = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP32_Jb(bxInstruction_c *i)
|
||||
{
|
||||
// it is impossible to get this instruction in long mode
|
||||
BX_ASSERT(i->as64L() == 0);
|
||||
|
||||
if (i->as32L()) {
|
||||
Bit32u count = ECX;
|
||||
|
||||
count--;
|
||||
if (count != 0) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
ECX = count;
|
||||
}
|
||||
else {
|
||||
Bit16u count = CX;
|
||||
|
||||
count--;
|
||||
if (count != 0) {
|
||||
Bit32u new_EIP = EIP + (Bit32s) i->Id();
|
||||
branch_near32(new_EIP);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, new_EIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
CX = count;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
576
simulators/bochs/cpu/ctrl_xfer64.cc
Normal file
576
simulators/bochs/cpu/ctrl_xfer64.cc
Normal file
@ -0,0 +1,576 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1) BX_CPU_C::branch_near64(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u new_RIP = RIP + (Bit32s) i->Id();
|
||||
|
||||
if (! IsCanonical(new_RIP)) {
|
||||
BX_ERROR(("branch_near64: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = new_RIP;
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE && !defined(BX_TRACE_CACHE_NO_SPECULATIVE_TRACING)
|
||||
// assert magic async_event to stop trace execution
|
||||
BX_CPU_THIS_PTR async_event |= BX_ASYNC_EVENT_STOP_TRACE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear64_Iw(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
Bit64u return_RIP = read_virtual_qword_64(BX_SEG_REG_SS, RSP);
|
||||
|
||||
if (! IsCanonical(return_RIP)) {
|
||||
BX_ERROR(("RETnear64_Iw: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = return_RIP;
|
||||
RSP += 8 + i->Iw();
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETnear64(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
Bit64u return_RIP = read_virtual_qword_64(BX_SEG_REG_SS, RSP);
|
||||
|
||||
if (! IsCanonical(return_RIP)) {
|
||||
BX_ERROR(("RETnear64: canonical RIP violation %08x%08x", GET32H(return_RIP), GET32L(return_RIP)));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = return_RIP;
|
||||
RSP += 8;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RETfar64_Iw(bxInstruction_c *i)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_ret;
|
||||
#endif
|
||||
|
||||
BX_ASSERT(protected_mode());
|
||||
|
||||
// return_protected is RSP safe
|
||||
return_protected(i, i->Iw());
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_RET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_Jq(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u new_RIP = RIP + (Bit32s) i->Id();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
/* push 64 bit EA of next instruction */
|
||||
write_virtual_qword_64(BX_SEG_REG_SS, RSP-8, RIP);
|
||||
|
||||
if (! IsCanonical(new_RIP)) {
|
||||
BX_ERROR(("CALL_Jq: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = new_RIP;
|
||||
RSP -= 8;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL_EqR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
Bit64u new_RIP = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
/* push 64 bit EA of next instruction */
|
||||
write_virtual_qword_64(BX_SEG_REG_SS, RSP-8, RIP);
|
||||
|
||||
if (! IsCanonical(new_RIP))
|
||||
{
|
||||
BX_ERROR(("CALL_Eq: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = new_RIP;
|
||||
RSP -= 8;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CALL64_Ep(bxInstruction_c *i)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_call;
|
||||
#endif
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
Bit16u cs_raw = read_virtual_word_64(i->seg(), (eaddr+8) & i->asize_mask());
|
||||
|
||||
BX_ASSERT(protected_mode());
|
||||
|
||||
// call_protected is RSP safe for 64-bit mode
|
||||
call_protected(i, cs_raw, op1_64);
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_CALL,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_Jq(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u new_RIP = RIP + (Bit32s) i->Id();
|
||||
|
||||
if (! IsCanonical(new_RIP)) {
|
||||
BX_ERROR(("JMP_Jq: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = new_RIP;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JO_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNO_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_OF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JB_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNB_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_CF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JZ_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNZ_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JBE_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF() || get_ZF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNBE_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! (get_CF() || get_ZF())) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JS_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_SF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNS_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_SF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JP_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_PF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNP_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_PF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JL_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() != getB_OF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNL_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() == getB_OF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JLE_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF() || (getB_SF() != getB_OF())) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JNLE_Jq(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF() && (getB_SF() == getB_OF())) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
if (! IsCanonical(op1_64)) {
|
||||
BX_ERROR(("JMP_Eq: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RIP = op1_64;
|
||||
|
||||
BX_INSTR_UCNEAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP, RIP);
|
||||
}
|
||||
|
||||
/* Far indirect jump */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JMP64_Ep(bxInstruction_c *i)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
Bit16u cs_raw = read_virtual_word_64(i->seg(), (eaddr+8) & i->asize_mask());
|
||||
|
||||
BX_ASSERT(protected_mode());
|
||||
|
||||
jump_protected(i, cs_raw, op1_64);
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_JMP,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IRET64(bxInstruction_c *i)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
if (!BX_CPU_THIS_PTR in_vmx_guest || !VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
|
||||
#endif
|
||||
BX_CPU_THIS_PTR disable_NMI = 0;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_iret;
|
||||
#endif
|
||||
|
||||
BX_ASSERT(long_mode());
|
||||
|
||||
long_iret(i);
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_IRET,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value, RIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::JRCXZ_Jb(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u temp_RCX;
|
||||
|
||||
if (i->as64L())
|
||||
temp_RCX = RCX;
|
||||
else
|
||||
temp_RCX = ECX;
|
||||
|
||||
if (temp_RCX == 0) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// There is some weirdness in LOOP instructions definition. If an exception
|
||||
// was generated during the instruction execution (for example #GP fault
|
||||
// because EIP was beyond CS segment limits) CPU state should restore the
|
||||
// state prior to instruction execution.
|
||||
//
|
||||
// The final point that we are not allowed to decrement RCX register before
|
||||
// it is known that no exceptions can happen.
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPNE64_Jb(bxInstruction_c *i)
|
||||
{
|
||||
if (i->as64L()) {
|
||||
Bit64u count = RCX;
|
||||
|
||||
if (((--count) != 0) && (get_ZF()==0)) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
RCX = count;
|
||||
}
|
||||
else {
|
||||
Bit32u count = ECX;
|
||||
|
||||
if (((--count) != 0) && (get_ZF()==0)) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
RCX = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOPE64_Jb(bxInstruction_c *i)
|
||||
{
|
||||
if (i->as64L()) {
|
||||
Bit64u count = RCX;
|
||||
|
||||
if (((--count) != 0) && get_ZF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
RCX = count;
|
||||
}
|
||||
else {
|
||||
Bit32u count = ECX;
|
||||
|
||||
if (((--count) != 0) && get_ZF()) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
RCX = count;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOOP64_Jb(bxInstruction_c *i)
|
||||
{
|
||||
if (i->as64L()) {
|
||||
Bit64u count = RCX;
|
||||
|
||||
if ((--count) != 0) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
RCX = count;
|
||||
}
|
||||
else {
|
||||
Bit32u count = ECX;
|
||||
|
||||
if ((--count) != 0) {
|
||||
branch_near64(i);
|
||||
BX_INSTR_CNEAR_BRANCH_TAKEN(BX_CPU_ID, RIP);
|
||||
}
|
||||
#if BX_INSTRUMENTATION
|
||||
else {
|
||||
BX_INSTR_CNEAR_BRANCH_NOT_TAKEN(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
|
||||
RCX = count;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
165
simulators/bochs/cpu/ctrl_xfer_pro.cc
Normal file
165
simulators/bochs/cpu/ctrl_xfer_pro.cc
Normal file
@ -0,0 +1,165 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier merging cpu64 & cpu code.
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
/* pass zero in check_rpl if no needed selector RPL checking for
|
||||
non-conforming segments */
|
||||
void BX_CPU_C::check_cs(bx_descriptor_t *descriptor, Bit16u cs_raw, Bit8u check_rpl, Bit8u check_cpl)
|
||||
{
|
||||
// descriptor AR byte must indicate code segment else #GP(selector)
|
||||
if (descriptor->valid==0 || descriptor->segment==0 ||
|
||||
IS_DATA_SEGMENT(descriptor->type))
|
||||
{
|
||||
BX_ERROR(("check_cs(0x%04x): not a valid code segment !", cs_raw));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
if (descriptor->u.segment.l && descriptor->u.segment.d_b) {
|
||||
BX_ERROR(("check_cs(0x%04x): Both CS.L and CS.D_B bits enabled !", cs_raw));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// if non-conforming, code segment descriptor DPL must = CPL else #GP(selector)
|
||||
if (IS_CODE_SEGMENT_NON_CONFORMING(descriptor->type)) {
|
||||
if (descriptor->dpl != check_cpl) {
|
||||
BX_ERROR(("check_cs(0x%04x): non-conforming code seg descriptor dpl != cpl, dpl=%d, cpl=%d",
|
||||
cs_raw, descriptor->dpl, check_cpl));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
/* RPL of destination selector must be <= CPL else #GP(selector) */
|
||||
if (check_rpl > check_cpl) {
|
||||
BX_ERROR(("check_cs(0x%04x): non-conforming code seg selector rpl > cpl, rpl=%d, cpl=%d",
|
||||
cs_raw, check_rpl, check_cpl));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
}
|
||||
// if conforming, then code segment descriptor DPL must <= CPL else #GP(selector)
|
||||
else {
|
||||
if (descriptor->dpl > check_cpl) {
|
||||
BX_ERROR(("check_cs(0x%04x): conforming code seg descriptor dpl > cpl, dpl=%d, cpl=%d",
|
||||
cs_raw, descriptor->dpl, check_cpl));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
// code segment must be present else #NP(selector)
|
||||
if (! descriptor->p) {
|
||||
BX_ERROR(("check_cs(0x%04x): code segment not present !", cs_raw));
|
||||
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::load_cs(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl)
|
||||
{
|
||||
// Add cpl to the selector value.
|
||||
selector->value = (0xfffc & selector->value) | cpl;
|
||||
|
||||
touch_segment(selector, descriptor);
|
||||
|
||||
#ifdef BX_SUPPORT_CS_LIMIT_DEMOTION
|
||||
// Handle special case of CS.LIMIT demotion (new descriptor limit is
|
||||
// smaller than current one)
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled > descriptor->u.segment.limit_scaled)
|
||||
BX_CPU_THIS_PTR iCache.flushICacheEntries();
|
||||
#endif
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector = *selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache = *descriptor;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = cpl;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 1;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
handleCpuModeChange();
|
||||
}
|
||||
#endif
|
||||
|
||||
updateFetchModeMask(/* CS reloaded */);
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck(/* CPL change */);
|
||||
#endif
|
||||
|
||||
// Loading CS will invalidate the EIP fetch window.
|
||||
invalidate_prefetch_q();
|
||||
}
|
||||
|
||||
void BX_CPU_C::branch_far32(bx_selector_t *selector,
|
||||
bx_descriptor_t *descriptor, Bit32u eip, Bit8u cpl)
|
||||
{
|
||||
/* instruction pointer must be in code segment limit else #GP(0) */
|
||||
if (eip > descriptor->u.segment.limit_scaled) {
|
||||
BX_ERROR(("branch_far32: EIP > limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* Load CS:IP from destination pointer */
|
||||
/* Load CS-cache with new segment descriptor */
|
||||
load_cs(selector, descriptor, cpl);
|
||||
|
||||
/* Change the EIP value */
|
||||
EIP = eip;
|
||||
}
|
||||
|
||||
void BX_CPU_C::branch_far64(bx_selector_t *selector,
|
||||
bx_descriptor_t *descriptor, bx_address rip, Bit8u cpl)
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode() && descriptor->u.segment.l) {
|
||||
if (! IsCanonical(rip)) {
|
||||
BX_ERROR(("branch_far64: canonical RIP violation"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
rip &= 0xffffffff;
|
||||
|
||||
/* instruction pointer must be in code segment limit else #GP(0) */
|
||||
if (rip > descriptor->u.segment.limit_scaled) {
|
||||
BX_ERROR(("branch_far64: RIP > limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Load CS:IP from destination pointer */
|
||||
/* Load CS-cache with new segment descriptor */
|
||||
load_cs(selector, descriptor, cpl);
|
||||
|
||||
/* Change the RIP value */
|
||||
RIP = rip;
|
||||
}
|
||||
313
simulators/bochs/cpu/data_xfer16.cc
Normal file
313
simulators/bochs/cpu/data_xfer16.cc
Normal file
@ -0,0 +1,313 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RXIw(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_16BIT_REG(i->rm(), i->Iw());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_RXAX(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u temp16 = AX;
|
||||
AX = BX_READ_16BIT_REG(i->rm());
|
||||
BX_WRITE_16BIT_REG(i->rm(), temp16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word(i->seg(), eaddr, BX_READ_16BIT_REG(i->nnn()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GwEwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u val16 = read_virtual_word(i->seg(), eaddr);
|
||||
BX_WRITE_16BIT_REG(i->nnn(), val16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwSwR(bxInstruction_c *i)
|
||||
{
|
||||
/* Illegal to use nonexisting segments */
|
||||
if (i->nnn() >= 6) {
|
||||
BX_INFO(("MOV_EwSw: using of nonexisting segment register %d", i->nnn()));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit16u seg_reg = BX_CPU_THIS_PTR sregs[i->nnn()].selector.value;
|
||||
|
||||
if (i->os32L()) {
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), seg_reg);
|
||||
}
|
||||
else {
|
||||
BX_WRITE_16BIT_REG(i->rm(), seg_reg);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwSwM(bxInstruction_c *i)
|
||||
{
|
||||
/* Illegal to use nonexisting segments */
|
||||
if (i->nnn() >= 6) {
|
||||
BX_INFO(("MOV_EwSw: using of nonexisting segment register %d", i->nnn()));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u seg_reg = BX_CPU_THIS_PTR sregs[i->nnn()].selector.value;
|
||||
write_virtual_word(i->seg(), eaddr, seg_reg);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_SwEw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16;
|
||||
|
||||
/* Attempt to load CS or nonexisting segment register */
|
||||
if (i->nnn() >= 6 || i->nnn() == BX_SEG_REG_CS) {
|
||||
BX_INFO(("MOV_EwSw: can't use this segment register %d", i->nnn()));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (i->modC0()) {
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
op2_16 = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[i->nnn()], op2_16);
|
||||
|
||||
if (i->nnn() == BX_SEG_REG_SS) {
|
||||
// MOV SS inhibits interrupts, debug exceptions and single-step
|
||||
// trap exceptions until the execution boundary following the
|
||||
// next instruction is reached.
|
||||
// Same code as POP_SS()
|
||||
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS_BY_MOVSS;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) eaddr);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_AXOd(bxInstruction_c *i)
|
||||
{
|
||||
AX = read_virtual_word_32(i->seg(), i->Id());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OdAX(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_word_32(i->seg(), i->Id(), AX);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word(i->seg(), eaddr, i->Iw());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GwEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
/* zero extend byte op2 into word op1 */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GwEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
/* zero extend byte op2 into word op1 */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GwEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
/* sign extend byte op2 into word op1 */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), (Bit8s) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GwEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(),i->extend8bitL());
|
||||
|
||||
/* sign extend byte op2 into word op1 */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), (Bit8s) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
write_RMW_virtual_word(op2_16);
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
#if BX_DEBUGGER
|
||||
// Note for mortals: the instruction to trigger this is "xchgw %bx,%bx"
|
||||
if (bx_dbg.magic_break_enabled && (i->nnn() == 3) && (i->rm() == 3))
|
||||
{
|
||||
BX_CPU_THIS_PTR magic_break = 1;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
BX_WRITE_16BIT_REG(i->rm(), op2_16);
|
||||
}
|
||||
|
||||
// Note: CMOV accesses a memory source operand (read), regardless
|
||||
// of whether condition is true or not. Thus, exceptions may
|
||||
// occur even if the MOV does not take place.
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVO_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNO_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_OF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVB_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNB_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_CF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVZ_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNZ_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_ZF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVBE_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF() || get_ZF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNBE_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (! (get_CF() || get_ZF()))
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVS_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_SF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNS_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_SF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVP_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_PF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNP_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_PF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVL_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() != getB_OF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNL_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() == getB_OF())
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVLE_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF() || (getB_SF() != getB_OF()))
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNLE_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF() && (getB_SF() == getB_OF()))
|
||||
BX_WRITE_16BIT_REG(i->nnn(), BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
317
simulators/bochs/cpu/data_xfer32.cc
Normal file
317
simulators/bochs/cpu/data_xfer32.cc
Normal file
@ -0,0 +1,317 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier for merging cpu64 and cpu32 code.
|
||||
#define RAX EAX
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_ERXEAX(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->rm() == 0) // 'xchg eax, eax' is NOP even in 64-bit mode
|
||||
return;
|
||||
#endif
|
||||
|
||||
Bit32u temp32 = EAX;
|
||||
RAX = BX_READ_32BIT_REG(i->rm());
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), temp32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_ERXId(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), i->Id());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV32_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_dword_32(i->seg(), eaddr, BX_READ_32BIT_REG(i->nnn()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV32_GdEdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u val32 = read_virtual_dword_32(i->seg(), eaddr);
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), val32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), eaddr);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EAXOd(bxInstruction_c *i)
|
||||
{
|
||||
RAX = read_virtual_dword_32(i->seg(), i->Id());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OdEAX(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_dword_32(i->seg(), i->Id(), EAX);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_dword(i->seg(), eaddr, i->Id());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
/* zero extend byte op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
/* zero extend byte op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op2_16 = read_virtual_word(i->seg(), eaddr);
|
||||
|
||||
/* zero extend word op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GdEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
/* zero extend word op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit32u) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op2_8 = read_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
/* sign extend byte op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit8s) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
/* sign extend byte op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit8s) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op2_16 = read_virtual_word(i->seg(), eaddr);
|
||||
|
||||
/* sign extend word op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit16s) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GdEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
/* sign extend word op2 into dword op1 */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), (Bit16s) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2_32, op1_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
write_RMW_virtual_dword(op2_32);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op2_32);
|
||||
}
|
||||
|
||||
// Note: CMOV accesses a memory source operand (read), regardless
|
||||
// of whether condition is true or not. Thus, exceptions may
|
||||
// occur even if the MOV does not take place.
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVO_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNO_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_OF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVB_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNB_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_CF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVZ_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNZ_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_ZF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVBE_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF() || get_ZF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNBE_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (! (get_CF() || get_ZF()))
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVS_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_SF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNS_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_SF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVP_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_PF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNP_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_PF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVL_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() != getB_OF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNL_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() == getB_OF())
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVLE_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF() || (getB_SF() != getB_OF()))
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNLE_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF() && (getB_SF() == getB_OF()))
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), BX_READ_32BIT_REG(i->rm()));
|
||||
|
||||
BX_CLEAR_64BIT_HIGH(i->nnn()); // always clear upper part of the register
|
||||
}
|
||||
350
simulators/bochs/cpu/data_xfer64.cc
Normal file
350
simulators/bochs/cpu/data_xfer64.cc
Normal file
@ -0,0 +1,350 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_RRXRAX(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u temp64 = RAX;
|
||||
RAX = BX_READ_64BIT_REG(i->rm());
|
||||
BX_WRITE_64BIT_REG(i->rm(), temp64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RRXIq(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_64BIT_REG(i->rm(), i->Iq());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV64_GdEdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u val32 = read_virtual_dword_64(i->seg(), eaddr);
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), val32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV64_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_dword_64(i->seg(), eaddr, BX_READ_32BIT_REG(i->nnn()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_qword_64(i->seg(), eaddr, BX_READ_64BIT_REG(i->nnn()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GqEqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u val64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
BX_WRITE_64BIT_REG(i->nnn(), val64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEA_GqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
BX_WRITE_64BIT_REG(i->nnn(), eaddr);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_ALOq(bxInstruction_c *i)
|
||||
{
|
||||
AL = read_virtual_byte_64(i->seg(), i->Iq());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqAL(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_byte_64(i->seg(), i->Iq(), AL);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_AXOq(bxInstruction_c *i)
|
||||
{
|
||||
AX = read_virtual_word_64(i->seg(), i->Iq());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqAX(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_word_64(i->seg(), i->Iq(), AX);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EAXOq(bxInstruction_c *i)
|
||||
{
|
||||
RAX = read_virtual_dword_64(i->seg(), i->Iq());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqEAX(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_dword_64(i->seg(), i->Iq(), EAX);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RAXOq(bxInstruction_c *i)
|
||||
{
|
||||
RAX = read_virtual_qword_64(i->seg(), i->Iq());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OqRAX(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_qword_64(i->seg(), i->Iq(), RAX);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op_64 = (Bit32s) i->Id();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_qword_64(i->seg(), eaddr, op_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op_64 = (Bit32s) i->Id();
|
||||
BX_WRITE_64BIT_REG(i->rm(), op_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op2_8 = read_virtual_byte_64(i->seg(), eaddr);
|
||||
|
||||
/* zero extend byte op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
/* zero extend byte op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op2_16 = read_virtual_word_64(i->seg(), eaddr);
|
||||
|
||||
/* zero extend word op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVZX_GqEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
/* zero extend word op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit64u) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op2_8 = read_virtual_byte_64(i->seg(), eaddr);
|
||||
|
||||
/* sign extend byte op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit8s) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
/* sign extend byte op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit8s) op2_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op2_16 = read_virtual_word_64(i->seg(), eaddr);
|
||||
|
||||
/* sign extend word op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit16s) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
/* sign extend word op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit16s) op2_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op2_32 = read_virtual_dword_64(i->seg(), eaddr);
|
||||
|
||||
/* sign extend word op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit32s) op2_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOVSX_GqEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
/* sign extend word op2 into qword op1 */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), (Bit32s) op2_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op2_64, op1_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
write_RMW_virtual_qword(op2_64);
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
Bit64u op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
BX_WRITE_64BIT_REG(i->rm(), op2_64);
|
||||
}
|
||||
|
||||
// Note: CMOV accesses a memory source operand (read), regardless
|
||||
// of whether condition is true or not. Thus, exceptions may
|
||||
// occur even if the MOV does not take place.
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVO_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNO_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_OF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVB_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNB_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_CF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVZ_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNZ_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_ZF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVBE_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF() || get_ZF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNBE_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (! (get_CF() || get_ZF()))
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVS_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_SF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNS_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_SF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVP_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_PF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNP_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (!get_PF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVL_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() != getB_OF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNL_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (getB_SF() == getB_OF())
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVLE_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (get_ZF() || (getB_SF() != getB_OF()))
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMOVNLE_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
if (! get_ZF() && (getB_SF() == getB_OF()))
|
||||
BX_WRITE_64BIT_REG(i->nnn(), BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
112
simulators/bochs/cpu/data_xfer8.cc
Normal file
112
simulators/bochs/cpu/data_xfer8.cc
Normal file
@ -0,0 +1,112 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RLIb(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), i->Ib());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_RHIb(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_8BIT_REGH(i->rm() & 0x03, i->Ib());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_byte(i->seg(), eaddr, BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GbEbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u val8 = read_virtual_byte(i->seg(), eaddr);
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), val8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op2);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_ALOd(bxInstruction_c *i)
|
||||
{
|
||||
AL = read_virtual_byte_32(i->seg(), i->Id());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_OdAL(bxInstruction_c *i)
|
||||
{
|
||||
write_virtual_byte_32(i->seg(), i->Id(), AL);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MOV_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_byte(i->seg(), eaddr, i->Ib());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XLAT(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
AL = read_virtual_byte_64(i->seg(), RBX + AL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
AL = read_virtual_byte(i->seg(), (Bit32u) (EBX + AL));
|
||||
}
|
||||
else {
|
||||
AL = read_virtual_byte_32(i->seg(), (Bit16u) (BX + AL));
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
|
||||
write_RMW_virtual_byte(op2);
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XCHG_EbGbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
Bit8u op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op2);
|
||||
}
|
||||
392
simulators/bochs/cpu/debugstuff.cc
Normal file
392
simulators/bochs/cpu/debugstuff.cc
Normal file
@ -0,0 +1,392 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_DISASM
|
||||
|
||||
#include "disasm/disasm.h"
|
||||
|
||||
void BX_CPU_C::debug_disasm_instruction(bx_address offset)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
bx_dbg_disassemble_current(BX_CPU_ID, 1); // only one cpu, print time stamp
|
||||
#else
|
||||
bx_phy_address phy_addr;
|
||||
Bit8u instr_buf[16];
|
||||
char char_buf[512];
|
||||
size_t i=0;
|
||||
|
||||
static char letters[] = "0123456789ABCDEF";
|
||||
static disassembler bx_disassemble;
|
||||
unsigned remainsInPage = 0x1000 - PAGE_OFFSET(offset);
|
||||
|
||||
bx_bool valid = dbg_xlate_linear2phy(BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_CS, offset), &phy_addr);
|
||||
if (valid) {
|
||||
BX_MEM(0)->dbg_fetch_mem(BX_CPU_THIS, phy_addr, 16, instr_buf);
|
||||
unsigned isize = bx_disassemble.disasm(
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b,
|
||||
BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64,
|
||||
BX_CPU_THIS_PTR get_segment_base(BX_SEG_REG_CS), offset,
|
||||
instr_buf, char_buf+i);
|
||||
if (isize <= remainsInPage) {
|
||||
i=strlen(char_buf);
|
||||
char_buf[i++] = ' ';
|
||||
char_buf[i++] = ':';
|
||||
char_buf[i++] = ' ';
|
||||
for (unsigned j=0; j<isize; j++) {
|
||||
char_buf[i++] = letters[(instr_buf[j] >> 4) & 0xf];
|
||||
char_buf[i++] = letters[(instr_buf[j] >> 0) & 0xf];
|
||||
}
|
||||
char_buf[i] = 0;
|
||||
BX_INFO(("0x" FMT_ADDRX ">> %s", offset, char_buf));
|
||||
}
|
||||
else {
|
||||
BX_INFO(("0x" FMT_ADDRX ": (instruction unavailable) page split instruction", offset));
|
||||
}
|
||||
}
|
||||
else {
|
||||
BX_INFO(("0x" FMT_ADDRX ": (instruction unavailable) page not present", offset));
|
||||
}
|
||||
#endif // #if BX_DEBUGGER
|
||||
}
|
||||
|
||||
#endif // #if BX_DISASM
|
||||
|
||||
const char* cpu_mode_string(unsigned cpu_mode)
|
||||
{
|
||||
static const char *cpu_mode_name[] = {
|
||||
"real mode",
|
||||
"v8086 mode",
|
||||
"protected mode",
|
||||
"compatibility mode",
|
||||
"long mode",
|
||||
"unknown mode"
|
||||
};
|
||||
|
||||
if(cpu_mode >= 5) cpu_mode = 5;
|
||||
return cpu_mode_name[cpu_mode];
|
||||
}
|
||||
|
||||
const char* cpu_state_string(unsigned state)
|
||||
{
|
||||
static const char *cpu_state_name[] = {
|
||||
"active",
|
||||
"halted",
|
||||
"in shutdown",
|
||||
"waiting for SIPI",
|
||||
"executing mwait",
|
||||
"executing mwait inhibit interrups",
|
||||
"unknown state"
|
||||
};
|
||||
|
||||
if(state >= 6) state = 6;
|
||||
return cpu_state_name[state];
|
||||
}
|
||||
|
||||
void BX_CPU_C::debug(bx_address offset)
|
||||
{
|
||||
BX_INFO(("CPU is in %s (%s)", cpu_mode_string(BX_CPU_THIS_PTR get_cpu_mode()),
|
||||
cpu_state_string(BX_CPU_THIS_PTR activity_state)));
|
||||
BX_INFO(("CS.d_b = %u bit",
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b ? 32 : 16));
|
||||
BX_INFO(("SS.d_b = %u bit",
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b ? 32 : 16));
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_INFO(("EFER = 0x%08x", BX_CPU_THIS_PTR efer.get32()));
|
||||
BX_INFO(("| RAX=%08x%08x RBX=%08x%08x",
|
||||
(unsigned) (RAX >> 32), (unsigned) EAX,
|
||||
(unsigned) (RBX >> 32), (unsigned) EBX));
|
||||
BX_INFO(("| RCX=%08x%08x RDX=%08x%08x",
|
||||
(unsigned) (RCX >> 32), (unsigned) ECX,
|
||||
(unsigned) (RDX >> 32), (unsigned) EDX));
|
||||
BX_INFO(("| RSP=%08x%08x RBP=%08x%08x",
|
||||
(unsigned) (RSP >> 32), (unsigned) ESP,
|
||||
(unsigned) (RBP >> 32), (unsigned) EBP));
|
||||
BX_INFO(("| RSI=%08x%08x RDI=%08x%08x",
|
||||
(unsigned) (RSI >> 32), (unsigned) ESI,
|
||||
(unsigned) (RDI >> 32), (unsigned) EDI));
|
||||
BX_INFO(("| R8=%08x%08x R9=%08x%08x",
|
||||
(unsigned) (R8 >> 32), (unsigned) (R8 & 0xFFFFFFFF),
|
||||
(unsigned) (R9 >> 32), (unsigned) (R9 & 0xFFFFFFFF)));
|
||||
BX_INFO(("| R10=%08x%08x R11=%08x%08x",
|
||||
(unsigned) (R10 >> 32), (unsigned) (R10 & 0xFFFFFFFF),
|
||||
(unsigned) (R11 >> 32), (unsigned) (R11 & 0xFFFFFFFF)));
|
||||
BX_INFO(("| R12=%08x%08x R13=%08x%08x",
|
||||
(unsigned) (R12 >> 32), (unsigned) (R12 & 0xFFFFFFFF),
|
||||
(unsigned) (R13 >> 32), (unsigned) (R13 & 0xFFFFFFFF)));
|
||||
BX_INFO(("| R14=%08x%08x R15=%08x%08x",
|
||||
(unsigned) (R14 >> 32), (unsigned) (R14 & 0xFFFFFFFF),
|
||||
(unsigned) (R15 >> 32), (unsigned) (R15 & 0xFFFFFFFF)));
|
||||
#else
|
||||
BX_INFO(("| EAX=%08x EBX=%08x ECX=%08x EDX=%08x",
|
||||
(unsigned) EAX, (unsigned) EBX, (unsigned) ECX, (unsigned) EDX));
|
||||
BX_INFO(("| ESP=%08x EBP=%08x ESI=%08x EDI=%08x",
|
||||
(unsigned) ESP, (unsigned) EBP, (unsigned) ESI, (unsigned) EDI));
|
||||
#endif
|
||||
BX_INFO(("| IOPL=%1u %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s %s",
|
||||
BX_CPU_THIS_PTR get_IOPL(),
|
||||
BX_CPU_THIS_PTR get_ID() ? "ID" : "id",
|
||||
BX_CPU_THIS_PTR get_VIP() ? "VIP" : "vip",
|
||||
BX_CPU_THIS_PTR get_VIF() ? "VIF" : "vif",
|
||||
BX_CPU_THIS_PTR get_AC() ? "AC" : "ac",
|
||||
BX_CPU_THIS_PTR get_VM() ? "VM" : "vm",
|
||||
BX_CPU_THIS_PTR get_RF() ? "RF" : "rf",
|
||||
BX_CPU_THIS_PTR get_NT() ? "NT" : "nt",
|
||||
BX_CPU_THIS_PTR get_OF() ? "OF" : "of",
|
||||
BX_CPU_THIS_PTR get_DF() ? "DF" : "df",
|
||||
BX_CPU_THIS_PTR get_IF() ? "IF" : "if",
|
||||
BX_CPU_THIS_PTR get_TF() ? "TF" : "tf",
|
||||
BX_CPU_THIS_PTR get_SF() ? "SF" : "sf",
|
||||
BX_CPU_THIS_PTR get_ZF() ? "ZF" : "zf",
|
||||
BX_CPU_THIS_PTR get_AF() ? "AF" : "af",
|
||||
BX_CPU_THIS_PTR get_PF() ? "PF" : "pf",
|
||||
BX_CPU_THIS_PTR get_CF() ? "CF" : "cf"));
|
||||
|
||||
BX_INFO(("| SEG selector base limit G D"));
|
||||
BX_INFO(("| SEG sltr(index|ti|rpl) base limit G D"));
|
||||
BX_INFO(("| CS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b));
|
||||
BX_INFO(("| DS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.index,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.ti,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.d_b));
|
||||
BX_INFO(("| SS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b));
|
||||
BX_INFO(("| ES:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.index,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.ti,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit_scaled,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.g,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.d_b));
|
||||
BX_INFO(("| FS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.index,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.ti,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.rpl,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.base,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.limit_scaled,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.g,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.u.segment.d_b));
|
||||
BX_INFO(("| GS:%04x( %04x| %01u| %1u) %08x %08x %1u %1u",
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.index,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.ti,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.rpl,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.base,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.limit_scaled,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.g,
|
||||
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.u.segment.d_b));
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_INFO(("| MSR_FS_BASE:%08x%08x",
|
||||
(unsigned) (MSR_FSBASE >> 32), (unsigned) (MSR_FSBASE & 0xFFFFFFFF)));
|
||||
BX_INFO(("| MSR_GS_BASE:%08x%08x",
|
||||
(unsigned) (MSR_GSBASE >> 32), (unsigned) (MSR_GSBASE & 0xFFFFFFFF)));
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_INFO(("| RIP=%08x%08x (%08x%08x)",
|
||||
(unsigned) (BX_CPU_THIS_PTR gen_reg[BX_64BIT_REG_RIP].dword.hrx),
|
||||
(unsigned) (EIP),
|
||||
(unsigned) (BX_CPU_THIS_PTR prev_rip >> 32),
|
||||
(unsigned) (BX_CPU_THIS_PTR prev_rip & 0xffffffff)));
|
||||
BX_INFO(("| CR0=0x%08x CR2=0x%08x%08x",
|
||||
(unsigned) (BX_CPU_THIS_PTR cr0.get32()),
|
||||
(unsigned) (BX_CPU_THIS_PTR cr2 >> 32),
|
||||
(unsigned) (BX_CPU_THIS_PTR cr2 & 0xffffffff)));
|
||||
BX_INFO(("| CR3=0x%08x CR4=0x%08x",
|
||||
(unsigned) BX_CPU_THIS_PTR cr3, BX_CPU_THIS_PTR cr4.get32()));
|
||||
#else
|
||||
BX_INFO(("| EIP=%08x (%08x)", (unsigned) EIP,
|
||||
(unsigned) BX_CPU_THIS_PTR prev_rip));
|
||||
|
||||
#if BX_CPU_LEVEL >= 2 && BX_CPU_LEVEL < 4
|
||||
BX_INFO(("| CR0=0x%08x CR2=0x%08x CR3=0x%08x",
|
||||
BX_CPU_THIS_PTR cr0.get32(),
|
||||
BX_CPU_THIS_PTR cr2,
|
||||
BX_CPU_THIS_PTR cr3));
|
||||
#elif BX_CPU_LEVEL >= 4
|
||||
BX_INFO(("| CR0=0x%08x CR2=0x%08x",
|
||||
BX_CPU_THIS_PTR cr0.get32(),
|
||||
BX_CPU_THIS_PTR cr2));
|
||||
BX_INFO(("| CR3=0x%08x CR4=0x%08x",
|
||||
BX_CPU_THIS_PTR cr3,
|
||||
BX_CPU_THIS_PTR cr4.get32()));
|
||||
#endif
|
||||
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
|
||||
#if BX_DISASM
|
||||
debug_disasm_instruction(offset);
|
||||
#endif // #if BX_DISASM
|
||||
}
|
||||
|
||||
|
||||
#if BX_DEBUGGER
|
||||
bx_bool BX_CPU_C::dbg_set_reg(unsigned reg, Bit32u val)
|
||||
{
|
||||
// returns 1=OK, 0=can't change
|
||||
Bit32u current_sys_bits;
|
||||
|
||||
switch (reg) {
|
||||
case BX_DBG_REG_EIP:
|
||||
EIP = val;
|
||||
invalidate_prefetch_q();
|
||||
return(1);
|
||||
case BX_DBG_REG_EFLAGS:
|
||||
if (val & 0xffff0000) {
|
||||
BX_INFO(("dbg_set_reg: can not set upper 16 bits of eflags."));
|
||||
return(0);
|
||||
}
|
||||
// make sure none of the system bits are being changed
|
||||
current_sys_bits = ((BX_CPU_THIS_PTR getB_NT()) << 14) |
|
||||
(BX_CPU_THIS_PTR get_IOPL () << 12) |
|
||||
((BX_CPU_THIS_PTR getB_TF()) << 8);
|
||||
if (current_sys_bits != (val & 0x0000f100)) {
|
||||
BX_INFO(("dbg_set_reg: can not modify NT, IOPL, or TF."));
|
||||
return(0);
|
||||
}
|
||||
BX_CPU_THIS_PTR set_CF(val & 0x01); val >>= 2;
|
||||
BX_CPU_THIS_PTR set_PF(val & 0x01); val >>= 2;
|
||||
BX_CPU_THIS_PTR set_AF(val & 0x01); val >>= 2;
|
||||
BX_CPU_THIS_PTR set_ZF(val & 0x01); val >>= 1;
|
||||
BX_CPU_THIS_PTR set_SF(val & 0x01); val >>= 2;
|
||||
BX_CPU_THIS_PTR set_IF(val & 0x01); val >>= 1;
|
||||
BX_CPU_THIS_PTR set_DF(val & 0x01); val >>= 1;
|
||||
BX_CPU_THIS_PTR set_OF(val & 0x01);
|
||||
return(1);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
unsigned BX_CPU_C::dbg_query_pending(void)
|
||||
{
|
||||
unsigned ret = 0;
|
||||
|
||||
if (BX_HRQ) { // DMA Hold Request
|
||||
ret |= BX_DBG_PENDING_DMA;
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR INTR && BX_CPU_THIS_PTR get_IF()) {
|
||||
ret |= BX_DBG_PENDING_IRQ;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::dbg_get_sreg(bx_dbg_sreg_t *sreg, unsigned sreg_no)
|
||||
{
|
||||
if (sreg_no > 5)
|
||||
return(0);
|
||||
sreg->valid = BX_CPU_THIS_PTR sregs[sreg_no].cache.valid;
|
||||
sreg->sel = BX_CPU_THIS_PTR sregs[sreg_no].selector.value;
|
||||
sreg->des_l = get_descriptor_l(&BX_CPU_THIS_PTR sregs[sreg_no].cache);
|
||||
sreg->des_h = get_descriptor_h(&BX_CPU_THIS_PTR sregs[sreg_no].cache);
|
||||
#if BX_SUPPORT_X86_64
|
||||
sreg->dword3 = BX_CPU_THIS_PTR sregs[sreg_no].cache.u.segment.base >> 32;
|
||||
#endif
|
||||
return(1);
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::dbg_set_sreg(unsigned sreg_no, bx_segment_reg_t *sreg)
|
||||
{
|
||||
if (sreg_no < 6) {
|
||||
BX_CPU_THIS_PTR sregs[sreg_no] = *sreg;
|
||||
if (sreg_no == BX_SEG_REG_CS) {
|
||||
handleCpuModeChange();
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck(/* CPL change */);
|
||||
#endif
|
||||
invalidate_prefetch_q();
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BX_CPU_C::dbg_get_tr(bx_dbg_sreg_t *sreg)
|
||||
{
|
||||
sreg->valid = BX_CPU_THIS_PTR tr.cache.valid;
|
||||
sreg->sel = BX_CPU_THIS_PTR tr.selector.value;
|
||||
sreg->des_l = get_descriptor_l(&BX_CPU_THIS_PTR tr.cache);
|
||||
sreg->des_h = get_descriptor_h(&BX_CPU_THIS_PTR tr.cache);
|
||||
#if BX_SUPPORT_X86_64
|
||||
sreg->dword3 = BX_CPU_THIS_PTR tr.cache.u.segment.base >> 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPU_C::dbg_get_ldtr(bx_dbg_sreg_t *sreg)
|
||||
{
|
||||
sreg->valid = BX_CPU_THIS_PTR ldtr.cache.valid;
|
||||
sreg->sel = BX_CPU_THIS_PTR ldtr.selector.value;
|
||||
sreg->des_l = get_descriptor_l(&BX_CPU_THIS_PTR ldtr.cache);
|
||||
sreg->des_h = get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache);
|
||||
#if BX_SUPPORT_X86_64
|
||||
sreg->dword3 = BX_CPU_THIS_PTR ldtr.cache.u.segment.base >> 32;
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPU_C::dbg_get_gdtr(bx_dbg_global_sreg_t *sreg)
|
||||
{
|
||||
sreg->base = BX_CPU_THIS_PTR gdtr.base;
|
||||
sreg->limit = BX_CPU_THIS_PTR gdtr.limit;
|
||||
}
|
||||
|
||||
void BX_CPU_C::dbg_get_idtr(bx_dbg_global_sreg_t *sreg)
|
||||
{
|
||||
sreg->base = BX_CPU_THIS_PTR idtr.base;
|
||||
sreg->limit = BX_CPU_THIS_PTR idtr.limit;
|
||||
}
|
||||
|
||||
#endif // #if BX_DEBUGGER
|
||||
|
||||
void BX_CPU_C::atexit(void)
|
||||
{
|
||||
debug(BX_CPU_THIS_PTR prev_rip);
|
||||
}
|
||||
192
simulators/bochs/cpu/descriptor.h
Executable file
192
simulators/bochs/cpu/descriptor.h
Executable file
@ -0,0 +1,192 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_DESCRIPTOR_H
|
||||
#define BX_DESCRIPTOR_H
|
||||
|
||||
//
|
||||
// |---------------------------------------------|
|
||||
// | Segment Descriptor |
|
||||
// |---------------------------------------------|
|
||||
// |33222222|2|2|2|2| 11 11 |1|11|1|11 | |
|
||||
// |10987654|3|2|1|0| 98 76 |5|43|2|1098|76543210|
|
||||
// |--------|-|-|-|-|-------|-|--|-|----|--------|
|
||||
// |Base |G|D|L|A|Limit |P|D |S|Type|Base |
|
||||
// |[31-24] | |/| |V|[19-16]| |P | | |[23-16] |
|
||||
// | | |B| |L| | |L | | | |
|
||||
// |------------------------|--------------------|
|
||||
// | Base [15-0] | Limit [15-0] |
|
||||
// |------------------------|--------------------|
|
||||
//
|
||||
|
||||
typedef struct { /* bx_selector_t */
|
||||
Bit16u value; /* the 16bit value of the selector */
|
||||
/* the following fields are extracted from the value field in protected
|
||||
mode only. They're used for sake of efficiency */
|
||||
Bit16u index; /* 13bit index extracted from value in protected mode */
|
||||
Bit8u ti; /* table indicator bit extracted from value */
|
||||
Bit8u rpl; /* RPL extracted from value */
|
||||
} bx_selector_t;
|
||||
|
||||
#define BX_SELECTOR_RPL(selector) ((selector) & 0x03)
|
||||
#define BX_SELECTOR_RPL_MASK (0xfffc)
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
||||
// do not go above 4 bits !
|
||||
#define SegValidCache (0x01)
|
||||
#define SegAccessROK (0x02)
|
||||
#define SegAccessWOK (0x04)
|
||||
|
||||
unsigned valid; // Holds above values, Or'd together. Used to
|
||||
// hold only 0 or 1.
|
||||
|
||||
bx_bool p; /* present */
|
||||
Bit8u dpl; /* descriptor privilege level 0..3 */
|
||||
bx_bool segment; /* 0 = system/gate, 1 = data/code segment */
|
||||
Bit8u type; /* For system & gate descriptors:
|
||||
* 0 = invalid descriptor (reserved)
|
||||
* 1 = 286 available Task State Segment (TSS)
|
||||
* 2 = LDT descriptor
|
||||
* 3 = 286 busy Task State Segment (TSS)
|
||||
* 4 = 286 call gate
|
||||
* 5 = task gate
|
||||
* 6 = 286 interrupt gate
|
||||
* 7 = 286 trap gate
|
||||
* 8 = (reserved)
|
||||
* 9 = 386 available TSS
|
||||
* 10 = (reserved)
|
||||
* 11 = 386 busy TSS
|
||||
* 12 = 386 call gate
|
||||
* 13 = (reserved)
|
||||
* 14 = 386 interrupt gate
|
||||
* 15 = 386 trap gate */
|
||||
|
||||
// For system & gate descriptors:
|
||||
|
||||
#define BX_GATE_TYPE_NONE (0x0)
|
||||
#define BX_SYS_SEGMENT_AVAIL_286_TSS (0x1)
|
||||
#define BX_SYS_SEGMENT_LDT (0x2)
|
||||
#define BX_SYS_SEGMENT_BUSY_286_TSS (0x3)
|
||||
#define BX_286_CALL_GATE (0x4)
|
||||
#define BX_TASK_GATE (0x5)
|
||||
#define BX_286_INTERRUPT_GATE (0x6)
|
||||
#define BX_286_TRAP_GATE (0x7)
|
||||
/* 0x8 reserved */
|
||||
#define BX_SYS_SEGMENT_AVAIL_386_TSS (0x9)
|
||||
/* 0xa reserved */
|
||||
#define BX_SYS_SEGMENT_BUSY_386_TSS (0xb)
|
||||
#define BX_386_CALL_GATE (0xc)
|
||||
/* 0xd reserved */
|
||||
#define BX_386_INTERRUPT_GATE (0xe)
|
||||
#define BX_386_TRAP_GATE (0xf)
|
||||
|
||||
// For data/code descriptors:
|
||||
|
||||
#define BX_DATA_READ_ONLY (0x0)
|
||||
#define BX_DATA_READ_ONLY_ACCESSED (0x1)
|
||||
#define BX_DATA_READ_WRITE (0x2)
|
||||
#define BX_DATA_READ_WRITE_ACCESSED (0x3)
|
||||
#define BX_DATA_READ_ONLY_EXPAND_DOWN (0x4)
|
||||
#define BX_DATA_READ_ONLY_EXPAND_DOWN_ACCESSED (0x5)
|
||||
#define BX_DATA_READ_WRITE_EXPAND_DOWN (0x6)
|
||||
#define BX_DATA_READ_WRITE_EXPAND_DOWN_ACCESSED (0x7)
|
||||
#define BX_CODE_EXEC_ONLY (0x8)
|
||||
#define BX_CODE_EXEC_ONLY_ACCESSED (0x9)
|
||||
#define BX_CODE_EXEC_READ (0xa)
|
||||
#define BX_CODE_EXEC_READ_ACCESSED (0xb)
|
||||
#define BX_CODE_EXEC_ONLY_CONFORMING (0xc)
|
||||
#define BX_CODE_EXEC_ONLY_CONFORMING_ACCESSED (0xd)
|
||||
#define BX_CODE_EXEC_READ_CONFORMING (0xe)
|
||||
#define BX_CODE_EXEC_READ_CONFORMING_ACCESSED (0xf)
|
||||
|
||||
union {
|
||||
struct {
|
||||
bx_address base; /* base address: 286=24bits, 386=32bits, long=64 */
|
||||
Bit32u limit_scaled; /* for efficiency, this contrived field is set to
|
||||
* limit for byte granular, and
|
||||
* (limit << 12) | 0xfff for page granular seg's
|
||||
*/
|
||||
bx_bool g; /* granularity: 0=byte, 1=4K (page) */
|
||||
bx_bool d_b; /* default size: 0=16bit, 1=32bit */
|
||||
#if BX_SUPPORT_X86_64
|
||||
bx_bool l; /* long mode: 0=compat, 1=64 bit */
|
||||
#endif
|
||||
bx_bool avl; /* available for use by system */
|
||||
} segment;
|
||||
struct {
|
||||
Bit8u param_count; /* 5bits (0..31) #words/dword to copy from caller's
|
||||
* stack to called procedure's stack. */
|
||||
Bit16u dest_selector;
|
||||
Bit32u dest_offset;
|
||||
} gate;
|
||||
struct { /* type 5: Task Gate Descriptor */
|
||||
Bit16u tss_selector; /* TSS segment selector */
|
||||
} taskgate;
|
||||
} u;
|
||||
|
||||
} bx_descriptor_t;
|
||||
|
||||
#define IS_PRESENT(descriptor) (descriptor.p)
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define IS_LONG64_SEGMENT(descriptor) (descriptor.u.segment.l)
|
||||
#else
|
||||
#define IS_LONG64_SEGMENT(descriptor) (0)
|
||||
#endif
|
||||
|
||||
#define IS_CODE_SEGMENT(type) (((type) >> 3) & 0x1)
|
||||
#define IS_CODE_SEGMENT_CONFORMING(type) (((type) >> 2) & 0x1)
|
||||
#define IS_DATA_SEGMENT_EXPAND_DOWN(type) (((type) >> 2) & 0x1)
|
||||
#define IS_CODE_SEGMENT_READABLE(type) (((type) >> 1) & 0x1)
|
||||
#define IS_DATA_SEGMENT_WRITEABLE(type) (((type) >> 1) & 0x1)
|
||||
|
||||
#define IS_SEGMENT_ACCESSED(type) ((type) & 0x1)
|
||||
|
||||
#define BX_SEGMENT_CODE (0x8)
|
||||
#define BX_SEGMENT_DATA_EXPAND_DOWN (0x4)
|
||||
#define BX_SEGMENT_CODE_CONFORMING (0x4)
|
||||
#define BX_SEGMENT_DATA_WRITE (0x2)
|
||||
#define BX_SEGMENT_CODE_READ (0x2)
|
||||
#define BX_SEGMENT_ACCESSED (0x1)
|
||||
|
||||
#define IS_DATA_SEGMENT(type) (! IS_CODE_SEGMENT(type))
|
||||
#define IS_CODE_SEGMENT_NON_CONFORMING(type) \
|
||||
(! IS_CODE_SEGMENT_CONFORMING(type))
|
||||
|
||||
typedef struct {
|
||||
bx_selector_t selector;
|
||||
bx_descriptor_t cache;
|
||||
} bx_segment_reg_t;
|
||||
|
||||
typedef struct {
|
||||
bx_address base; /* base address: 24bits=286,32bits=386,64bits=x86-64 */
|
||||
Bit16u limit; /* limit, 16bits */
|
||||
} bx_global_segment_reg_t;
|
||||
|
||||
void parse_selector(Bit16u raw_selector, bx_selector_t *selector);
|
||||
Bit8u get_ar_byte(const bx_descriptor_t *d);
|
||||
void set_ar_byte(bx_descriptor_t *d, Bit8u ar_byte);
|
||||
void parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp);
|
||||
|
||||
#endif
|
||||
941
simulators/bochs/cpu/exception.cc
Normal file
941
simulators/bochs/cpu/exception.cc
Normal file
@ -0,0 +1,941 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#include "param_names.h"
|
||||
#include "iodev/iodev.h"
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier merging cpu64 & cpu code.
|
||||
#define RIP EIP
|
||||
#define RSP ESP
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPU_C::long_mode_int(Bit8u vector, unsigned soft_int, bx_bool push_error, Bit16u error_code)
|
||||
{
|
||||
bx_descriptor_t gate_descriptor, cs_descriptor;
|
||||
bx_selector_t cs_selector;
|
||||
|
||||
// interrupt vector must be within IDT table limits,
|
||||
// else #GP(vector*8 + 2 + EXT)
|
||||
if ((vector*16 + 15) > BX_CPU_THIS_PTR idtr.limit) {
|
||||
BX_ERROR(("interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
Bit64u desctmp1 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16);
|
||||
Bit64u desctmp2 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16 + 8);
|
||||
|
||||
if (desctmp2 & BX_CONST64(0x00001F0000000000)) {
|
||||
BX_ERROR(("interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0"));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
Bit32u dword1 = GET32L(desctmp1);
|
||||
Bit32u dword2 = GET32H(desctmp1);
|
||||
Bit32u dword3 = GET32L(desctmp2);
|
||||
|
||||
parse_descriptor(dword1, dword2, &gate_descriptor);
|
||||
|
||||
if ((gate_descriptor.valid==0) || gate_descriptor.segment)
|
||||
{
|
||||
BX_ERROR(("interrupt(long mode): gate descriptor is not valid sys seg"));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
// descriptor AR byte must indicate interrupt gate, trap gate,
|
||||
// or task gate, else #GP(vector*8 + 2 + EXT)
|
||||
if (gate_descriptor.type != BX_386_INTERRUPT_GATE &&
|
||||
gate_descriptor.type != BX_386_TRAP_GATE)
|
||||
{
|
||||
BX_ERROR(("interrupt(long mode): unsupported gate type %u",
|
||||
(unsigned) gate_descriptor.type));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
// if software interrupt, then gate descripor DPL must be >= CPL,
|
||||
// else #GP(vector * 8 + 2 + EXT)
|
||||
if (soft_int && gate_descriptor.dpl < CPL)
|
||||
{
|
||||
BX_ERROR(("interrupt(long mode): soft_int && gate.dpl < CPL"));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
// Gate must be present, else #NP(vector * 8 + 2 + EXT)
|
||||
if (! IS_PRESENT(gate_descriptor)) {
|
||||
BX_ERROR(("interrupt(long mode): gate.p == 0"));
|
||||
exception(BX_NP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
Bit16u gate_dest_selector = gate_descriptor.u.gate.dest_selector;
|
||||
Bit64u gate_dest_offset = ((Bit64u)dword3 << 32) |
|
||||
gate_descriptor.u.gate.dest_offset;
|
||||
|
||||
unsigned ist = gate_descriptor.u.gate.param_count & 0x7;
|
||||
|
||||
// examine CS selector and descriptor given in gate descriptor
|
||||
// selector must be non-null else #GP(EXT)
|
||||
if ((gate_dest_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("int_trap_gate(long mode): selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(gate_dest_selector, &cs_selector);
|
||||
|
||||
// selector must be within its descriptor table limits
|
||||
// else #GP(selector+EXT)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// descriptor AR byte must indicate code seg
|
||||
// and code segment descriptor DPL<=CPL, else #GP(selector+EXT)
|
||||
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
|
||||
IS_DATA_SEGMENT(cs_descriptor.type) ||
|
||||
cs_descriptor.dpl > CPL)
|
||||
{
|
||||
BX_ERROR(("interrupt(long mode): not accessible or not code segment"));
|
||||
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
// check that it's a 64 bit segment
|
||||
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
|
||||
{
|
||||
BX_ERROR(("interrupt(long mode): must be 64 bit segment"));
|
||||
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
// segment must be present, else #NP(selector + EXT)
|
||||
if (! IS_PRESENT(cs_descriptor)) {
|
||||
BX_ERROR(("interrupt(long mode): segment not present"));
|
||||
exception(BX_NP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
Bit64u RSP_for_cpl_x;
|
||||
|
||||
Bit64u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
|
||||
Bit64u old_RIP = RIP;
|
||||
Bit64u old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
|
||||
Bit64u old_RSP = RSP;
|
||||
|
||||
// if code segment is non-conforming and DPL < CPL then
|
||||
// INTERRUPT TO INNER PRIVILEGE:
|
||||
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && cs_descriptor.dpl < CPL)
|
||||
{
|
||||
BX_DEBUG(("interrupt(long mode): INTERRUPT TO INNER PRIVILEGE"));
|
||||
|
||||
// check selector and descriptor for new stack in current TSS
|
||||
if (ist > 0) {
|
||||
BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist));
|
||||
RSP_for_cpl_x = get_RSP_from_TSS(ist+3);
|
||||
}
|
||||
else {
|
||||
RSP_for_cpl_x = get_RSP_from_TSS(cs_descriptor.dpl);
|
||||
}
|
||||
|
||||
// align stack
|
||||
RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0);
|
||||
|
||||
// push old stack long pointer onto new stack
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags());
|
||||
// push long pointer to return address onto new stack
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP);
|
||||
RSP_for_cpl_x -= 40;
|
||||
|
||||
if (push_error) {
|
||||
RSP_for_cpl_x -= 8;
|
||||
write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code);
|
||||
}
|
||||
|
||||
// load CS:RIP (guaranteed to be in 64 bit mode)
|
||||
branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, cs_descriptor.dpl);
|
||||
|
||||
// set up null SS descriptor
|
||||
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], cs_descriptor.dpl);
|
||||
}
|
||||
else if(IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) || cs_descriptor.dpl==CPL)
|
||||
{
|
||||
// if code segment is conforming OR code segment DPL = CPL then
|
||||
// INTERRUPT TO SAME PRIVILEGE LEVEL:
|
||||
|
||||
BX_DEBUG(("interrupt(long mode): INTERRUPT TO SAME PRIVILEGE"));
|
||||
|
||||
// check selector and descriptor for new stack in current TSS
|
||||
if (ist > 0) {
|
||||
BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist));
|
||||
RSP_for_cpl_x = get_RSP_from_TSS(ist+3);
|
||||
}
|
||||
else {
|
||||
RSP_for_cpl_x = RSP;
|
||||
}
|
||||
|
||||
// align stack
|
||||
RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0);
|
||||
|
||||
// push flags onto stack
|
||||
// push current CS selector onto stack
|
||||
// push return offset onto stack
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags());
|
||||
// push long pointer to return address onto new stack
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP);
|
||||
RSP_for_cpl_x -= 40;
|
||||
|
||||
if (push_error) {
|
||||
RSP_for_cpl_x -= 8;
|
||||
write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code);
|
||||
}
|
||||
|
||||
// set the RPL field of CS to CPL
|
||||
branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, CPL);
|
||||
}
|
||||
else {
|
||||
BX_ERROR(("interrupt(long mode): bad descriptor type %u (CS.DPL=%u CPL=%u)",
|
||||
(unsigned) cs_descriptor.type, (unsigned) cs_descriptor.dpl, (unsigned) CPL));
|
||||
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
RSP = RSP_for_cpl_x;
|
||||
|
||||
// if interrupt gate then set IF to 0
|
||||
if (!(gate_descriptor.type & 1)) // even is int-gate
|
||||
BX_CPU_THIS_PTR clear_IF();
|
||||
BX_CPU_THIS_PTR clear_TF();
|
||||
//BX_CPU_THIS_PTR clear_VM(); // VM is clear in long mode
|
||||
BX_CPU_THIS_PTR clear_RF();
|
||||
BX_CPU_THIS_PTR clear_NT();
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPU_C::protected_mode_int(Bit8u vector, unsigned soft_int, bx_bool push_error, Bit16u error_code)
|
||||
{
|
||||
bx_descriptor_t gate_descriptor, cs_descriptor;
|
||||
bx_selector_t cs_selector;
|
||||
|
||||
Bit16u raw_tss_selector;
|
||||
bx_selector_t tss_selector;
|
||||
bx_descriptor_t tss_descriptor;
|
||||
|
||||
Bit16u gate_dest_selector;
|
||||
Bit32u gate_dest_offset;
|
||||
|
||||
// interrupt vector must be within IDT table limits,
|
||||
// else #GP(vector*8 + 2 + EXT)
|
||||
if ((vector*8 + 7) > BX_CPU_THIS_PTR idtr.limit) {
|
||||
BX_ERROR(("interrupt(): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
Bit64u desctmp = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*8);
|
||||
|
||||
Bit32u dword1 = GET32L(desctmp);
|
||||
Bit32u dword2 = GET32H(desctmp);
|
||||
|
||||
parse_descriptor(dword1, dword2, &gate_descriptor);
|
||||
|
||||
if ((gate_descriptor.valid==0) || gate_descriptor.segment) {
|
||||
BX_ERROR(("interrupt(): gate descriptor is not valid sys seg (vector=0x%02x)", vector));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
// descriptor AR byte must indicate interrupt gate, trap gate,
|
||||
// or task gate, else #GP(vector*8 + 2 + EXT)
|
||||
switch (gate_descriptor.type) {
|
||||
case BX_TASK_GATE:
|
||||
case BX_286_INTERRUPT_GATE:
|
||||
case BX_286_TRAP_GATE:
|
||||
case BX_386_INTERRUPT_GATE:
|
||||
case BX_386_TRAP_GATE:
|
||||
break;
|
||||
default:
|
||||
BX_ERROR(("interrupt(): gate.type(%u) != {5,6,7,14,15}",
|
||||
(unsigned) gate_descriptor.type));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
// if software interrupt, then gate descripor DPL must be >= CPL,
|
||||
// else #GP(vector * 8 + 2 + EXT)
|
||||
if (soft_int && gate_descriptor.dpl < CPL) {
|
||||
BX_ERROR(("interrupt(): soft_int && (gate.dpl < CPL)"));
|
||||
exception(BX_GP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
// Gate must be present, else #NP(vector * 8 + 2 + EXT)
|
||||
if (! IS_PRESENT(gate_descriptor)) {
|
||||
BX_ERROR(("interrupt(): gate not present"));
|
||||
exception(BX_NP_EXCEPTION, vector*8 + 2);
|
||||
}
|
||||
|
||||
switch (gate_descriptor.type) {
|
||||
case BX_TASK_GATE:
|
||||
// examine selector to TSS, given in task gate descriptor
|
||||
raw_tss_selector = gate_descriptor.u.taskgate.tss_selector;
|
||||
parse_selector(raw_tss_selector, &tss_selector);
|
||||
|
||||
// must specify global in the local/global bit,
|
||||
// else #GP(TSS selector)
|
||||
if (tss_selector.ti) {
|
||||
BX_ERROR(("interrupt(): tss_selector.ti=1 from gate descriptor - #GP(tss_selector)"));
|
||||
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// index must be within GDT limits, else #TS(TSS selector)
|
||||
fetch_raw_descriptor(&tss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
|
||||
parse_descriptor(dword1, dword2, &tss_descriptor);
|
||||
|
||||
// AR byte must specify available TSS,
|
||||
// else #GP(TSS selector)
|
||||
if (tss_descriptor.valid==0 || tss_descriptor.segment) {
|
||||
BX_ERROR(("interrupt(): TSS selector points to invalid or bad TSS - #GP(tss_selector)"));
|
||||
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
if (tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
|
||||
tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS)
|
||||
{
|
||||
BX_ERROR(("interrupt(): TSS selector points to bad TSS - #GP(tss_selector)"));
|
||||
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// TSS must be present, else #NP(TSS selector)
|
||||
if (! IS_PRESENT(tss_descriptor)) {
|
||||
BX_ERROR(("interrupt(): TSS descriptor.p == 0"));
|
||||
exception(BX_NP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// switch tasks with nesting to TSS
|
||||
task_switch(0, &tss_selector, &tss_descriptor,
|
||||
BX_TASK_FROM_INT, dword1, dword2);
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
// if interrupt was caused by fault with error code
|
||||
// stack limits must allow push of 2 more bytes, else #SS(0)
|
||||
// push error code onto stack
|
||||
|
||||
if (push_error) {
|
||||
if (tss_descriptor.type >= 9) // TSS386
|
||||
push_32(error_code);
|
||||
else
|
||||
push_16(error_code);
|
||||
}
|
||||
|
||||
// instruction pointer must be in CS limit, else #GP(0)
|
||||
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("interrupt(): EIP > CS.limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
return;
|
||||
|
||||
case BX_286_INTERRUPT_GATE:
|
||||
case BX_286_TRAP_GATE:
|
||||
case BX_386_INTERRUPT_GATE:
|
||||
case BX_386_TRAP_GATE:
|
||||
gate_dest_selector = gate_descriptor.u.gate.dest_selector;
|
||||
gate_dest_offset = gate_descriptor.u.gate.dest_offset;
|
||||
|
||||
// examine CS selector and descriptor given in gate descriptor
|
||||
// selector must be non-null else #GP(EXT)
|
||||
if ((gate_dest_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("int_trap_gate(): selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(gate_dest_selector, &cs_selector);
|
||||
|
||||
// selector must be within its descriptor table limits
|
||||
// else #GP(selector+EXT)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// descriptor AR byte must indicate code seg
|
||||
// and code segment descriptor DPL<=CPL, else #GP(selector+EXT)
|
||||
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
|
||||
IS_DATA_SEGMENT(cs_descriptor.type) ||
|
||||
cs_descriptor.dpl > CPL)
|
||||
{
|
||||
BX_ERROR(("interrupt(): not accessible or not code segment cs=0x%04x", cs_selector.value));
|
||||
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
// segment must be present, else #NP(selector + EXT)
|
||||
if (! IS_PRESENT(cs_descriptor)) {
|
||||
BX_ERROR(("interrupt(): segment not present"));
|
||||
exception(BX_NP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
// if code segment is non-conforming and DPL < CPL then
|
||||
// INTERRUPT TO INNER PRIVILEGE
|
||||
if(IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && cs_descriptor.dpl < CPL)
|
||||
{
|
||||
Bit16u old_SS, old_CS, SS_for_cpl_x;
|
||||
Bit32u ESP_for_cpl_x, old_EIP, old_ESP;
|
||||
bx_descriptor_t ss_descriptor;
|
||||
bx_selector_t ss_selector;
|
||||
int is_v8086_mode = v8086_mode();
|
||||
|
||||
BX_DEBUG(("interrupt(): INTERRUPT TO INNER PRIVILEGE"));
|
||||
|
||||
// check selector and descriptor for new stack in current TSS
|
||||
get_SS_ESP_from_TSS(cs_descriptor.dpl,
|
||||
&SS_for_cpl_x, &ESP_for_cpl_x);
|
||||
|
||||
if (is_v8086_mode && cs_descriptor.dpl != 0) {
|
||||
// if code segment DPL != 0 then #GP(new code segment selector)
|
||||
BX_ERROR(("interrupt(): code segment DPL(%d) != 0 in v8086 mode", cs_descriptor.dpl));
|
||||
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
// Selector must be non-null else #TS(EXT)
|
||||
if ((SS_for_cpl_x & 0xfffc) == 0) {
|
||||
BX_ERROR(("interrupt(): SS selector null"));
|
||||
exception(BX_TS_EXCEPTION, 0); /* TS(ext) */
|
||||
}
|
||||
|
||||
// selector index must be within its descriptor table limits
|
||||
// else #TS(SS selector + EXT)
|
||||
parse_selector(SS_for_cpl_x, &ss_selector);
|
||||
// fetch 2 dwords of descriptor; call handles out of limits checks
|
||||
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_TS_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &ss_descriptor);
|
||||
|
||||
// selector rpl must = dpl of code segment,
|
||||
// else #TS(SS selector + ext)
|
||||
if (ss_selector.rpl != cs_descriptor.dpl) {
|
||||
BX_ERROR(("interrupt(): SS.rpl != CS.dpl"));
|
||||
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// stack seg DPL must = DPL of code segment,
|
||||
// else #TS(SS selector + ext)
|
||||
if (ss_descriptor.dpl != cs_descriptor.dpl) {
|
||||
BX_ERROR(("interrupt(): SS.dpl != CS.dpl"));
|
||||
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// descriptor must indicate writable data segment,
|
||||
// else #TS(SS selector + EXT)
|
||||
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
|
||||
IS_CODE_SEGMENT(ss_descriptor.type) ||
|
||||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("interrupt(): SS is not writable data segment"));
|
||||
exception(BX_TS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// seg must be present, else #SS(SS selector + ext)
|
||||
if (! IS_PRESENT(ss_descriptor)) {
|
||||
BX_ERROR(("interrupt(): SS not present"));
|
||||
exception(BX_SS_EXCEPTION, SS_for_cpl_x & 0xfffc);
|
||||
}
|
||||
|
||||
// IP must be within CS segment boundaries, else #GP(0)
|
||||
if (gate_dest_offset > cs_descriptor.u.segment.limit_scaled) {
|
||||
BX_ERROR(("interrupt(): gate EIP > CS.limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
old_ESP = ESP;
|
||||
old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
|
||||
old_EIP = EIP;
|
||||
old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
|
||||
|
||||
// Prepare new stack segment
|
||||
bx_segment_reg_t new_stack;
|
||||
new_stack.selector = ss_selector;
|
||||
new_stack.cache = ss_descriptor;
|
||||
new_stack.selector.rpl = cs_descriptor.dpl;
|
||||
// add cpl to the selector value
|
||||
new_stack.selector.value = (0xfffc & new_stack.selector.value) |
|
||||
new_stack.selector.rpl;
|
||||
|
||||
if (ss_descriptor.u.segment.d_b) {
|
||||
Bit32u temp_ESP = ESP_for_cpl_x;
|
||||
|
||||
if (is_v8086_mode)
|
||||
{
|
||||
if (gate_descriptor.type>=14) { // 386 int/trap gate
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-12, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-16, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
temp_ESP -= 16;
|
||||
}
|
||||
else {
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-6, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-8, cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
temp_ESP -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (gate_descriptor.type>=14) { // 386 int/trap gate
|
||||
// push long pointer to old stack onto new stack
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, old_ESP);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-12, cs_descriptor.dpl, read_eflags());
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-16, cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP-20, cs_descriptor.dpl, old_EIP);
|
||||
temp_ESP -= 20;
|
||||
|
||||
if (push_error) {
|
||||
temp_ESP -= 4;
|
||||
write_new_stack_dword_32(&new_stack, temp_ESP, cs_descriptor.dpl, error_code);
|
||||
}
|
||||
}
|
||||
else { // 286 int/trap gate
|
||||
// push long pointer to old stack onto new stack
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-2, cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-4, cs_descriptor.dpl, (Bit16u) old_ESP);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-6, cs_descriptor.dpl, (Bit16u) read_eflags());
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-8, cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_word_32(&new_stack, temp_ESP-10, cs_descriptor.dpl, (Bit16u) old_EIP);
|
||||
temp_ESP -= 10;
|
||||
|
||||
if (push_error) {
|
||||
temp_ESP -= 2;
|
||||
write_new_stack_word_32(&new_stack, temp_ESP, cs_descriptor.dpl, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
ESP = temp_ESP;
|
||||
}
|
||||
else {
|
||||
Bit16u temp_SP = (Bit16u) ESP_for_cpl_x;
|
||||
|
||||
if (is_v8086_mode)
|
||||
{
|
||||
if (gate_descriptor.type>=14) { // 386 int/trap gate
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-12), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-16), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
temp_SP -= 16;
|
||||
}
|
||||
else {
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-6), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
temp_SP -= 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (gate_descriptor.type>=14) { // 386 int/trap gate
|
||||
// push long pointer to old stack onto new stack
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, old_ESP);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-12), cs_descriptor.dpl, read_eflags());
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-16), cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_dword_32(&new_stack, (Bit16u)(temp_SP-20), cs_descriptor.dpl, old_EIP);
|
||||
temp_SP -= 20;
|
||||
|
||||
if (push_error) {
|
||||
temp_SP -= 4;
|
||||
write_new_stack_dword_32(&new_stack, temp_SP, cs_descriptor.dpl, error_code);
|
||||
}
|
||||
}
|
||||
else { // 286 int/trap gate
|
||||
// push long pointer to old stack onto new stack
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-2), cs_descriptor.dpl, old_SS);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-4), cs_descriptor.dpl, (Bit16u) old_ESP);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-6), cs_descriptor.dpl, (Bit16u) read_eflags());
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-8), cs_descriptor.dpl, old_CS);
|
||||
write_new_stack_word_32(&new_stack, (Bit16u)(temp_SP-10), cs_descriptor.dpl, (Bit16u) old_EIP);
|
||||
temp_SP -= 10;
|
||||
|
||||
if (push_error) {
|
||||
temp_SP -= 2;
|
||||
write_new_stack_word_32(&new_stack, temp_SP, cs_descriptor.dpl, error_code);
|
||||
}
|
||||
}
|
||||
|
||||
SP = temp_SP;
|
||||
}
|
||||
|
||||
// load new CS:eIP values from gate
|
||||
// set CPL to new code segment DPL
|
||||
// set RPL of CS to CPL
|
||||
load_cs(&cs_selector, &cs_descriptor, cs_descriptor.dpl);
|
||||
|
||||
// load new SS:eSP values from TSS
|
||||
load_ss(&ss_selector, &ss_descriptor, cs_descriptor.dpl);
|
||||
|
||||
if (is_v8086_mode)
|
||||
{
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BX_DEBUG(("interrupt(): INTERRUPT TO SAME PRIVILEGE"));
|
||||
|
||||
if (v8086_mode() && (IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) || cs_descriptor.dpl != 0)) {
|
||||
// if code segment DPL != 0 then #GP(new code segment selector)
|
||||
BX_ERROR(("interrupt(): code segment conforming or DPL(%d) != 0 in v8086 mode", cs_descriptor.dpl));
|
||||
exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
// EIP must be in CS limit else #GP(0)
|
||||
if (gate_dest_offset > cs_descriptor.u.segment.limit_scaled) {
|
||||
BX_ERROR(("interrupt(): IP > CS descriptor limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// push flags onto stack
|
||||
// push current CS selector onto stack
|
||||
// push return offset onto stack
|
||||
if (gate_descriptor.type >= 14) { // 386 gate
|
||||
push_32(read_eflags());
|
||||
push_32(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_32(EIP);
|
||||
if (push_error)
|
||||
push_32(error_code);
|
||||
}
|
||||
else { // 286 gate
|
||||
push_16((Bit16u) read_eflags());
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_16(IP);
|
||||
if (push_error)
|
||||
push_16(error_code);
|
||||
}
|
||||
|
||||
// load CS:IP from gate
|
||||
// load CS descriptor
|
||||
// set the RPL field of CS to CPL
|
||||
load_cs(&cs_selector, &cs_descriptor, CPL);
|
||||
}
|
||||
|
||||
EIP = gate_dest_offset;
|
||||
|
||||
// if interrupt gate then set IF to 0
|
||||
if (!(gate_descriptor.type & 1)) // even is int-gate
|
||||
BX_CPU_THIS_PTR clear_IF();
|
||||
BX_CPU_THIS_PTR clear_TF();
|
||||
BX_CPU_THIS_PTR clear_NT();
|
||||
BX_CPU_THIS_PTR clear_VM();
|
||||
BX_CPU_THIS_PTR clear_RF();
|
||||
return;
|
||||
|
||||
default:
|
||||
BX_PANIC(("bad descriptor type in interrupt()!"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPU_C::real_mode_int(Bit8u vector, bx_bool push_error, Bit16u error_code)
|
||||
{
|
||||
if ((vector*4+3) > BX_CPU_THIS_PTR idtr.limit) {
|
||||
BX_ERROR(("interrupt(real mode) vector > idtr.limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
push_16((Bit16u) read_eflags());
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
push_16(IP);
|
||||
|
||||
Bit16u new_ip = system_read_word(BX_CPU_THIS_PTR idtr.base + 4 * vector);
|
||||
// CS.LIMIT can't change when in real/v8086 mode
|
||||
if (new_ip > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("interrupt(real mode): instruction pointer not within code segment limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit16u cs_selector = system_read_word(BX_CPU_THIS_PTR idtr.base + 4 * vector + 2);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_selector);
|
||||
EIP = new_ip;
|
||||
|
||||
/* INT affects the following flags: I,T */
|
||||
BX_CPU_THIS_PTR clear_IF();
|
||||
BX_CPU_THIS_PTR clear_TF();
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
BX_CPU_THIS_PTR clear_AC();
|
||||
#endif
|
||||
BX_CPU_THIS_PTR clear_RF();
|
||||
}
|
||||
|
||||
void BX_CPU_C::interrupt(Bit8u vector, unsigned type, bx_bool push_error, Bit16u error_code)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_intsig;
|
||||
#if BX_DEBUG_LINUX
|
||||
if (bx_dbg.linux_syscall) {
|
||||
if (vector == 0x80) bx_dbg_linux_syscall(BX_CPU_ID);
|
||||
}
|
||||
#endif
|
||||
bx_dbg_interrupt(BX_CPU_ID, vector, error_code);
|
||||
#endif
|
||||
|
||||
BX_INSTR_INTERRUPT(BX_CPU_ID, vector);
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
bx_bool soft_int = 0;
|
||||
switch(type) {
|
||||
case BX_SOFTWARE_INTERRUPT:
|
||||
case BX_SOFTWARE_EXCEPTION:
|
||||
soft_int = 1;
|
||||
break;
|
||||
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
|
||||
case BX_EXTERNAL_INTERRUPT:
|
||||
case BX_NMI:
|
||||
case BX_HARDWARE_EXCEPTION:
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("interrupt(): unknown exception type %d", type));
|
||||
}
|
||||
|
||||
BX_DEBUG(("interrupt(): vector = %02x, TYPE = %u, EXT = %u",
|
||||
vector, type, (unsigned) BX_CPU_THIS_PTR EXT));
|
||||
|
||||
// Discard any traps and inhibits for new context; traps will
|
||||
// resume upon return.
|
||||
BX_CPU_THIS_PTR debug_trap = 0;
|
||||
BX_CPU_THIS_PTR inhibit_mask = 0;
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
BX_CPU_THIS_PTR in_event = 1;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
long_mode_int(vector, soft_int, push_error, error_code);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if(real_mode()) {
|
||||
real_mode_int(vector, push_error, error_code);
|
||||
}
|
||||
else {
|
||||
protected_mode_int(vector, soft_int, push_error, error_code);
|
||||
}
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
#if BX_X86_DEBUGGER
|
||||
BX_CPU_THIS_PTR in_repeat = 0;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
BX_CPU_THIS_PTR in_event = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Exception classes. These are used as indexes into the 'is_exception_OK'
|
||||
* array below, and are stored in the 'exception' array also
|
||||
*/
|
||||
#define BX_ET_BENIGN 0
|
||||
#define BX_ET_CONTRIBUTORY 1
|
||||
#define BX_ET_PAGE_FAULT 2
|
||||
|
||||
#define BX_ET_DOUBLE_FAULT 10
|
||||
|
||||
static const bx_bool is_exception_OK[3][3] = {
|
||||
{ 1, 1, 1 }, /* 1st exception is BENIGN */
|
||||
{ 1, 0, 1 }, /* 1st exception is CONTRIBUTORY */
|
||||
{ 1, 0, 0 } /* 1st exception is PAGE_FAULT */
|
||||
};
|
||||
|
||||
#define BX_EXCEPTION_CLASS_TRAP 0
|
||||
#define BX_EXCEPTION_CLASS_FAULT 1
|
||||
#define BX_EXCEPTION_CLASS_ABORT 2
|
||||
|
||||
struct BxExceptionInfo exceptions_info[BX_CPU_HANDLED_EXCEPTIONS+1] = {
|
||||
/* DE */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* DB */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 }, // NMI
|
||||
/* BP */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_TRAP, 0 },
|
||||
/* OF */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_TRAP, 0 },
|
||||
/* BR */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* UD */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* NM */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* DF */ { BX_ET_DOUBLE_FAULT, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
// coprocessor segment overrun (286,386 only)
|
||||
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* TS */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
/* NP */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
/* SS */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
/* GP */ { BX_ET_CONTRIBUTORY, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
/* PF */ { BX_ET_PAGE_FAULT, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 }, // reserved
|
||||
/* MF */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* AC */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 1 },
|
||||
/* MC */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_ABORT, 0 },
|
||||
/* XM */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 },
|
||||
/* -- */ { BX_ET_BENIGN, BX_EXCEPTION_CLASS_FAULT, 0 } // default
|
||||
};
|
||||
|
||||
// vector: 0..255: vector in IDT
|
||||
// error_code: if exception generates and error, push this error code
|
||||
// trap: override exception class to TRAP
|
||||
void BX_CPU_C::exception(unsigned vector, Bit16u error_code)
|
||||
{
|
||||
BX_INSTR_EXCEPTION(BX_CPU_ID, vector, error_code);
|
||||
|
||||
#if BX_DEBUGGER
|
||||
bx_dbg_exception(BX_CPU_ID, vector, error_code);
|
||||
#endif
|
||||
|
||||
BX_DEBUG(("exception(0x%02x): error_code=%04x", vector, error_code));
|
||||
|
||||
unsigned exception_type = 0;
|
||||
unsigned exception_class = BX_EXCEPTION_CLASS_FAULT;
|
||||
bx_bool push_error = 0;
|
||||
|
||||
if (vector < BX_CPU_HANDLED_EXCEPTIONS) {
|
||||
push_error = exceptions_info[vector].push_error;
|
||||
exception_class = exceptions_info[vector].exception_class;
|
||||
exception_type = exceptions_info[vector].exception_type;
|
||||
}
|
||||
else {
|
||||
BX_PANIC(("exception(%u): bad vector", vector));
|
||||
}
|
||||
|
||||
if (vector != BX_PF_EXCEPTION && vector != BX_DF_EXCEPTION) {
|
||||
// Page faults have different format
|
||||
error_code = (error_code & 0xfffe) | BX_CPU_THIS_PTR EXT;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_Event(0, BX_HARDWARE_EXCEPTION, vector, error_code, push_error);
|
||||
#endif
|
||||
|
||||
if (BX_CPU_THIS_PTR errorno > 0) {
|
||||
if (BX_CPU_THIS_PTR errorno > 2 || BX_CPU_THIS_PTR curr_exception == BX_ET_DOUBLE_FAULT) {
|
||||
// restore RIP/RSP to value before error occurred
|
||||
RIP = BX_CPU_THIS_PTR prev_rip;
|
||||
if (BX_CPU_THIS_PTR speculative_rsp)
|
||||
RSP = BX_CPU_THIS_PTR prev_rsp;
|
||||
|
||||
debug(BX_CPU_THIS_PTR prev_rip); // print debug information to the log
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_TripleFault();
|
||||
#endif
|
||||
#if BX_DEBUGGER
|
||||
// trap into debugger (similar as done when PANIC occured)
|
||||
bx_debug_break();
|
||||
#endif
|
||||
if (SIM->get_param_bool(BXPN_RESET_ON_TRIPLE_FAULT)->get()) {
|
||||
BX_ERROR(("exception(): 3rd (%d) exception with no resolution, shutdown status is %02xh, resetting", vector, DEV_cmos_get_reg(0x0f)));
|
||||
bx_pc_system.Reset(BX_RESET_HARDWARE);
|
||||
}
|
||||
else {
|
||||
BX_PANIC(("exception(): 3rd (%d) exception with no resolution", vector));
|
||||
BX_ERROR(("WARNING: Any simulation after this point is completely bogus !"));
|
||||
shutdown();
|
||||
}
|
||||
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
|
||||
}
|
||||
}
|
||||
|
||||
// note: fault-class exceptions _except_ #DB set RF in
|
||||
// eflags image.
|
||||
if (exception_class == BX_EXCEPTION_CLASS_FAULT)
|
||||
{
|
||||
// restore RIP/RSP to value before error occurred
|
||||
RIP = BX_CPU_THIS_PTR prev_rip;
|
||||
if (BX_CPU_THIS_PTR speculative_rsp)
|
||||
RSP = BX_CPU_THIS_PTR prev_rsp;
|
||||
|
||||
if (vector != BX_DB_EXCEPTION) BX_CPU_THIS_PTR assert_RF();
|
||||
}
|
||||
|
||||
if (vector == BX_DB_EXCEPTION) {
|
||||
// Commit debug events to DR6
|
||||
#if BX_CPU_LEVEL <= 4
|
||||
// On 386/486 bit12 is settable
|
||||
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
|
||||
(BX_CPU_THIS_PTR debug_trap & 0x0000f00f);
|
||||
#else
|
||||
// On Pentium+, bit12 is always zero
|
||||
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
|
||||
(BX_CPU_THIS_PTR debug_trap & 0x0000e00f);
|
||||
#endif
|
||||
// clear GD flag in the DR7 prior entering debug exception handler
|
||||
BX_CPU_THIS_PTR dr7 &= ~0x00002000;
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR EXT = 1;
|
||||
|
||||
/* if we've already had 1st exception, see if 2nd causes a
|
||||
* Double Fault instead. Otherwise, just record 1st exception
|
||||
*/
|
||||
if (BX_CPU_THIS_PTR errorno > 0 && exception_type != BX_ET_DOUBLE_FAULT) {
|
||||
if (! is_exception_OK[BX_CPU_THIS_PTR curr_exception][exception_type]) {
|
||||
exception(BX_DF_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR curr_exception = exception_type;
|
||||
BX_CPU_THIS_PTR errorno++;
|
||||
|
||||
if (real_mode()) {
|
||||
push_error = 0; // not INT, no error code pushed
|
||||
error_code = 0;
|
||||
}
|
||||
|
||||
interrupt(vector, BX_HARDWARE_EXCEPTION, push_error, error_code);
|
||||
BX_CPU_THIS_PTR errorno = 0; // error resolved
|
||||
longjmp(BX_CPU_THIS_PTR jmp_buf_env, 1); // go back to main decode loop
|
||||
}
|
||||
1811
simulators/bochs/cpu/fetchdecode.cc
Normal file
1811
simulators/bochs/cpu/fetchdecode.cc
Normal file
File diff suppressed because it is too large
Load Diff
793
simulators/bochs/cpu/fetchdecode.h
Executable file
793
simulators/bochs/cpu/fetchdecode.h
Executable file
@ -0,0 +1,793 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-2011 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_COMMON_FETCHDECODE_TABLES_H
|
||||
#define BX_COMMON_FETCHDECODE_TABLES_H
|
||||
|
||||
typedef struct BxOpcodeInfo_t {
|
||||
Bit16u Attr;
|
||||
Bit16u IA;
|
||||
const BxOpcodeInfo_t *AnotherArray;
|
||||
} BxOpcodeInfo_t;
|
||||
|
||||
//
|
||||
// This file contains common IA-32/X86-64 opcode tables, like FPU opcode
|
||||
// table, 3DNow! opcode table or SSE opcode groups (choose the opcode
|
||||
// according to instruction prefixes)
|
||||
//
|
||||
|
||||
BX_CPP_INLINE Bit16u FetchWORD(const Bit8u *iptr)
|
||||
{
|
||||
Bit16u data;
|
||||
ReadHostWordFromLittleEndian(iptr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE Bit32u FetchDWORD(const Bit8u *iptr)
|
||||
{
|
||||
Bit32u data;
|
||||
ReadHostDWordFromLittleEndian(iptr, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE Bit64u FetchQWORD(const Bit8u *iptr)
|
||||
{
|
||||
Bit64u data;
|
||||
ReadHostQWordFromLittleEndian(iptr, data);
|
||||
return data;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define BX_PREPARE_SSE (0x01)
|
||||
#define BX_PREPARE_AVX (0x02)
|
||||
#define BX_VEX_L128 (0x04) /* VEX.L128 allowed */
|
||||
#define BX_VEX_L256 (0x08) /* VEX.L256 allowed */
|
||||
|
||||
struct bxIAOpcodeTable {
|
||||
BxExecutePtr_tR execute1;
|
||||
BxExecutePtr_tR execute2;
|
||||
Bit32u flags;
|
||||
};
|
||||
|
||||
//
|
||||
// Common FetchDecode Opcode Tables
|
||||
//
|
||||
|
||||
#include "fetchdecode_x87.h"
|
||||
#include "fetchdecode_sse.h"
|
||||
|
||||
/* ************************************************************************ */
|
||||
/* Opcode Groups */
|
||||
|
||||
/* ******* */
|
||||
/* Group 1 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG1EbIb[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { BxLockable, BX_IA_ADD_EbIb },
|
||||
/* 1 */ { BxLockable, BX_IA_OR_EbIb },
|
||||
/* 2 */ { BxLockable, BX_IA_ADC_EbIb },
|
||||
/* 3 */ { BxLockable, BX_IA_SBB_EbIb },
|
||||
/* 4 */ { BxLockable, BX_IA_AND_EbIb },
|
||||
/* 5 */ { BxLockable, BX_IA_SUB_EbIb },
|
||||
/* 6 */ { BxLockable, BX_IA_XOR_EbIb },
|
||||
/* 7 */ { 0, BX_IA_CMP_EbIb }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG1Ew[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { BxLockable, BX_IA_ADD_EwIw },
|
||||
/* 1 */ { BxLockable, BX_IA_OR_EwIw },
|
||||
/* 2 */ { BxLockable, BX_IA_ADC_EwIw },
|
||||
/* 3 */ { BxLockable, BX_IA_SBB_EwIw },
|
||||
/* 4 */ { BxLockable, BX_IA_AND_EwIw },
|
||||
/* 5 */ { BxLockable, BX_IA_SUB_EwIw },
|
||||
/* 6 */ { BxLockable, BX_IA_XOR_EwIw },
|
||||
/* 7 */ { 0, BX_IA_CMP_EwIw }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG1Ed[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { BxLockable, BX_IA_ADD_EdId },
|
||||
/* 1 */ { BxLockable, BX_IA_OR_EdId },
|
||||
/* 2 */ { BxLockable, BX_IA_ADC_EdId },
|
||||
/* 3 */ { BxLockable, BX_IA_SBB_EdId },
|
||||
/* 4 */ { BxLockable, BX_IA_AND_EdId },
|
||||
/* 5 */ { BxLockable, BX_IA_SUB_EdId },
|
||||
/* 6 */ { BxLockable, BX_IA_XOR_EdId },
|
||||
/* 7 */ { 0, BX_IA_CMP_EdId }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G1Eq[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { BxLockable, BX_IA_ADD_EqId },
|
||||
/* 1 */ { BxLockable, BX_IA_OR_EqId },
|
||||
/* 2 */ { BxLockable, BX_IA_ADC_EqId },
|
||||
/* 3 */ { BxLockable, BX_IA_SBB_EqId },
|
||||
/* 4 */ { BxLockable, BX_IA_AND_EqId },
|
||||
/* 5 */ { BxLockable, BX_IA_SUB_EqId },
|
||||
/* 6 */ { BxLockable, BX_IA_XOR_EqId },
|
||||
/* 7 */ { 0, BX_IA_CMP_EqId }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******** */
|
||||
/* Group 1A */
|
||||
/* ******** */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG1AEw[8] = {
|
||||
/* 0 */ { 0, BX_IA_POP_Ew },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG1AEd[8] = {
|
||||
/* 0 */ { 0, BX_IA_POP_Ed },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G1AEq[8] = {
|
||||
/* 0 */ { 0, BX_IA_POP_Eq },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******* */
|
||||
/* Group 2 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG2Eb[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { 0, BX_IA_ROL_Eb },
|
||||
/* 1 */ { 0, BX_IA_ROR_Eb },
|
||||
/* 2 */ { 0, BX_IA_RCL_Eb },
|
||||
/* 3 */ { 0, BX_IA_RCR_Eb },
|
||||
/* 4 */ { 0, BX_IA_SHL_Eb },
|
||||
/* 5 */ { 0, BX_IA_SHR_Eb },
|
||||
/* 6 */ { 0, BX_IA_SHL_Eb },
|
||||
/* 7 */ { 0, BX_IA_SAR_Eb }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG2Ew[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { 0, BX_IA_ROL_Ew },
|
||||
/* 1 */ { 0, BX_IA_ROR_Ew },
|
||||
/* 2 */ { 0, BX_IA_RCL_Ew },
|
||||
/* 3 */ { 0, BX_IA_RCR_Ew },
|
||||
/* 4 */ { 0, BX_IA_SHL_Ew },
|
||||
/* 5 */ { 0, BX_IA_SHR_Ew },
|
||||
/* 6 */ { 0, BX_IA_SHL_Ew },
|
||||
/* 7 */ { 0, BX_IA_SAR_Ew }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG2Ed[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { 0, BX_IA_ROL_Ed },
|
||||
/* 1 */ { 0, BX_IA_ROR_Ed },
|
||||
/* 2 */ { 0, BX_IA_RCL_Ed },
|
||||
/* 3 */ { 0, BX_IA_RCR_Ed },
|
||||
/* 4 */ { 0, BX_IA_SHL_Ed },
|
||||
/* 5 */ { 0, BX_IA_SHR_Ed },
|
||||
/* 6 */ { 0, BX_IA_SHL_Ed },
|
||||
/* 7 */ { 0, BX_IA_SAR_Ed }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G2Eq[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { 0, BX_IA_ROL_Eq },
|
||||
/* 1 */ { 0, BX_IA_ROR_Eq },
|
||||
/* 2 */ { 0, BX_IA_RCL_Eq },
|
||||
/* 3 */ { 0, BX_IA_RCR_Eq },
|
||||
/* 4 */ { 0, BX_IA_SHL_Eq },
|
||||
/* 5 */ { 0, BX_IA_SHR_Eq },
|
||||
/* 6 */ { 0, BX_IA_SHL_Eq },
|
||||
/* 7 */ { 0, BX_IA_SAR_Eq }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******* */
|
||||
/* Group 3 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG3Eb[8] = {
|
||||
/* 0 */ { BxImmediate_Ib, BX_IA_TEST_EbIb },
|
||||
/* 1 */ { BxImmediate_Ib, BX_IA_TEST_EbIb },
|
||||
/* 2 */ { BxLockable, BX_IA_NOT_Eb },
|
||||
/* 3 */ { BxLockable, BX_IA_NEG_Eb },
|
||||
/* 4 */ { 0, BX_IA_MUL_ALEb },
|
||||
/* 5 */ { 0, BX_IA_IMUL_ALEb },
|
||||
/* 6 */ { 0, BX_IA_DIV_ALEb },
|
||||
/* 7 */ { 0, BX_IA_IDIV_ALEb }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG3Ew[8] = {
|
||||
/* 0 */ { BxImmediate_Iw, BX_IA_TEST_EwIw },
|
||||
/* 1 */ { BxImmediate_Iw, BX_IA_TEST_EwIw },
|
||||
/* 2 */ { BxLockable, BX_IA_NOT_Ew },
|
||||
/* 3 */ { BxLockable, BX_IA_NEG_Ew },
|
||||
/* 4 */ { 0, BX_IA_MUL_AXEw },
|
||||
/* 5 */ { 0, BX_IA_IMUL_AXEw },
|
||||
/* 6 */ { 0, BX_IA_DIV_AXEw },
|
||||
/* 7 */ { 0, BX_IA_IDIV_AXEw }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG3Ed[8] = {
|
||||
/* 0 */ { BxImmediate_Id, BX_IA_TEST_EdId },
|
||||
/* 1 */ { BxImmediate_Id, BX_IA_TEST_EdId },
|
||||
/* 2 */ { BxLockable, BX_IA_NOT_Ed },
|
||||
/* 3 */ { BxLockable, BX_IA_NEG_Ed },
|
||||
/* 4 */ { 0, BX_IA_MUL_EAXEd },
|
||||
/* 5 */ { 0, BX_IA_IMUL_EAXEd },
|
||||
/* 6 */ { 0, BX_IA_DIV_EAXEd },
|
||||
/* 7 */ { 0, BX_IA_IDIV_EAXEd }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G3Eq[8] = {
|
||||
/* 0 */ { BxImmediate_Id, BX_IA_TEST_EqId },
|
||||
/* 1 */ { BxImmediate_Id, BX_IA_TEST_EqId },
|
||||
/* 2 */ { BxLockable, BX_IA_NOT_Eq },
|
||||
/* 3 */ { BxLockable, BX_IA_NEG_Eq },
|
||||
/* 4 */ { 0, BX_IA_MUL_RAXEq },
|
||||
/* 5 */ { 0, BX_IA_IMUL_RAXEq },
|
||||
/* 6 */ { 0, BX_IA_DIV_RAXEq },
|
||||
/* 7 */ { 0, BX_IA_IDIV_RAXEq }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******* */
|
||||
/* Group 4 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG4[8] = {
|
||||
/* 0 */ { BxLockable, BX_IA_INC_Eb },
|
||||
/* 1 */ { BxLockable, BX_IA_DEC_Eb },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
/* ******* */
|
||||
/* Group 5 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG5w[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { BxLockable, BX_IA_INC_Ew },
|
||||
/* 1 */ { BxLockable, BX_IA_DEC_Ew },
|
||||
/* 2 */ { BxTraceEnd, BX_IA_CALL_Ew },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_CALL16_Ep },
|
||||
/* 4 */ { BxTraceEnd, BX_IA_JMP_Ew },
|
||||
/* 5 */ { BxTraceEnd, BX_IA_JMP16_Ep },
|
||||
/* 6 */ { 0, BX_IA_PUSH_Ew },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG5d[8] = {
|
||||
// attributes defined in main area
|
||||
/* 0 */ { BxLockable, BX_IA_INC_Ed },
|
||||
/* 1 */ { BxLockable, BX_IA_DEC_Ed },
|
||||
/* 2 */ { BxTraceEnd, BX_IA_CALL_Ed },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_CALL32_Ep },
|
||||
/* 4 */ { BxTraceEnd, BX_IA_JMP_Ed },
|
||||
/* 5 */ { BxTraceEnd, BX_IA_JMP32_Ep },
|
||||
/* 6 */ { 0, BX_IA_PUSH_Ed },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G5w[8] = {
|
||||
/* 0 */ { BxLockable, BX_IA_INC_Ew },
|
||||
/* 1 */ { BxLockable, BX_IA_DEC_Ew },
|
||||
/* 2 */ { BxTraceEnd, BX_IA_CALL_Eq },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_CALL16_Ep },
|
||||
/* 4 */ { BxTraceEnd, BX_IA_JMP_Eq },
|
||||
/* 5 */ { BxTraceEnd, BX_IA_JMP16_Ep },
|
||||
/* 6 */ { 0, BX_IA_PUSH_Ew },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G5d[8] = {
|
||||
/* 0 */ { BxLockable, BX_IA_INC_Ed },
|
||||
/* 1 */ { BxLockable, BX_IA_DEC_Ed },
|
||||
/* 2 */ { BxTraceEnd, BX_IA_CALL_Eq },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_CALL32_Ep },
|
||||
/* 4 */ { BxTraceEnd, BX_IA_JMP_Eq },
|
||||
/* 5 */ { BxTraceEnd, BX_IA_JMP32_Ep },
|
||||
/* 6 */ { 0, BX_IA_PUSH_Eq },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G5q[8] = {
|
||||
/* 0 */ { BxLockable, BX_IA_INC_Eq },
|
||||
/* 1 */ { BxLockable, BX_IA_DEC_Eq },
|
||||
/* 2 */ { BxTraceEnd, BX_IA_CALL_Eq },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_CALL64_Ep }, // TODO: 64-bit offset for Intel
|
||||
/* 4 */ { BxTraceEnd, BX_IA_JMP_Eq },
|
||||
/* 5 */ { BxTraceEnd, BX_IA_JMP64_Ep }, // TODO: 64-bit offset for Intel
|
||||
/* 6 */ { 0, BX_IA_PUSH_Eq },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******* */
|
||||
/* Group 6 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG6[8] = {
|
||||
/* 0 */ { 0, BX_IA_SLDT_Ew },
|
||||
/* 1 */ { 0, BX_IA_STR_Ew },
|
||||
/* 2 */ { 0, BX_IA_LLDT_Ew },
|
||||
/* 3 */ { 0, BX_IA_LTR_Ew },
|
||||
/* 4 */ { 0, BX_IA_VERR_Ew },
|
||||
/* 5 */ { 0, BX_IA_VERW_Ew },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
/* ******* */
|
||||
/* Group 7 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG7[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_SGDT_Ms },
|
||||
/* 1 */ { 0, BX_IA_SIDT_Ms },
|
||||
/* 2 */ { 0, BX_IA_LGDT_Ms },
|
||||
/* 3 */ { 0, BX_IA_LIDT_Ms },
|
||||
/* 4 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 7 */ { BxTraceEnd, BX_IA_INVLPG },
|
||||
|
||||
/* /r form */
|
||||
/* 0F 01 C0 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C1 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMCALL, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C2 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMLAUNCH, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C3 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMRESUME, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C4 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMXOFF, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C5 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C6 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C7 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C8 */ { BxPrefixSSE, BX_IA_MONITOR, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C9 */ { BxPrefixSSE | BxTraceEnd, BX_IA_MWAIT, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 CA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CD */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CF */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D0 */ { BxPrefixSSE, BX_IA_XGETBV, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 D1 */ { BxPrefixSSE, BX_IA_XSETBV, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 D2 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D3 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D4 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D5 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D6 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D7 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D8 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D9 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DD */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DF */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 E0 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E1 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E2 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E3 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E4 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E5 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E6 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E7 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E8 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 E9 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 ED */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EF */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 F0 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F1 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F2 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F3 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F4 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F5 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F7 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F8 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 F9 */ { 0, BX_IA_RDTSCP },
|
||||
/* 0F 01 FA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FD */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FF */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG7q[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_SGDT64_Ms },
|
||||
/* 1 */ { 0, BX_IA_SIDT64_Ms },
|
||||
/* 2 */ { 0, BX_IA_LGDT64_Ms },
|
||||
/* 3 */ { 0, BX_IA_LIDT64_Ms },
|
||||
/* 4 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 7 */ { BxTraceEnd, BX_IA_INVLPG },
|
||||
|
||||
/* /r form */
|
||||
/* 0F 01 C0 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C1 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMCALL, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C2 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMLAUNCH, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C3 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMRESUME, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C4 */ { BxTraceEnd | BxPrefixSSE, BX_IA_VMXOFF, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C5 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C6 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C7 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 C8 */ { BxPrefixSSE, BX_IA_MONITOR, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 C9 */ { BxPrefixSSE | BxTraceEnd, BX_IA_MWAIT, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 CA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CD */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 CF */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D0 */ { BxPrefixSSE, BX_IA_XGETBV, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 D1 */ { BxPrefixSSE, BX_IA_XSETBV, BxOpcodeGroupSSE_ERR },
|
||||
/* 0F 01 D2 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D3 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D4 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D5 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D6 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D7 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D8 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 D9 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DD */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 DF */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 E0 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E1 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E2 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E3 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E4 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E5 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E6 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E7 */ { 0, BX_IA_SMSW_Ew },
|
||||
/* 0F 01 E8 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 E9 */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 ED */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 EF */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 F0 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F1 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F2 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F3 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F4 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F5 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F6 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F7 */ { BxTraceEnd, BX_IA_LMSW_Ew },
|
||||
/* 0F 01 F8 */ { 0, BX_IA_SWAPGS },
|
||||
/* 0F 01 F9 */ { 0, BX_IA_RDTSCP },
|
||||
/* 0F 01 FA */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FB */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FC */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FD */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FE */ { 0, BX_IA_ERROR },
|
||||
/* 0F 01 FF */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******* */
|
||||
/* Group 8 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG8EwIb[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { BxImmediate_Ib, BX_IA_BT_EwIb },
|
||||
/* 5 */ { BxImmediate_Ib | BxLockable, BX_IA_BTS_EwIb },
|
||||
/* 6 */ { BxImmediate_Ib | BxLockable, BX_IA_BTR_EwIb },
|
||||
/* 7 */ { BxImmediate_Ib | BxLockable, BX_IA_BTC_EwIb }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG8EdIb[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { BxImmediate_Ib, BX_IA_BT_EdIb },
|
||||
/* 5 */ { BxImmediate_Ib | BxLockable, BX_IA_BTS_EdIb },
|
||||
/* 6 */ { BxImmediate_Ib | BxLockable, BX_IA_BTR_EdIb },
|
||||
/* 7 */ { BxImmediate_Ib | BxLockable, BX_IA_BTC_EdIb }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G8EqIb[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { BxImmediate_Ib, BX_IA_BT_EqIb },
|
||||
/* 5 */ { BxImmediate_Ib | BxLockable, BX_IA_BTS_EqIb },
|
||||
/* 6 */ { BxImmediate_Ib | BxLockable, BX_IA_BTR_EqIb },
|
||||
/* 7 */ { BxImmediate_Ib | BxLockable, BX_IA_BTC_EqIb }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******* */
|
||||
/* Group 9 */
|
||||
/* ******* */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG9M[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { BxLockable, BX_IA_CMPXCHG8B },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxPrefixSSE, BX_IA_VMPTRLD_Mq, BxOpcodeGroupSSE_G9VMX6 },
|
||||
/* 7 */ { BxPrefixSSE, BX_IA_VMPTRST_Mq, BxOpcodeGroupSSE_ERR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G9qM[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { BxLockable, BX_IA_CMPXCHG16B },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxPrefixSSE, BX_IA_VMPTRLD_Mq, BxOpcodeGroupSSE_G9VMX6 },
|
||||
/* 7 */ { BxPrefixSSE, BX_IA_VMPTRST_Mq, BxOpcodeGroupSSE_ERR }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******** */
|
||||
/* Group 11 */
|
||||
/* ******** */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG11Eb[8] = {
|
||||
/* 0 */ { BxImmediate_Ib, BX_IA_MOV_EbIb },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG11Ew[8] = {
|
||||
/* 0 */ { BxImmediate_Iw, BX_IA_MOV_EwIw },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG11Ed[8] = {
|
||||
/* 0 */ { BxImmediate_Id, BX_IA_MOV_EdId },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo64G11Eq[8] = {
|
||||
/* 0 */ { BxImmediate_Id, BX_IA_MOV_EqId },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ******** */
|
||||
/* Group 12 */
|
||||
/* ******** */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG12R[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRLW_PqIb, BxOpcodeGroupSSE_G1202 },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRAW_PqIb, BxOpcodeGroupSSE_G1204 },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSLLW_PqIb, BxOpcodeGroupSSE_G1206 },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
/* ******** */
|
||||
/* Group 13 */
|
||||
/* ******** */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG13R[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRLD_PqIb, BxOpcodeGroupSSE_G1302 },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRAD_PqIb, BxOpcodeGroupSSE_G1304 },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSLLD_PqIb, BxOpcodeGroupSSE_G1306 },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
/* ******** */
|
||||
/* Group 14 */
|
||||
/* ******** */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG14R[8] = {
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSRLQ_PqIb, BxOpcodeGroupSSE_G1402 },
|
||||
/* 3 */ { BxImmediate_Ib | BxPrefixSSE66, BX_IA_PSRLDQ_UdqIb },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { BxImmediate_Ib | BxPrefixSSE, BX_IA_PSLLQ_PqIb, BxOpcodeGroupSSE_G1406 },
|
||||
/* 7 */ { BxImmediate_Ib | BxPrefixSSE66, BX_IA_PSLLDQ_UdqIb }
|
||||
};
|
||||
|
||||
/* ******** */
|
||||
/* Group 15 */
|
||||
/* ******** */
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG15[8*2] = {
|
||||
/* /r form */
|
||||
/* 0 */ { 0, BX_IA_ERROR },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_ERROR },
|
||||
/* 3 */ { 0, BX_IA_ERROR },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { BxPrefixSSE, BX_IA_LFENCE, BxOpcodeGroupSSE_ERR },
|
||||
/* 6 */ { BxPrefixSSE, BX_IA_MFENCE, BxOpcodeGroupSSE_ERR },
|
||||
/* 7 */ { BxPrefixSSE, BX_IA_SFENCE, BxOpcodeGroupSSE_ERR },
|
||||
|
||||
/* /m form */
|
||||
/* 0 */ { BxPrefixSSE, BX_IA_FXSAVE, BxOpcodeGroupSSE_ERR },
|
||||
/* 1 */ { BxPrefixSSE, BX_IA_FXRSTOR, BxOpcodeGroupSSE_ERR },
|
||||
/* 2 */ { BxPrefixSSE, BX_IA_LDMXCSR, BxOpcodeGroupSSE_ERR },
|
||||
/* 3 */ { BxPrefixSSE, BX_IA_STMXCSR, BxOpcodeGroupSSE_ERR },
|
||||
/* 4 */ { BxPrefixSSE, BX_IA_XSAVE, BxOpcodeGroupSSE_ERR },
|
||||
/* 5 */ { BxPrefixSSE, BX_IA_XRSTOR, BxOpcodeGroupSSE_ERR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { BxPrefixSSE, BX_IA_CLFLUSH, BxOpcodeGroupSSE_ERR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoG15q[8*2] = {
|
||||
/* /r form */
|
||||
/* 0 */ { BxPrefixSSEF3, BX_IA_RDFSBASE },
|
||||
/* 1 */ { BxPrefixSSEF3, BX_IA_RDGSBASE },
|
||||
/* 2 */ { BxPrefixSSEF3, BX_IA_WRFSBASE },
|
||||
/* 3 */ { BxPrefixSSEF3, BX_IA_WRGSBASE },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { BxPrefixSSE, BX_IA_LFENCE, BxOpcodeGroupSSE_ERR },
|
||||
/* 6 */ { BxPrefixSSE, BX_IA_MFENCE, BxOpcodeGroupSSE_ERR },
|
||||
/* 7 */ { BxPrefixSSE, BX_IA_SFENCE, BxOpcodeGroupSSE_ERR },
|
||||
|
||||
/* /m form */
|
||||
/* 0 */ { BxPrefixSSE, BX_IA_FXSAVE, BxOpcodeGroupSSE_ERR },
|
||||
/* 1 */ { BxPrefixSSE, BX_IA_FXRSTOR, BxOpcodeGroupSSE_ERR },
|
||||
/* 2 */ { BxPrefixSSE, BX_IA_LDMXCSR, BxOpcodeGroupSSE_ERR },
|
||||
/* 3 */ { BxPrefixSSE, BX_IA_STMXCSR, BxOpcodeGroupSSE_ERR },
|
||||
/* 4 */ { BxPrefixSSE, BX_IA_XSAVE, BxOpcodeGroupSSE_ERR },
|
||||
/* 5 */ { BxPrefixSSE, BX_IA_XRSTOR, BxOpcodeGroupSSE_ERR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { BxPrefixSSE, BX_IA_CLFLUSH, BxOpcodeGroupSSE_ERR }
|
||||
};
|
||||
#endif
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoMOV_RdCd[8] = {
|
||||
/* 0 */ { 0, BX_IA_MOV_RdCR0 },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_MOV_RdCR2 },
|
||||
/* 3 */ { 0, BX_IA_MOV_RdCR3 },
|
||||
/* 4 */ { 0, BX_IA_MOV_RdCR4 },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoMOV_CdRd[8] = {
|
||||
/* 0 */ { BxTraceEnd, BX_IA_MOV_CR0Rd },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_MOV_CR2Rd },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_MOV_CR3Rd },
|
||||
/* 4 */ { BxTraceEnd, BX_IA_MOV_CR4Rd },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoMOV_RqCq[8] = {
|
||||
/* 0 */ { 0, BX_IA_MOV_RqCR0 },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_MOV_RqCR2 },
|
||||
/* 3 */ { 0, BX_IA_MOV_RqCR3 },
|
||||
/* 4 */ { 0, BX_IA_MOV_RqCR4 },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
static const BxOpcodeInfo_t BxOpcodeInfoMOV_CqRq[8] = {
|
||||
/* 0 */ { BxTraceEnd, BX_IA_MOV_CR0Rq },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_MOV_CR2Rq },
|
||||
/* 3 */ { BxTraceEnd, BX_IA_MOV_CR3Rq },
|
||||
/* 4 */ { BxTraceEnd, BX_IA_MOV_CR4Rq },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // BX_COMMON_FETCHDECODE_TABLES_H
|
||||
2228
simulators/bochs/cpu/fetchdecode64.cc
Normal file
2228
simulators/bochs/cpu/fetchdecode64.cc
Normal file
File diff suppressed because it is too large
Load Diff
1424
simulators/bochs/cpu/fetchdecode_sse.h
Executable file
1424
simulators/bochs/cpu/fetchdecode_sse.h
Executable file
File diff suppressed because it is too large
Load Diff
768
simulators/bochs/cpu/fetchdecode_x87.h
Executable file
768
simulators/bochs/cpu/fetchdecode_x87.h
Executable file
@ -0,0 +1,768 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_X87_FETCHDECODE_TABLES_H
|
||||
#define BX_X87_FETCHDECODE_TABLES_H
|
||||
|
||||
//
|
||||
// Common FetchDecode Opcode Tables - x87 and 3dnow!
|
||||
//
|
||||
|
||||
#if BX_SUPPORT_FPU
|
||||
|
||||
/* ************************************************************************ */
|
||||
/* FPU Opcodes */
|
||||
|
||||
// D8 (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FPGroupD8[8*2] = {
|
||||
/* /r form */
|
||||
/* 0 */ { 0, BX_IA_FADD_ST0_STj },
|
||||
/* 1 */ { 0, BX_IA_FMUL_ST0_STj },
|
||||
/* 2 */ { 0, BX_IA_FCOM_STi },
|
||||
/* 3 */ { 0, BX_IA_FCOMP_STi },
|
||||
/* 4 */ { 0, BX_IA_FSUB_ST0_STj },
|
||||
/* 5 */ { 0, BX_IA_FSUBR_ST0_STj },
|
||||
/* 6 */ { 0, BX_IA_FDIV_ST0_STj },
|
||||
/* 7 */ { 0, BX_IA_FDIVR_ST0_STj },
|
||||
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FADD_SINGLE_REAL },
|
||||
/* 1 */ { 0, BX_IA_FMUL_SINGLE_REAL },
|
||||
/* 2 */ { 0, BX_IA_FCOM_SINGLE_REAL },
|
||||
/* 3 */ { 0, BX_IA_FCOMP_SINGLE_REAL },
|
||||
/* 4 */ { 0, BX_IA_FSUB_SINGLE_REAL },
|
||||
/* 5 */ { 0, BX_IA_FSUBR_SINGLE_REAL },
|
||||
/* 6 */ { 0, BX_IA_FDIV_SINGLE_REAL },
|
||||
/* 7 */ { 0, BX_IA_FDIVR_SINGLE_REAL }
|
||||
};
|
||||
|
||||
// D9 (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointD9[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FLD_SINGLE_REAL },
|
||||
/* 1 */ { 0, BX_IA_ERROR },
|
||||
/* 2 */ { 0, BX_IA_FST_SINGLE_REAL },
|
||||
/* 3 */ { 0, BX_IA_FSTP_SINGLE_REAL },
|
||||
/* 4 */ { 0, BX_IA_FLDENV },
|
||||
/* 5 */ { 0, BX_IA_FLDCW },
|
||||
/* 6 */ { 0, BX_IA_FNSTENV },
|
||||
/* 7 */ { 0, BX_IA_FNSTCW },
|
||||
|
||||
/* /r form */
|
||||
/* D9 C0 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C1 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C2 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C3 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C4 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C5 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C6 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C7 */ { 0, BX_IA_FLD_STi },
|
||||
/* D9 C8 */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 C9 */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 CA */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 CB */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 CC */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 CD */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 CE */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 CF */ { 0, BX_IA_FXCH_STi },
|
||||
/* D9 D0 */ { 0, BX_IA_FNOP },
|
||||
/* D9 D1 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D2 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D3 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D4 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D5 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D6 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D7 */ { 0, BX_IA_ERROR },
|
||||
/* D9 D8 */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 D9 */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 DA */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 DB */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 DC */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 DD */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 DE */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 DF */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* D9 E0 */ { 0, BX_IA_FCHS },
|
||||
/* D9 E1 */ { 0, BX_IA_FABS },
|
||||
/* D9 E2 */ { 0, BX_IA_ERROR },
|
||||
/* D9 E3 */ { 0, BX_IA_ERROR },
|
||||
/* D9 E4 */ { 0, BX_IA_FTST },
|
||||
/* D9 E5 */ { 0, BX_IA_FXAM },
|
||||
/* D9 E6 */ { 0, BX_IA_ERROR },
|
||||
/* D9 E7 */ { 0, BX_IA_ERROR },
|
||||
/* D9 E8 */ { 0, BX_IA_FLD1 },
|
||||
/* D9 E9 */ { 0, BX_IA_FLDL2T },
|
||||
/* D9 EA */ { 0, BX_IA_FLDL2E },
|
||||
/* D9 EB */ { 0, BX_IA_FLDPI },
|
||||
/* D9 EC */ { 0, BX_IA_FLDLG2 },
|
||||
/* D9 ED */ { 0, BX_IA_FLDLN2 },
|
||||
/* D9 EE */ { 0, BX_IA_FLDZ },
|
||||
/* D9 EF */ { 0, BX_IA_ERROR },
|
||||
/* D9 F0 */ { 0, BX_IA_F2XM1 },
|
||||
/* D9 F1 */ { 0, BX_IA_FYL2X },
|
||||
/* D9 F2 */ { 0, BX_IA_FPTAN },
|
||||
/* D9 F3 */ { 0, BX_IA_FPATAN },
|
||||
/* D9 F4 */ { 0, BX_IA_FXTRACT },
|
||||
/* D9 F5 */ { 0, BX_IA_FPREM1 },
|
||||
/* D9 F6 */ { 0, BX_IA_FDECSTP },
|
||||
/* D9 F7 */ { 0, BX_IA_FINCSTP },
|
||||
/* D9 F8 */ { 0, BX_IA_FPREM },
|
||||
/* D9 F9 */ { 0, BX_IA_FYL2XP1 },
|
||||
/* D9 FA */ { 0, BX_IA_FSQRT },
|
||||
/* D9 FB */ { 0, BX_IA_FSINCOS },
|
||||
/* D9 FC */ { 0, BX_IA_FRNDINT },
|
||||
/* D9 FD */ { 0, BX_IA_FSCALE },
|
||||
/* D9 FE */ { 0, BX_IA_FSIN },
|
||||
/* D9 FF */ { 0, BX_IA_FCOS }
|
||||
};
|
||||
|
||||
// DA (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDA[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FIADD_DWORD_INTEGER },
|
||||
/* 1 */ { 0, BX_IA_FIMUL_DWORD_INTEGER },
|
||||
/* 2 */ { 0, BX_IA_FICOM_DWORD_INTEGER },
|
||||
/* 3 */ { 0, BX_IA_FICOMP_DWORD_INTEGER },
|
||||
/* 4 */ { 0, BX_IA_FISUB_DWORD_INTEGER },
|
||||
/* 5 */ { 0, BX_IA_FISUBR_DWORD_INTEGER },
|
||||
/* 6 */ { 0, BX_IA_FIDIV_DWORD_INTEGER },
|
||||
/* 7 */ { 0, BX_IA_FIDIVR_DWORD_INTEGER },
|
||||
|
||||
/* /r form */
|
||||
/* DA C0 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C1 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C2 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C3 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C4 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C5 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C6 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C7 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C8 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA C9 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA CA */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA CB */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA CC */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA CD */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA CE */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA CF */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D0 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D1 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D2 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D3 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D4 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D5 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D6 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D7 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D8 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA D9 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA DA */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA DB */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA DC */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA DD */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA DE */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA DF */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DA E0 */ { 0, BX_IA_ERROR },
|
||||
/* DA E1 */ { 0, BX_IA_ERROR },
|
||||
/* DA E2 */ { 0, BX_IA_ERROR },
|
||||
/* DA E3 */ { 0, BX_IA_ERROR },
|
||||
/* DA E4 */ { 0, BX_IA_ERROR },
|
||||
/* DA E5 */ { 0, BX_IA_ERROR },
|
||||
/* DA E6 */ { 0, BX_IA_ERROR },
|
||||
/* DA E7 */ { 0, BX_IA_ERROR },
|
||||
/* DA E8 */ { 0, BX_IA_ERROR },
|
||||
/* DA E9 */ { 0, BX_IA_FUCOMPP },
|
||||
/* DA EA */ { 0, BX_IA_ERROR },
|
||||
/* DA EB */ { 0, BX_IA_ERROR },
|
||||
/* DA EC */ { 0, BX_IA_ERROR },
|
||||
/* DA ED */ { 0, BX_IA_ERROR },
|
||||
/* DA EE */ { 0, BX_IA_ERROR },
|
||||
/* DA EF */ { 0, BX_IA_ERROR },
|
||||
/* DA F0 */ { 0, BX_IA_ERROR },
|
||||
/* DA F1 */ { 0, BX_IA_ERROR },
|
||||
/* DA F2 */ { 0, BX_IA_ERROR },
|
||||
/* DA F3 */ { 0, BX_IA_ERROR },
|
||||
/* DA F4 */ { 0, BX_IA_ERROR },
|
||||
/* DA F5 */ { 0, BX_IA_ERROR },
|
||||
/* DA F6 */ { 0, BX_IA_ERROR },
|
||||
/* DA F7 */ { 0, BX_IA_ERROR },
|
||||
/* DA F8 */ { 0, BX_IA_ERROR },
|
||||
/* DA F9 */ { 0, BX_IA_ERROR },
|
||||
/* DA FA */ { 0, BX_IA_ERROR },
|
||||
/* DA FB */ { 0, BX_IA_ERROR },
|
||||
/* DA FC */ { 0, BX_IA_ERROR },
|
||||
/* DA FD */ { 0, BX_IA_ERROR },
|
||||
/* DA FE */ { 0, BX_IA_ERROR },
|
||||
/* DA FF */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
|
||||
// DB (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDB[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FILD_DWORD_INTEGER },
|
||||
/* 1 */ { 0, BX_IA_FISTTP32 },
|
||||
/* 2 */ { 0, BX_IA_FIST_DWORD_INTEGER },
|
||||
/* 3 */ { 0, BX_IA_FISTP_DWORD_INTEGER },
|
||||
/* 4 */ { 0, BX_IA_ERROR },
|
||||
/* 5 */ { 0, BX_IA_FLD_EXTENDED_REAL },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_FSTP_EXTENDED_REAL },
|
||||
|
||||
/* /r form */
|
||||
/* DB C0 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C1 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C2 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C3 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C4 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C5 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C6 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C7 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C8 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB C9 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB CA */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB CB */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB CC */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB CD */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB CE */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB CF */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D0 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D1 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D2 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D3 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D4 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D5 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D6 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D7 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D8 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB D9 */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB DA */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB DB */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB DC */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB DD */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB DE */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB DF */ { 0, BX_IA_FCMOV_ST0_STj },
|
||||
/* DB E0 */ { 0, BX_IA_FPLEGACY }, // feni (287 only)
|
||||
/* DB E1 */ { 0, BX_IA_FPLEGACY }, // fdisi (287 only)
|
||||
/* DB E2 */ { 0, BX_IA_FNCLEX },
|
||||
/* DB E3 */ { 0, BX_IA_FNINIT },
|
||||
/* DB E4 */ { 0, BX_IA_FPLEGACY }, // fsetpm (287 only)
|
||||
/* DB E5 */ { 0, BX_IA_ERROR },
|
||||
/* DB E6 */ { 0, BX_IA_ERROR },
|
||||
/* DB E7 */ { 0, BX_IA_ERROR },
|
||||
/* DB E8 */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB E9 */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB EA */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB EB */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB EC */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB ED */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB EE */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB EF */ { 0, BX_IA_FUCOMI_ST0_STj },
|
||||
/* DB F0 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F1 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F2 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F3 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F4 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F5 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F6 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F7 */ { 0, BX_IA_FCOMI_ST0_STj },
|
||||
/* DB F8 */ { 0, BX_IA_ERROR },
|
||||
/* DB F9 */ { 0, BX_IA_ERROR },
|
||||
/* DB FA */ { 0, BX_IA_ERROR },
|
||||
/* DB FB */ { 0, BX_IA_ERROR },
|
||||
/* DB FC */ { 0, BX_IA_ERROR },
|
||||
/* DB FD */ { 0, BX_IA_ERROR },
|
||||
/* DB FE */ { 0, BX_IA_ERROR },
|
||||
/* DB FF */ { 0, BX_IA_ERROR }
|
||||
};
|
||||
// DC (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FPGroupDC[8*2] = {
|
||||
/* /r form */
|
||||
/* 0 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* 1 */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* 2 */ { 0, BX_IA_FCOM_STi }, // undocumented
|
||||
/* 3 */ { 0, BX_IA_FCOMP_STi }, // undocumented
|
||||
/* 4 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* 5 */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* 6 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* 7 */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FADD_DOUBLE_REAL },
|
||||
/* 1 */ { 0, BX_IA_FMUL_DOUBLE_REAL },
|
||||
/* 2 */ { 0, BX_IA_FCOM_DOUBLE_REAL },
|
||||
/* 3 */ { 0, BX_IA_FCOMP_DOUBLE_REAL },
|
||||
/* 4 */ { 0, BX_IA_FSUB_DOUBLE_REAL },
|
||||
/* 5 */ { 0, BX_IA_FSUBR_DOUBLE_REAL },
|
||||
/* 6 */ { 0, BX_IA_FDIV_DOUBLE_REAL },
|
||||
/* 7 */ { 0, BX_IA_FDIVR_DOUBLE_REAL }
|
||||
};
|
||||
|
||||
// DD (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FPGroupDD[8*2] = {
|
||||
/* /r form */
|
||||
/* 0 */ { 0, BX_IA_FFREE_STi },
|
||||
/* 1 */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* 2 */ { 0, BX_IA_FST_STi },
|
||||
/* 3 */ { 0, BX_IA_FSTP_STi },
|
||||
/* 4 */ { 0, BX_IA_FUCOM_STi },
|
||||
/* 5 */ { 0, BX_IA_FUCOMP_STi },
|
||||
/* 6 */ { 0, BX_IA_ERROR },
|
||||
/* 7 */ { 0, BX_IA_ERROR },
|
||||
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FLD_DOUBLE_REAL },
|
||||
/* 1 */ { 0, BX_IA_FISTTP64 },
|
||||
/* 2 */ { 0, BX_IA_FST_DOUBLE_REAL },
|
||||
/* 3 */ { 0, BX_IA_FSTP_DOUBLE_REAL },
|
||||
/* 4 */ { 0, BX_IA_FRSTOR },
|
||||
/* 5 */ { 0, BX_IA_ERROR },
|
||||
/* 6 */ { 0, BX_IA_FNSAVE },
|
||||
/* 7 */ { 0, BX_IA_FNSTSW }
|
||||
};
|
||||
|
||||
// DE (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDE[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FIADD_WORD_INTEGER },
|
||||
/* 1 */ { 0, BX_IA_FIMUL_WORD_INTEGER },
|
||||
/* 2 */ { 0, BX_IA_FICOM_WORD_INTEGER },
|
||||
/* 3 */ { 0, BX_IA_FICOMP_WORD_INTEGER },
|
||||
/* 4 */ { 0, BX_IA_FISUB_WORD_INTEGER },
|
||||
/* 5 */ { 0, BX_IA_FISUBR_WORD_INTEGER },
|
||||
/* 6 */ { 0, BX_IA_FIDIV_WORD_INTEGER },
|
||||
/* 7 */ { 0, BX_IA_FIDIVR_WORD_INTEGER },
|
||||
|
||||
/* /r form */ // all instructions pop FPU stack
|
||||
/* DE C0 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C1 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C2 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C3 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C4 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C5 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C6 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C7 */ { 0, BX_IA_FADD_STi_ST0 },
|
||||
/* DE C8 */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE C9 */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE CA */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE CB */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE CC */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE CD */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE CE */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE CF */ { 0, BX_IA_FMUL_STi_ST0 },
|
||||
/* DE D0 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D1 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D2 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D3 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D4 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D5 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D6 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D7 */ { 0, BX_IA_FCOMP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DE D8 */ { 0, BX_IA_ERROR },
|
||||
/* DE D9 */ { 0, BX_IA_FCOMPP },
|
||||
/* DE DA */ { 0, BX_IA_ERROR },
|
||||
/* DE DB */ { 0, BX_IA_ERROR },
|
||||
/* DE DC */ { 0, BX_IA_ERROR },
|
||||
/* DE DD */ { 0, BX_IA_ERROR },
|
||||
/* DE DE */ { 0, BX_IA_ERROR },
|
||||
/* DE DF */ { 0, BX_IA_ERROR },
|
||||
/* DE E0 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E1 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E2 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E3 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E4 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E5 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E6 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E7 */ { 0, BX_IA_FSUBR_STi_ST0 },
|
||||
/* DE E8 */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE E9 */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE EA */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE EB */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE EC */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE ED */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE EE */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE EF */ { 0, BX_IA_FSUB_STi_ST0 },
|
||||
/* DE F0 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F1 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F2 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F3 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F4 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F5 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F6 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F7 */ { 0, BX_IA_FDIVR_STi_ST0 },
|
||||
/* DE F8 */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE F9 */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE FA */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE FB */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE FC */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE FD */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE FE */ { 0, BX_IA_FDIV_STi_ST0 },
|
||||
/* DE FF */ { 0, BX_IA_FDIV_STi_ST0 }
|
||||
};
|
||||
|
||||
// DF (modrm is outside 00h - BFh)
|
||||
static const BxOpcodeInfo_t BxOpcodeInfo_FloatingPointDF[64+8] = {
|
||||
/* /m form */
|
||||
/* 0 */ { 0, BX_IA_FILD_WORD_INTEGER },
|
||||
/* 1 */ { 0, BX_IA_FISTTP16 },
|
||||
/* 2 */ { 0, BX_IA_FIST_WORD_INTEGER },
|
||||
/* 3 */ { 0, BX_IA_FISTP_WORD_INTEGER },
|
||||
/* 4 */ { 0, BX_IA_FBLD_PACKED_BCD },
|
||||
/* 5 */ { 0, BX_IA_FILD_QWORD_INTEGER },
|
||||
/* 6 */ { 0, BX_IA_FBSTP_PACKED_BCD },
|
||||
/* 7 */ { 0, BX_IA_FISTP_QWORD_INTEGER },
|
||||
|
||||
/* /r form */
|
||||
/* DF C0 */ { 0, BX_IA_FFREEP_STi }, // 287+ compatibility opcode
|
||||
/* DF C1 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C2 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C3 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C4 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C5 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C6 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C7 */ { 0, BX_IA_FFREEP_STi },
|
||||
/* DF C8 */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF C9 */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF CA */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF CB */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF CC */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF CD */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF CE */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF CF */ { 0, BX_IA_FXCH_STi }, // undocumented
|
||||
/* DF D0 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D1 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D2 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D3 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D4 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D5 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D6 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D7 */ { 0, BX_IA_FSTP_STi }, // undocumented, special FPSTACK pop case
|
||||
/* DF D8 */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF D9 */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF DA */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF DB */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF DC */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF DD */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF DE */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF DF */ { 0, BX_IA_FSTP_STi }, // undocumented
|
||||
/* DF E0 */ { 0, BX_IA_FNSTSW_AX },
|
||||
/* DF E1 */ { 0, BX_IA_ERROR },
|
||||
/* DF E2 */ { 0, BX_IA_ERROR },
|
||||
/* DF E3 */ { 0, BX_IA_ERROR },
|
||||
/* DF E4 */ { 0, BX_IA_ERROR },
|
||||
/* DF E5 */ { 0, BX_IA_ERROR },
|
||||
/* DF E6 */ { 0, BX_IA_ERROR },
|
||||
/* DF E7 */ { 0, BX_IA_ERROR },
|
||||
/* DF E8 */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF E9 */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF EA */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF EB */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF EC */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF ED */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF EE */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF EF */ { 0, BX_IA_FUCOMIP_ST0_STj },
|
||||
/* DF F0 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F1 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F2 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F3 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F4 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F5 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F6 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F7 */ { 0, BX_IA_FCOMIP_ST0_STj },
|
||||
/* DF F8 */ { 0, BX_IA_ERROR },
|
||||
/* DF F9 */ { 0, BX_IA_ERROR },
|
||||
/* DF FA */ { 0, BX_IA_ERROR },
|
||||
/* DF FB */ { 0, BX_IA_ERROR },
|
||||
/* DF FC */ { 0, BX_IA_ERROR },
|
||||
/* DF FD */ { 0, BX_IA_ERROR },
|
||||
/* DF FE */ { 0, BX_IA_ERROR },
|
||||
/* DF FF */ { 0, BX_IA_ERROR },
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
/* ************************************************************************ */
|
||||
/* 3DNow! Opcodes */
|
||||
|
||||
#if BX_SUPPORT_3DNOW
|
||||
|
||||
static Bit16u Bx3DNowOpcode[256] = {
|
||||
// 256 entries for 3DNow opcodes, by suffix
|
||||
/* 00 */ BX_IA_ERROR,
|
||||
/* 01 */ BX_IA_ERROR,
|
||||
/* 02 */ BX_IA_ERROR,
|
||||
/* 03 */ BX_IA_ERROR,
|
||||
/* 04 */ BX_IA_ERROR,
|
||||
/* 05 */ BX_IA_ERROR,
|
||||
/* 06 */ BX_IA_ERROR,
|
||||
/* 07 */ BX_IA_ERROR,
|
||||
/* 08 */ BX_IA_ERROR,
|
||||
/* 09 */ BX_IA_ERROR,
|
||||
/* 0A */ BX_IA_ERROR,
|
||||
/* 0B */ BX_IA_ERROR,
|
||||
/* 0C */ BX_IA_PI2FW_PqQq,
|
||||
/* 0D */ BX_IA_PI2FD_PqQq,
|
||||
/* 0E */ BX_IA_ERROR,
|
||||
/* 0F */ BX_IA_ERROR,
|
||||
/* 10 */ BX_IA_ERROR,
|
||||
/* 11 */ BX_IA_ERROR,
|
||||
/* 12 */ BX_IA_ERROR,
|
||||
/* 13 */ BX_IA_ERROR,
|
||||
/* 14 */ BX_IA_ERROR,
|
||||
/* 15 */ BX_IA_ERROR,
|
||||
/* 16 */ BX_IA_ERROR,
|
||||
/* 17 */ BX_IA_ERROR,
|
||||
/* 18 */ BX_IA_ERROR,
|
||||
/* 19 */ BX_IA_ERROR,
|
||||
/* 1A */ BX_IA_ERROR,
|
||||
/* 1B */ BX_IA_ERROR,
|
||||
/* 1C */ BX_IA_PF2IW_PqQq,
|
||||
/* 1D */ BX_IA_PF2ID_PqQq,
|
||||
/* 1E */ BX_IA_ERROR,
|
||||
/* 1F */ BX_IA_ERROR,
|
||||
/* 20 */ BX_IA_ERROR,
|
||||
/* 21 */ BX_IA_ERROR,
|
||||
/* 22 */ BX_IA_ERROR,
|
||||
/* 23 */ BX_IA_ERROR,
|
||||
/* 24 */ BX_IA_ERROR,
|
||||
/* 25 */ BX_IA_ERROR,
|
||||
/* 26 */ BX_IA_ERROR,
|
||||
/* 27 */ BX_IA_ERROR,
|
||||
/* 28 */ BX_IA_ERROR,
|
||||
/* 29 */ BX_IA_ERROR,
|
||||
/* 2A */ BX_IA_ERROR,
|
||||
/* 2B */ BX_IA_ERROR,
|
||||
/* 2C */ BX_IA_ERROR,
|
||||
/* 2D */ BX_IA_ERROR,
|
||||
/* 2E */ BX_IA_ERROR,
|
||||
/* 2F */ BX_IA_ERROR,
|
||||
/* 30 */ BX_IA_ERROR,
|
||||
/* 31 */ BX_IA_ERROR,
|
||||
/* 32 */ BX_IA_ERROR,
|
||||
/* 33 */ BX_IA_ERROR,
|
||||
/* 34 */ BX_IA_ERROR,
|
||||
/* 35 */ BX_IA_ERROR,
|
||||
/* 36 */ BX_IA_ERROR,
|
||||
/* 37 */ BX_IA_ERROR,
|
||||
/* 38 */ BX_IA_ERROR,
|
||||
/* 39 */ BX_IA_ERROR,
|
||||
/* 3A */ BX_IA_ERROR,
|
||||
/* 3B */ BX_IA_ERROR,
|
||||
/* 3C */ BX_IA_ERROR,
|
||||
/* 3D */ BX_IA_ERROR,
|
||||
/* 3E */ BX_IA_ERROR,
|
||||
/* 3F */ BX_IA_ERROR,
|
||||
/* 40 */ BX_IA_ERROR,
|
||||
/* 41 */ BX_IA_ERROR,
|
||||
/* 42 */ BX_IA_ERROR,
|
||||
/* 43 */ BX_IA_ERROR,
|
||||
/* 44 */ BX_IA_ERROR,
|
||||
/* 45 */ BX_IA_ERROR,
|
||||
/* 46 */ BX_IA_ERROR,
|
||||
/* 47 */ BX_IA_ERROR,
|
||||
/* 48 */ BX_IA_ERROR,
|
||||
/* 49 */ BX_IA_ERROR,
|
||||
/* 4A */ BX_IA_ERROR,
|
||||
/* 4B */ BX_IA_ERROR,
|
||||
/* 4C */ BX_IA_ERROR,
|
||||
/* 4D */ BX_IA_ERROR,
|
||||
/* 4E */ BX_IA_ERROR,
|
||||
/* 4F */ BX_IA_ERROR,
|
||||
/* 50 */ BX_IA_ERROR,
|
||||
/* 51 */ BX_IA_ERROR,
|
||||
/* 52 */ BX_IA_ERROR,
|
||||
/* 53 */ BX_IA_ERROR,
|
||||
/* 54 */ BX_IA_ERROR,
|
||||
/* 55 */ BX_IA_ERROR,
|
||||
/* 56 */ BX_IA_ERROR,
|
||||
/* 57 */ BX_IA_ERROR,
|
||||
/* 58 */ BX_IA_ERROR,
|
||||
/* 59 */ BX_IA_ERROR,
|
||||
/* 5A */ BX_IA_ERROR,
|
||||
/* 5B */ BX_IA_ERROR,
|
||||
/* 5C */ BX_IA_ERROR,
|
||||
/* 5D */ BX_IA_ERROR,
|
||||
/* 5E */ BX_IA_ERROR,
|
||||
/* 5F */ BX_IA_ERROR,
|
||||
/* 60 */ BX_IA_ERROR,
|
||||
/* 61 */ BX_IA_ERROR,
|
||||
/* 62 */ BX_IA_ERROR,
|
||||
/* 63 */ BX_IA_ERROR,
|
||||
/* 64 */ BX_IA_ERROR,
|
||||
/* 65 */ BX_IA_ERROR,
|
||||
/* 66 */ BX_IA_ERROR,
|
||||
/* 67 */ BX_IA_ERROR,
|
||||
/* 68 */ BX_IA_ERROR,
|
||||
/* 69 */ BX_IA_ERROR,
|
||||
/* 6A */ BX_IA_ERROR,
|
||||
/* 6B */ BX_IA_ERROR,
|
||||
/* 6C */ BX_IA_ERROR,
|
||||
/* 6D */ BX_IA_ERROR,
|
||||
/* 6E */ BX_IA_ERROR,
|
||||
/* 6F */ BX_IA_ERROR,
|
||||
/* 70 */ BX_IA_ERROR,
|
||||
/* 71 */ BX_IA_ERROR,
|
||||
/* 72 */ BX_IA_ERROR,
|
||||
/* 73 */ BX_IA_ERROR,
|
||||
/* 74 */ BX_IA_ERROR,
|
||||
/* 75 */ BX_IA_ERROR,
|
||||
/* 76 */ BX_IA_ERROR,
|
||||
/* 77 */ BX_IA_ERROR,
|
||||
/* 78 */ BX_IA_ERROR,
|
||||
/* 79 */ BX_IA_ERROR,
|
||||
/* 7A */ BX_IA_ERROR,
|
||||
/* 7B */ BX_IA_ERROR,
|
||||
/* 7C */ BX_IA_ERROR,
|
||||
/* 7D */ BX_IA_ERROR,
|
||||
/* 7E */ BX_IA_ERROR,
|
||||
/* 7F */ BX_IA_ERROR,
|
||||
/* 80 */ BX_IA_ERROR,
|
||||
/* 81 */ BX_IA_ERROR,
|
||||
/* 82 */ BX_IA_ERROR,
|
||||
/* 83 */ BX_IA_ERROR,
|
||||
/* 84 */ BX_IA_ERROR,
|
||||
/* 85 */ BX_IA_ERROR,
|
||||
/* 86 */ BX_IA_ERROR,
|
||||
/* 87 */ BX_IA_ERROR,
|
||||
/* 88 */ BX_IA_ERROR,
|
||||
/* 89 */ BX_IA_ERROR,
|
||||
/* 8A */ BX_IA_PFNACC_PqQq,
|
||||
/* 8B */ BX_IA_ERROR,
|
||||
/* 8C */ BX_IA_ERROR,
|
||||
/* 8D */ BX_IA_ERROR,
|
||||
/* 8E */ BX_IA_PFPNACC_PqQq,
|
||||
/* 8F */ BX_IA_ERROR,
|
||||
/* 90 */ BX_IA_PFCMPGE_PqQq,
|
||||
/* 91 */ BX_IA_ERROR,
|
||||
/* 92 */ BX_IA_ERROR,
|
||||
/* 93 */ BX_IA_ERROR,
|
||||
/* 94 */ BX_IA_PFMIN_PqQq,
|
||||
/* 95 */ BX_IA_ERROR,
|
||||
/* 96 */ BX_IA_PFRCP_PqQq,
|
||||
/* 97 */ BX_IA_PFRSQRT_PqQq,
|
||||
/* 98 */ BX_IA_ERROR,
|
||||
/* 99 */ BX_IA_ERROR,
|
||||
/* 9A */ BX_IA_PFSUB_PqQq,
|
||||
/* 9B */ BX_IA_ERROR,
|
||||
/* 9C */ BX_IA_ERROR,
|
||||
/* 9D */ BX_IA_ERROR,
|
||||
/* 9E */ BX_IA_PFADD_PqQq,
|
||||
/* 9F */ BX_IA_ERROR,
|
||||
/* A0 */ BX_IA_PFCMPGT_PqQq,
|
||||
/* A1 */ BX_IA_ERROR,
|
||||
/* A2 */ BX_IA_ERROR,
|
||||
/* A3 */ BX_IA_ERROR,
|
||||
/* A4 */ BX_IA_PFMAX_PqQq,
|
||||
/* A5 */ BX_IA_ERROR,
|
||||
/* A6 */ BX_IA_PFRCPIT1_PqQq,
|
||||
/* A7 */ BX_IA_PFRSQIT1_PqQq,
|
||||
/* A8 */ BX_IA_ERROR,
|
||||
/* A9 */ BX_IA_ERROR,
|
||||
/* AA */ BX_IA_PFSUBR_PqQq,
|
||||
/* AB */ BX_IA_ERROR,
|
||||
/* AC */ BX_IA_ERROR,
|
||||
/* AD */ BX_IA_ERROR,
|
||||
/* AE */ BX_IA_PFACC_PqQq,
|
||||
/* AF */ BX_IA_ERROR,
|
||||
/* B0 */ BX_IA_PFCMPEQ_PqQq,
|
||||
/* B1 */ BX_IA_ERROR,
|
||||
/* B2 */ BX_IA_ERROR,
|
||||
/* B3 */ BX_IA_ERROR,
|
||||
/* B4 */ BX_IA_PFMUL_PqQq,
|
||||
/* B5 */ BX_IA_ERROR,
|
||||
/* B6 */ BX_IA_PFRCPIT2_PqQq,
|
||||
/* B7 */ BX_IA_PMULHRW_PqQq,
|
||||
/* B8 */ BX_IA_ERROR,
|
||||
/* B9 */ BX_IA_ERROR,
|
||||
/* BA */ BX_IA_ERROR,
|
||||
/* BB */ BX_IA_PSWAPD_PqQq,
|
||||
/* BC */ BX_IA_ERROR,
|
||||
/* BD */ BX_IA_ERROR,
|
||||
/* BE */ BX_IA_ERROR,
|
||||
/* BF */ BX_IA_PAVGB_PqQq,
|
||||
/* C0 */ BX_IA_ERROR,
|
||||
/* C1 */ BX_IA_ERROR,
|
||||
/* C2 */ BX_IA_ERROR,
|
||||
/* C3 */ BX_IA_ERROR,
|
||||
/* C4 */ BX_IA_ERROR,
|
||||
/* C5 */ BX_IA_ERROR,
|
||||
/* C6 */ BX_IA_ERROR,
|
||||
/* C7 */ BX_IA_ERROR,
|
||||
/* C8 */ BX_IA_ERROR,
|
||||
/* C9 */ BX_IA_ERROR,
|
||||
/* CA */ BX_IA_ERROR,
|
||||
/* CB */ BX_IA_ERROR,
|
||||
/* CC */ BX_IA_ERROR,
|
||||
/* CD */ BX_IA_ERROR,
|
||||
/* CE */ BX_IA_ERROR,
|
||||
/* CF */ BX_IA_ERROR,
|
||||
/* D0 */ BX_IA_ERROR,
|
||||
/* D1 */ BX_IA_ERROR,
|
||||
/* D2 */ BX_IA_ERROR,
|
||||
/* D3 */ BX_IA_ERROR,
|
||||
/* D4 */ BX_IA_ERROR,
|
||||
/* D5 */ BX_IA_ERROR,
|
||||
/* D6 */ BX_IA_ERROR,
|
||||
/* D7 */ BX_IA_ERROR,
|
||||
/* D8 */ BX_IA_ERROR,
|
||||
/* D9 */ BX_IA_ERROR,
|
||||
/* DA */ BX_IA_ERROR,
|
||||
/* DB */ BX_IA_ERROR,
|
||||
/* DC */ BX_IA_ERROR,
|
||||
/* DD */ BX_IA_ERROR,
|
||||
/* DE */ BX_IA_ERROR,
|
||||
/* DF */ BX_IA_ERROR,
|
||||
/* E0 */ BX_IA_ERROR,
|
||||
/* E1 */ BX_IA_ERROR,
|
||||
/* E2 */ BX_IA_ERROR,
|
||||
/* E3 */ BX_IA_ERROR,
|
||||
/* E4 */ BX_IA_ERROR,
|
||||
/* E5 */ BX_IA_ERROR,
|
||||
/* E6 */ BX_IA_ERROR,
|
||||
/* E7 */ BX_IA_ERROR,
|
||||
/* E8 */ BX_IA_ERROR,
|
||||
/* E9 */ BX_IA_ERROR,
|
||||
/* EA */ BX_IA_ERROR,
|
||||
/* EB */ BX_IA_ERROR,
|
||||
/* EC */ BX_IA_ERROR,
|
||||
/* ED */ BX_IA_ERROR,
|
||||
/* EE */ BX_IA_ERROR,
|
||||
/* EF */ BX_IA_ERROR,
|
||||
/* F0 */ BX_IA_ERROR,
|
||||
/* F1 */ BX_IA_ERROR,
|
||||
/* F2 */ BX_IA_ERROR,
|
||||
/* F3 */ BX_IA_ERROR,
|
||||
/* F4 */ BX_IA_ERROR,
|
||||
/* F5 */ BX_IA_ERROR,
|
||||
/* F6 */ BX_IA_ERROR,
|
||||
/* F7 */ BX_IA_ERROR,
|
||||
/* F8 */ BX_IA_ERROR,
|
||||
/* F9 */ BX_IA_ERROR,
|
||||
/* FA */ BX_IA_ERROR,
|
||||
/* FB */ BX_IA_ERROR,
|
||||
/* FC */ BX_IA_ERROR,
|
||||
/* FD */ BX_IA_ERROR,
|
||||
/* FE */ BX_IA_ERROR,
|
||||
/* FF */ BX_IA_ERROR
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BX_X87_FETCHDECODE_TABLES_H
|
||||
331
simulators/bochs/cpu/flag_ctrl.cc
Normal file
331
simulators/bochs/cpu/flag_ctrl.cc
Normal file
@ -0,0 +1,331 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2002-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RSP ESP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAHF(bxInstruction_c *i)
|
||||
{
|
||||
set_SF((AH & 0x80) >> 7);
|
||||
set_ZF((AH & 0x40) >> 6);
|
||||
set_AF((AH & 0x10) >> 4);
|
||||
set_CF (AH & 0x01);
|
||||
set_PF((AH & 0x04) >> 2);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LAHF(bxInstruction_c *i)
|
||||
{
|
||||
AH = read_eflags() & 0xFF;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLC(bxInstruction_c *i)
|
||||
{
|
||||
clear_CF();
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STC(bxInstruction_c *i)
|
||||
{
|
||||
assert_CF();
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLI(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u IOPL = BX_CPU_THIS_PTR get_IOPL();
|
||||
|
||||
if (protected_mode())
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_PVI() && (CPL == 3))
|
||||
{
|
||||
if (IOPL < 3) {
|
||||
BX_CPU_THIS_PTR clear_VIF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (IOPL < CPL) {
|
||||
BX_DEBUG(("CLI: IOPL < CPL in protected mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (v8086_mode())
|
||||
{
|
||||
if (IOPL != 3) {
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_VME()) {
|
||||
BX_CPU_THIS_PTR clear_VIF();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("CLI: IOPL != 3 in v8086 mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR clear_IF();
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STI(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u IOPL = BX_CPU_THIS_PTR get_IOPL();
|
||||
|
||||
if (protected_mode())
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_PVI())
|
||||
{
|
||||
if (CPL == 3 && IOPL < 3) {
|
||||
if (! BX_CPU_THIS_PTR get_VIP())
|
||||
{
|
||||
BX_CPU_THIS_PTR assert_VIF();
|
||||
return;
|
||||
}
|
||||
|
||||
BX_DEBUG(("STI: #GP(0) in VME mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (CPL > IOPL) {
|
||||
BX_DEBUG(("STI: CPL > IOPL in protected mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
else if (v8086_mode())
|
||||
{
|
||||
if (IOPL != 3) {
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_VME() && BX_CPU_THIS_PTR get_VIP() == 0)
|
||||
{
|
||||
BX_CPU_THIS_PTR assert_VIF();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("STI: IOPL != 3 in v8086 mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!BX_CPU_THIS_PTR get_IF()) {
|
||||
BX_CPU_THIS_PTR assert_IF();
|
||||
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CLD(bxInstruction_c *i)
|
||||
{
|
||||
BX_CPU_THIS_PTR clear_DF();
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STD(bxInstruction_c *i)
|
||||
{
|
||||
BX_CPU_THIS_PTR assert_DF();
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::CMC(bxInstruction_c *i)
|
||||
{
|
||||
set_CF(! get_CF());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHF_Fw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u flags = (Bit16u) read_eflags();
|
||||
|
||||
if (v8086_mode()) {
|
||||
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_VME()) {
|
||||
flags |= EFlagsIOPLMask;
|
||||
if (BX_CPU_THIS_PTR get_VIF())
|
||||
flags |= EFlagsIFMask;
|
||||
else
|
||||
flags &= ~EFlagsIFMask;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
BX_DEBUG(("PUSHFW: #GP(0) in v8086 (no VME) mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
push_16(flags);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPF_Fw(bxInstruction_c *i)
|
||||
{
|
||||
// Build a mask of the following bits:
|
||||
// x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask | EFlagsNTMask;
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u flags16 = pop_16();
|
||||
|
||||
if (protected_mode()) {
|
||||
if (CPL==0)
|
||||
changeMask |= EFlagsIOPLMask;
|
||||
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
}
|
||||
else if (v8086_mode()) {
|
||||
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_VME()) {
|
||||
|
||||
if (((flags16 & EFlagsIFMask) && BX_CPU_THIS_PTR get_VIP()) ||
|
||||
(flags16 & EFlagsTFMask))
|
||||
{
|
||||
BX_ERROR(("POPFW: #GP(0) in VME mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// IF, IOPL unchanged, EFLAGS.VIF = TMP_FLAGS.IF
|
||||
changeMask |= EFlagsVIFMask;
|
||||
Bit32u flags32 = (Bit32u) flags16;
|
||||
if (flags32 & EFlagsIFMask) flags32 |= EFlagsVIFMask;
|
||||
writeEFlags(flags32, changeMask);
|
||||
RSP_COMMIT;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
BX_DEBUG(("POPFW: #GP(0) in v8086 (no VME) mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
changeMask |= EFlagsIFMask;
|
||||
}
|
||||
else {
|
||||
// All non-reserved flags can be modified
|
||||
changeMask |= (EFlagsIOPLMask | EFlagsIFMask);
|
||||
}
|
||||
|
||||
writeEFlags((Bit32u) flags16, changeMask);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHF_Fd(bxInstruction_c *i)
|
||||
{
|
||||
if (v8086_mode() && (BX_CPU_THIS_PTR get_IOPL()<3)) {
|
||||
BX_DEBUG(("PUSHFD: #GP(0) in v8086 mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// VM & RF flags cleared in image stored on the stack
|
||||
push_32(read_eflags() & 0x00fcffff);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPF_Fd(bxInstruction_c *i)
|
||||
{
|
||||
// Build a mask of the following bits:
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
|
||||
EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
changeMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit32u flags32 = pop_32();
|
||||
|
||||
if (protected_mode()) {
|
||||
// IOPL changed only if (CPL == 0),
|
||||
// IF changed only if (CPL <= EFLAGS.IOPL),
|
||||
// VIF, VIP, VM are unaffected
|
||||
if (CPL==0)
|
||||
changeMask |= EFlagsIOPLMask;
|
||||
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
}
|
||||
else if (v8086_mode()) {
|
||||
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
|
||||
BX_ERROR(("POPFD: #GP(0) in v8086 mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
// v8086-mode: VM, IOPL, VIP, VIF are unaffected
|
||||
changeMask |= EFlagsIFMask;
|
||||
}
|
||||
else { // Real-mode
|
||||
// VIF, VIP, VM are unaffected
|
||||
changeMask |= (EFlagsIOPLMask | EFlagsIFMask);
|
||||
}
|
||||
|
||||
writeEFlags(flags32, changeMask);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHF_Fq(bxInstruction_c *i)
|
||||
{
|
||||
// VM & RF flags cleared in image stored on the stack
|
||||
push_64(read_eflags() & 0x00fcffff);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPF_Fq(bxInstruction_c *i)
|
||||
{
|
||||
// Build a mask of the following bits:
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask
|
||||
| EFlagsNTMask | EFlagsRFMask | EFlagsACMask
|
||||
| EFlagsIDMask;
|
||||
|
||||
BX_ASSERT (protected_mode());
|
||||
|
||||
Bit32u eflags32 = (Bit32u) pop_64();
|
||||
|
||||
if (CPL==0)
|
||||
changeMask |= EFlagsIOPLMask;
|
||||
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
|
||||
// VIF, VIP, VM are unaffected
|
||||
writeEFlags(eflags32, changeMask);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BX_CPU_LEVEL >= 3
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SALC(bxInstruction_c *i)
|
||||
{
|
||||
if (get_CF()) {
|
||||
AL = 0xff;
|
||||
}
|
||||
else {
|
||||
AL = 0x00;
|
||||
}
|
||||
}
|
||||
114
simulators/bochs/cpu/flag_ctrl_pro.cc
Normal file
114
simulators/bochs/cpu/flag_ctrl_pro.cc
Normal file
@ -0,0 +1,114 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::setEFlags(Bit32u val)
|
||||
{
|
||||
// VM flag could not be set from long mode
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
if (BX_CPU_THIS_PTR get_VM()) BX_PANIC(("VM is set in long mode !"));
|
||||
val &= ~EFlagsVMMask;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (val & (EFlagsTFMask|EFlagsRFMask)) {
|
||||
BX_CPU_THIS_PTR async_event = 1; // TF == 1 || RF == 1
|
||||
}
|
||||
|
||||
if (val & EFlagsIFMask) {
|
||||
if (! BX_CPU_THIS_PTR get_IF())
|
||||
BX_CPU_THIS_PTR async_event = 1; // IF bit was set
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR eflags = val;
|
||||
BX_CPU_THIS_PTR lf_flags_status = 0; // OSZAPC flags are known.
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck(/* EFLAGS.AC reloaded */);
|
||||
#endif
|
||||
|
||||
handleCpuModeChange(); // VM flag might be changed
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::writeEFlags(Bit32u flags, Bit32u changeMask)
|
||||
{
|
||||
// Build a mask of the non-reserved bits:
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u supportMask = 0x00037fd5;
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
supportMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
|
||||
#endif
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
supportMask |= (EFlagsVIPMask | EFlagsVIFMask); // VIP/VIF
|
||||
#endif
|
||||
|
||||
// Screen out changing of any unsupported bits.
|
||||
changeMask &= supportMask;
|
||||
|
||||
Bit32u newEFlags = (BX_CPU_THIS_PTR eflags & ~changeMask) |
|
||||
(flags & changeMask);
|
||||
setEFlags(newEFlags);
|
||||
// OSZAPC flags are known - done in setEFlags(newEFlags)
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::write_flags(Bit16u flags, bx_bool change_IOPL, bx_bool change_IF)
|
||||
{
|
||||
// Build a mask of the following bits:
|
||||
// x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = 0x0dd5;
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
changeMask |= EFlagsNTMask; // NT is modified as requested.
|
||||
if (change_IOPL)
|
||||
changeMask |= EFlagsIOPLMask; // IOPL is modified as requested.
|
||||
#endif
|
||||
if (change_IF)
|
||||
changeMask |= EFlagsIFMask;
|
||||
|
||||
writeEFlags(Bit32u(flags), changeMask);
|
||||
}
|
||||
|
||||
// Cause arithmetic flags to be in known state and cached in val32.
|
||||
Bit32u BX_CPU_C::force_flags(void)
|
||||
{
|
||||
if (BX_CPU_THIS_PTR lf_flags_status) {
|
||||
Bit32u newflags;
|
||||
|
||||
newflags = get_CF() ? EFlagsCFMask : 0;
|
||||
newflags |= get_PF() ? EFlagsPFMask : 0;
|
||||
newflags |= get_AF() ? EFlagsAFMask : 0;
|
||||
newflags |= get_ZF() ? EFlagsZFMask : 0;
|
||||
newflags |= get_SF() ? EFlagsSFMask : 0;
|
||||
newflags |= get_OF() ? EFlagsOFMask : 0;
|
||||
|
||||
setEFlagsOSZAPC(newflags);
|
||||
}
|
||||
|
||||
return BX_CPU_THIS_PTR eflags;
|
||||
}
|
||||
46
simulators/bochs/cpu/fpu_emu.cc
Normal file
46
simulators/bochs/cpu/fpu_emu.cc
Normal file
@ -0,0 +1,46 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2004-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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
/* 9B */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FWAIT(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_SUPPORT_FPU
|
||||
if (BX_CPU_THIS_PTR cr0.get_TS() && BX_CPU_THIS_PTR cr0.get_MP())
|
||||
exception(BX_NM_EXCEPTION, 0);
|
||||
|
||||
BX_CPU_THIS_PTR FPU_check_pending_exceptions();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* relevant only when FPU support is disabled */
|
||||
#if BX_SUPPORT_FPU == 0
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FPU_ESC(bxInstruction_c *i)
|
||||
{
|
||||
if (BX_CPU_THIS_PTR cr0.get_EM() || BX_CPU_THIS_PTR cr0.get_TS())
|
||||
exception(BX_NM_EXCEPTION, 0);
|
||||
}
|
||||
#endif
|
||||
263
simulators/bochs/cpu/i387.h
Normal file
263
simulators/bochs/cpu/i387.h
Normal file
@ -0,0 +1,263 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2004-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _BX_I387_RELATED_EXTENSIONS_H_
|
||||
#define _BX_I387_RELATED_EXTENSIONS_H_
|
||||
|
||||
#if BX_SUPPORT_FPU
|
||||
|
||||
#include "fpu/softfloat.h"
|
||||
|
||||
#define BX_FPU_REG(index) \
|
||||
(BX_CPU_THIS_PTR the_i387.st_space[index & 0x7])
|
||||
|
||||
#if defined(NEED_CPU_REG_SHORTCUTS)
|
||||
#define FPU_PARTIAL_STATUS (BX_CPU_THIS_PTR the_i387.swd)
|
||||
#define FPU_CONTROL_WORD (BX_CPU_THIS_PTR the_i387.cwd)
|
||||
#define FPU_TAG_WORD (BX_CPU_THIS_PTR the_i387.twd)
|
||||
#define FPU_TOS (BX_CPU_THIS_PTR the_i387.tos)
|
||||
#endif
|
||||
|
||||
#include "fpu/tag_w.h"
|
||||
#include "fpu/status_w.h"
|
||||
#include "fpu/control_w.h"
|
||||
|
||||
extern int FPU_tagof(const floatx80 ®);
|
||||
|
||||
//
|
||||
// Minimal i387 structure
|
||||
//
|
||||
struct BOCHSAPI_MSVCONLY i387_t
|
||||
{
|
||||
i387_t() {}
|
||||
|
||||
public:
|
||||
void init(); // used by FINIT/FNINIT instructions
|
||||
void reset(); // called on CPU reset
|
||||
|
||||
int is_IA_masked() const { return (cwd & FPU_CW_Invalid); }
|
||||
|
||||
Bit16u get_control_word() const { return cwd; }
|
||||
Bit16u get_tag_word() const { return twd; }
|
||||
Bit16u get_status_word() const { return (swd & ~FPU_SW_Top & 0xFFFF) | ((tos << 11) & FPU_SW_Top); }
|
||||
Bit16u get_partial_status() const { return swd; }
|
||||
|
||||
void FPU_pop ();
|
||||
void FPU_push();
|
||||
|
||||
void FPU_settagi(int tag, int stnr);
|
||||
void FPU_settagi_valid(int stnr);
|
||||
int FPU_gettagi(int stnr);
|
||||
|
||||
floatx80 FPU_read_regi(int stnr) { return st_space[(tos+stnr) & 7]; }
|
||||
void FPU_save_regi(floatx80 reg, int stnr);
|
||||
void FPU_save_regi(floatx80 reg, int tag, int stnr);
|
||||
|
||||
public:
|
||||
Bit16u cwd; // control word
|
||||
Bit16u swd; // status word
|
||||
Bit16u twd; // tag word
|
||||
Bit16u foo; // last instruction opcode
|
||||
|
||||
bx_address fip;
|
||||
bx_address fdp;
|
||||
Bit16u fcs;
|
||||
Bit16u fds;
|
||||
|
||||
floatx80 st_space[8];
|
||||
|
||||
unsigned char tos;
|
||||
unsigned char align1;
|
||||
unsigned char align2;
|
||||
unsigned char align3;
|
||||
};
|
||||
|
||||
#define IS_TAG_EMPTY(i) \
|
||||
((BX_CPU_THIS_PTR the_i387.FPU_gettagi(i)) == FPU_Tag_Empty)
|
||||
|
||||
#define BX_READ_FPU_REG(i) \
|
||||
(BX_CPU_THIS_PTR the_i387.FPU_read_regi(i))
|
||||
|
||||
#define BX_WRITE_FPU_REG(value, i) \
|
||||
BX_CPU_THIS_PTR the_i387.FPU_save_regi((value), (i));
|
||||
|
||||
#define BX_WRITE_FPU_REGISTER_AND_TAG(value, tag, i) \
|
||||
BX_CPU_THIS_PTR the_i387.FPU_save_regi((value), (tag), (i));
|
||||
|
||||
BX_CPP_INLINE int i387_t::FPU_gettagi(int stnr)
|
||||
{
|
||||
return (twd >> (((stnr+tos) & 7)*2)) & 3;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void i387_t::FPU_settagi_valid(int stnr)
|
||||
{
|
||||
int regnr = (stnr + tos) & 7;
|
||||
twd &= ~(3 << (regnr*2)); // FPU_Tag_Valid == '00
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void i387_t::FPU_settagi(int tag, int stnr)
|
||||
{
|
||||
int regnr = (stnr + tos) & 7;
|
||||
twd &= ~(3 << (regnr*2));
|
||||
twd |= (tag & 3) << (regnr*2);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void i387_t::FPU_push(void)
|
||||
{
|
||||
tos = (tos - 1) & 7;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void i387_t::FPU_pop(void)
|
||||
{
|
||||
twd |= 3 << (tos*2);
|
||||
tos = (tos + 1) & 7;
|
||||
}
|
||||
|
||||
// it is only possisble to read FPU tag word through certain
|
||||
// instructions like FNSAVE, and they update tag word to its
|
||||
// real value anyway
|
||||
BX_CPP_INLINE void i387_t::FPU_save_regi(floatx80 reg, int stnr)
|
||||
{
|
||||
st_space[(stnr+tos) & 7] = reg;
|
||||
FPU_settagi_valid(stnr);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void i387_t::FPU_save_regi(floatx80 reg, int tag, int stnr)
|
||||
{
|
||||
st_space[(stnr+tos) & 7] = reg;
|
||||
FPU_settagi(tag, stnr);
|
||||
}
|
||||
|
||||
#include <string.h>
|
||||
|
||||
BX_CPP_INLINE void i387_t::init()
|
||||
{
|
||||
cwd = 0x037F;
|
||||
swd = 0;
|
||||
tos = 0;
|
||||
twd = 0xFFFF;
|
||||
foo = 0;
|
||||
fip = 0;
|
||||
fcs = 0;
|
||||
fds = 0;
|
||||
fdp = 0;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void i387_t::reset()
|
||||
{
|
||||
cwd = 0x0040;
|
||||
swd = 0;
|
||||
tos = 0;
|
||||
twd = 0x5555;
|
||||
foo = 0;
|
||||
fip = 0;
|
||||
fcs = 0;
|
||||
fds = 0;
|
||||
fdp = 0;
|
||||
|
||||
memset(st_space, 0, sizeof(floatx80)*8);
|
||||
}
|
||||
|
||||
typedef union bx_packed_mmx_reg_t {
|
||||
Bit8s mmx_sbyte[8];
|
||||
Bit16s mmx_s16[4];
|
||||
Bit32s mmx_s32[2];
|
||||
Bit64s mmx_s64;
|
||||
Bit8u mmx_ubyte[8];
|
||||
Bit16u mmx_u16[4];
|
||||
Bit32u mmx_u32[2];
|
||||
Bit64u mmx_u64;
|
||||
} BxPackedMmxRegister;
|
||||
|
||||
#ifdef BX_BIG_ENDIAN
|
||||
#define mmx64s(i) mmx_s64
|
||||
#define mmx32s(i) mmx_s32[1 - (i)]
|
||||
#define mmx16s(i) mmx_s16[3 - (i)]
|
||||
#define mmxsbyte(i) mmx_sbyte[7 - (i)]
|
||||
#define mmxubyte(i) mmx_ubyte[7 - (i)]
|
||||
#define mmx16u(i) mmx_u16[3 - (i)]
|
||||
#define mmx32u(i) mmx_u32[1 - (i)]
|
||||
#define mmx64u mmx_u64
|
||||
#else
|
||||
#define mmx64s(i) mmx_s64
|
||||
#define mmx32s(i) mmx_s32[(i)]
|
||||
#define mmx16s(i) mmx_s16[(i)]
|
||||
#define mmxsbyte(i) mmx_sbyte[(i)]
|
||||
#define mmxubyte(i) mmx_ubyte[(i)]
|
||||
#define mmx16u(i) mmx_u16[(i)]
|
||||
#define mmx32u(i) mmx_u32[(i)]
|
||||
#define mmx64u mmx_u64
|
||||
#endif
|
||||
|
||||
/* for compatability with already written code */
|
||||
#define MMXSB0(reg) (reg.mmxsbyte(0))
|
||||
#define MMXSB1(reg) (reg.mmxsbyte(1))
|
||||
#define MMXSB2(reg) (reg.mmxsbyte(2))
|
||||
#define MMXSB3(reg) (reg.mmxsbyte(3))
|
||||
#define MMXSB4(reg) (reg.mmxsbyte(4))
|
||||
#define MMXSB5(reg) (reg.mmxsbyte(5))
|
||||
#define MMXSB6(reg) (reg.mmxsbyte(6))
|
||||
#define MMXSB7(reg) (reg.mmxsbyte(7))
|
||||
|
||||
#define MMXSW0(reg) (reg.mmx16s(0))
|
||||
#define MMXSW1(reg) (reg.mmx16s(1))
|
||||
#define MMXSW2(reg) (reg.mmx16s(2))
|
||||
#define MMXSW3(reg) (reg.mmx16s(3))
|
||||
|
||||
#define MMXSD0(reg) (reg.mmx32s(0))
|
||||
#define MMXSD1(reg) (reg.mmx32s(1))
|
||||
|
||||
#define MMXSQ(reg) (reg.mmx64s)
|
||||
#define MMXUQ(reg) (reg.mmx64u)
|
||||
|
||||
#define MMXUD0(reg) (reg.mmx32u(0))
|
||||
#define MMXUD1(reg) (reg.mmx32u(1))
|
||||
|
||||
#define MMXUW0(reg) (reg.mmx16u(0))
|
||||
#define MMXUW1(reg) (reg.mmx16u(1))
|
||||
#define MMXUW2(reg) (reg.mmx16u(2))
|
||||
#define MMXUW3(reg) (reg.mmx16u(3))
|
||||
|
||||
#define MMXUB0(reg) (reg.mmxubyte(0))
|
||||
#define MMXUB1(reg) (reg.mmxubyte(1))
|
||||
#define MMXUB2(reg) (reg.mmxubyte(2))
|
||||
#define MMXUB3(reg) (reg.mmxubyte(3))
|
||||
#define MMXUB4(reg) (reg.mmxubyte(4))
|
||||
#define MMXUB5(reg) (reg.mmxubyte(5))
|
||||
#define MMXUB6(reg) (reg.mmxubyte(6))
|
||||
#define MMXUB7(reg) (reg.mmxubyte(7))
|
||||
|
||||
#define BX_MMX_REG(index) (BX_FPU_REG(index).fraction)
|
||||
|
||||
#define BX_READ_MMX_REG(index) \
|
||||
(*((const BxPackedMmxRegister*)(&(BX_MMX_REG(index)))))
|
||||
|
||||
#define BX_WRITE_MMX_REG(index, value) \
|
||||
{ \
|
||||
(BX_FPU_REG(index)).fraction = MMXUQ(value); \
|
||||
(BX_FPU_REG(index)).exp = 0xffff; \
|
||||
}
|
||||
|
||||
#endif /* BX_SUPPORT_FPU */
|
||||
|
||||
#endif
|
||||
1352
simulators/bochs/cpu/ia_opcodes.h
Normal file
1352
simulators/bochs/cpu/ia_opcodes.h
Normal file
File diff suppressed because it is too large
Load Diff
269
simulators/bochs/cpu/icache.cc
Executable file
269
simulators/bochs/cpu/icache.cc
Executable file
@ -0,0 +1,269 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2011 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
bxPageWriteStampTable pageWriteStampTable;
|
||||
|
||||
void flushICaches(void)
|
||||
{
|
||||
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
|
||||
BX_CPU(i)->iCache.flushICacheEntries();
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
BX_CPU(i)->async_event |= BX_ASYNC_EVENT_STOP_TRACE;
|
||||
#endif
|
||||
}
|
||||
|
||||
pageWriteStampTable.resetWriteStamps();
|
||||
}
|
||||
|
||||
void handleSMC(bx_phy_address pAddr, Bit32u mask)
|
||||
{
|
||||
for (unsigned i=0; i<BX_SMP_PROCESSORS; i++) {
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
BX_CPU(i)->async_event |= BX_ASYNC_EVENT_STOP_TRACE;
|
||||
#endif
|
||||
BX_CPU(i)->iCache.handleSMC(pAddr, mask);
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
|
||||
void BX_CPU_C::serveICacheMiss(bxICacheEntry_c *entry, Bit32u eipBiased, bx_phy_address pAddr)
|
||||
{
|
||||
BX_CPU_THIS_PTR iCache.alloc_trace(entry);
|
||||
|
||||
// Cache miss. We weren't so lucky, but let's be optimistic - try to build
|
||||
// trace from incoming instruction bytes stream !
|
||||
entry->pAddr = pAddr;
|
||||
entry->traceMask = 0;
|
||||
|
||||
unsigned remainingInPage = BX_CPU_THIS_PTR eipPageWindowSize - eipBiased;
|
||||
const Bit8u *fetchPtr = BX_CPU_THIS_PTR eipFetchPtr + eipBiased;
|
||||
int ret;
|
||||
|
||||
bxInstruction_c *i = entry->i;
|
||||
|
||||
Bit32u pageOffset = PAGE_OFFSET((Bit32u) pAddr);
|
||||
Bit32u traceMask = 0;
|
||||
|
||||
for (unsigned n=0;n<BX_MAX_TRACE_LENGTH;n++)
|
||||
{
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
||||
ret = fetchDecode64(fetchPtr, i, remainingInPage);
|
||||
else
|
||||
#endif
|
||||
ret = fetchDecode32(fetchPtr, i, remainingInPage);
|
||||
|
||||
if (ret < 0) {
|
||||
// Fetching instruction on segment/page boundary
|
||||
if (n > 0) {
|
||||
// The trace is already valid, it has several instructions inside,
|
||||
// in this case just drop the boundary instruction and stop
|
||||
// tracing.
|
||||
break;
|
||||
}
|
||||
// First instruction is boundary fetch, leave the trace cache entry
|
||||
// invalid for now because boundaryFetch() can fault
|
||||
entry->pAddr = ~entry->pAddr;
|
||||
entry->tlen = 1;
|
||||
boundaryFetch(fetchPtr, remainingInPage, i);
|
||||
|
||||
// Add the instruction to trace cache
|
||||
entry->pAddr = ~entry->pAddr;
|
||||
entry->traceMask = 0x80000000; /* last line in page */
|
||||
pageWriteStampTable.markICacheMask(entry->pAddr, entry->traceMask);
|
||||
pageWriteStampTable.markICacheMask(BX_CPU_THIS_PTR pAddrPage, 0x1);
|
||||
BX_CPU_THIS_PTR iCache.commit_page_split_trace(BX_CPU_THIS_PTR pAddrPage, entry);
|
||||
return;
|
||||
}
|
||||
|
||||
// add instruction to the trace
|
||||
unsigned iLen = i->ilen();
|
||||
entry->tlen++;
|
||||
|
||||
BX_INSTR_OPCODE(BX_CPU_ID, fetchPtr, iLen,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b, long64_mode());
|
||||
|
||||
traceMask |= 1 << (pageOffset >> 7);
|
||||
traceMask |= 1 << ((pageOffset + iLen - 1) >> 7);
|
||||
|
||||
// continue to the next instruction
|
||||
remainingInPage -= iLen;
|
||||
if (ret != 0 /* stop trace indication */ || remainingInPage == 0) break;
|
||||
pAddr += iLen;
|
||||
pageOffset += iLen;
|
||||
fetchPtr += iLen;
|
||||
i++;
|
||||
|
||||
// try to find a trace starting from current pAddr and merge
|
||||
if (remainingInPage >= 15) // avoid merging with page split trace
|
||||
if (mergeTraces(entry, i, pAddr)) break;
|
||||
}
|
||||
|
||||
//BX_INFO(("commit trace %08x len=%d mask %08x", (Bit32u) entry->pAddr, entry->tlen, pageWriteStampTable.getFineGranularityMapping(entry->pAddr)));
|
||||
|
||||
entry->traceMask |= traceMask;
|
||||
|
||||
pageWriteStampTable.markICacheMask(pAddr, entry->traceMask);
|
||||
|
||||
BX_CPU_THIS_PTR iCache.commit_trace(entry->tlen);
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::mergeTraces(bxICacheEntry_c *entry, bxInstruction_c *i, bx_phy_address pAddr)
|
||||
{
|
||||
bxICacheEntry_c *e = BX_CPU_THIS_PTR iCache.get_entry(pAddr, BX_CPU_THIS_PTR fetchModeMask);
|
||||
|
||||
if (e->pAddr == pAddr)
|
||||
{
|
||||
// determine max amount of instruction to take from another entry
|
||||
unsigned max_length = e->tlen;
|
||||
if (max_length + entry->tlen > BX_MAX_TRACE_LENGTH)
|
||||
max_length = BX_MAX_TRACE_LENGTH - entry->tlen;
|
||||
if(max_length == 0) return 0;
|
||||
|
||||
memcpy(i, e->i, sizeof(bxInstruction_c)*max_length);
|
||||
entry->tlen += max_length;
|
||||
BX_ASSERT(entry->tlen <= BX_MAX_TRACE_LENGTH);
|
||||
|
||||
entry->traceMask |= e->traceMask;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else // BX_SUPPORT_TRACE_CACHE == 0
|
||||
|
||||
bx_bool BX_CPU_C::fetchInstruction(bxInstruction_c *iStorage, Bit32u eipBiased)
|
||||
{
|
||||
unsigned remainingInPage = BX_CPU_THIS_PTR eipPageWindowSize - eipBiased;
|
||||
const Bit8u *fetchPtr = BX_CPU_THIS_PTR eipFetchPtr + eipBiased;
|
||||
int ret;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
||||
ret = fetchDecode64(fetchPtr, iStorage, remainingInPage);
|
||||
else
|
||||
#endif
|
||||
ret = fetchDecode32(fetchPtr, iStorage, remainingInPage);
|
||||
|
||||
if (ret < 0) {
|
||||
// handle instrumentation callback inside boundaryFetch
|
||||
boundaryFetch(fetchPtr, remainingInPage, iStorage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BX_INSTRUMENTATION
|
||||
BX_INSTR_OPCODE(BX_CPU_ID, fetchPtr, iStorage->ilen(),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b, long64_mode());
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BX_CPU_C::serveICacheMiss(bxICacheEntry_c *entry, Bit32u eipBiased, bx_phy_address pAddr)
|
||||
{
|
||||
// The entry will be marked valid if fetchdecode will succeed
|
||||
if (fetchInstruction(entry->i, eipBiased)) {
|
||||
entry->pAddr = pAddr;
|
||||
pageWriteStampTable.markICache(pAddr, entry->i->ilen());
|
||||
}
|
||||
else {
|
||||
entry->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BX_CPU_C::boundaryFetch(const Bit8u *fetchPtr, unsigned remainingInPage, bxInstruction_c *i)
|
||||
{
|
||||
unsigned j, k;
|
||||
Bit8u fetchBuffer[32];
|
||||
int ret;
|
||||
|
||||
if (remainingInPage >= 15) {
|
||||
BX_ERROR(("boundaryFetch #GP(0): too many instruction prefixes"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// Read all leftover bytes in current page up to boundary.
|
||||
for (j=0; j<remainingInPage; j++) {
|
||||
fetchBuffer[j] = *fetchPtr++;
|
||||
}
|
||||
|
||||
// The 2nd chunk of the instruction is on the next page.
|
||||
// Set RIP to the 0th byte of the 2nd page, and force a
|
||||
// prefetch so direct access of that physical page is possible, and
|
||||
// all the associated info is updated.
|
||||
RIP += remainingInPage;
|
||||
prefetch();
|
||||
|
||||
unsigned fetchBufferLimit = 15;
|
||||
if (BX_CPU_THIS_PTR eipPageWindowSize < 15) {
|
||||
BX_DEBUG(("boundaryFetch: small window size after prefetch=%d bytes, remainingInPage=%d bytes", BX_CPU_THIS_PTR eipPageWindowSize, remainingInPage));
|
||||
fetchBufferLimit = BX_CPU_THIS_PTR eipPageWindowSize;
|
||||
}
|
||||
|
||||
// We can fetch straight from the 0th byte, which is eipFetchPtr;
|
||||
fetchPtr = BX_CPU_THIS_PTR eipFetchPtr;
|
||||
|
||||
// read leftover bytes in next page
|
||||
for (k=0; k<fetchBufferLimit; k++, j++) {
|
||||
fetchBuffer[j] = *fetchPtr++;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64)
|
||||
ret = fetchDecode64(fetchBuffer, i, remainingInPage+fetchBufferLimit);
|
||||
else
|
||||
#endif
|
||||
ret = fetchDecode32(fetchBuffer, i, remainingInPage+fetchBufferLimit);
|
||||
|
||||
if (ret < 0) {
|
||||
BX_INFO(("boundaryFetch #GP(0): failed to complete instruction decoding"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// Restore EIP since we fudged it to start at the 2nd page boundary.
|
||||
RIP = BX_CPU_THIS_PTR prev_rip;
|
||||
|
||||
// Since we cross an instruction boundary, note that we need a prefetch()
|
||||
// again on the next instruction. Perhaps we can optimize this to
|
||||
// eliminate the extra prefetch() since we do it above, but have to
|
||||
// think about repeated instructions, etc.
|
||||
// invalidate_prefetch_q();
|
||||
|
||||
BX_INSTR_OPCODE(BX_CPU_ID, fetchBuffer, i->ilen(),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b, long64_mode());
|
||||
}
|
||||
242
simulators/bochs/cpu/icache.h
Executable file
242
simulators/bochs/cpu/icache.h
Executable file
@ -0,0 +1,242 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2011 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_ICACHE_H
|
||||
#define BX_ICACHE_H
|
||||
|
||||
extern void handleSMC(bx_phy_address pAddr, Bit32u mask);
|
||||
|
||||
class bxPageWriteStampTable
|
||||
{
|
||||
#define PHY_MEM_PAGES (1024*1024)
|
||||
Bit32u *fineGranularityMapping;
|
||||
|
||||
public:
|
||||
bxPageWriteStampTable() {
|
||||
fineGranularityMapping = new Bit32u[PHY_MEM_PAGES];
|
||||
resetWriteStamps();
|
||||
}
|
||||
~bxPageWriteStampTable() { delete [] fineGranularityMapping; }
|
||||
|
||||
BX_CPP_INLINE Bit32u hash(bx_phy_address pAddr) const {
|
||||
// can share writeStamps between multiple pages if >32 bit phy address
|
||||
return ((Bit32u) pAddr) >> 12;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE Bit32u getFineGranularityMapping(bx_phy_address pAddr) const
|
||||
{
|
||||
return fineGranularityMapping[hash(pAddr)];
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void markICache(bx_phy_address pAddr, unsigned len)
|
||||
{
|
||||
Bit32u mask = 1 << (PAGE_OFFSET((Bit32u) pAddr) >> 7);
|
||||
mask |= 1 << (PAGE_OFFSET((Bit32u) pAddr + len - 1) >> 7);
|
||||
|
||||
fineGranularityMapping[hash(pAddr)] |= mask;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void markICacheMask(bx_phy_address pAddr, Bit32u mask)
|
||||
{
|
||||
fineGranularityMapping[hash(pAddr)] |= mask;
|
||||
}
|
||||
|
||||
// whole page is being altered
|
||||
BX_CPP_INLINE void decWriteStamp(bx_phy_address pAddr)
|
||||
{
|
||||
Bit32u index = hash(pAddr);
|
||||
|
||||
if (fineGranularityMapping[index]) {
|
||||
handleSMC(pAddr, 0xffffffff); // one of the CPUs might be running trace from this page
|
||||
fineGranularityMapping[index] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// assumption: write does not split 4K page
|
||||
BX_CPP_INLINE void decWriteStamp(bx_phy_address pAddr, unsigned len)
|
||||
{
|
||||
Bit32u index = hash(pAddr);
|
||||
|
||||
if (fineGranularityMapping[index]) {
|
||||
Bit32u mask = 1 << (PAGE_OFFSET((Bit32u) pAddr) >> 7);
|
||||
mask |= 1 << (PAGE_OFFSET((Bit32u) pAddr + len - 1) >> 7);
|
||||
|
||||
if (fineGranularityMapping[index] & mask) {
|
||||
// one of the CPUs might be running trace from this page
|
||||
handleSMC(pAddr, mask);
|
||||
fineGranularityMapping[index] &= ~mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void resetWriteStamps(void);
|
||||
};
|
||||
|
||||
BX_CPP_INLINE void bxPageWriteStampTable::resetWriteStamps(void)
|
||||
{
|
||||
for (Bit32u i=0; i<PHY_MEM_PAGES; i++) {
|
||||
fineGranularityMapping[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
extern bxPageWriteStampTable pageWriteStampTable;
|
||||
|
||||
#define BxICacheEntries (64 * 1024) // Must be a power of 2.
|
||||
#define BxICacheMemPool (384 * 1024)
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
#define BX_MAX_TRACE_LENGTH 32
|
||||
#endif
|
||||
|
||||
struct bxICacheEntry_c
|
||||
{
|
||||
bx_phy_address pAddr; // Physical address of the instruction
|
||||
Bit32u traceMask;
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
Bit32u tlen; // Trace length in instructions
|
||||
bxInstruction_c *i;
|
||||
#else
|
||||
// ... define as array of 1 to simplify merge with trace cache code
|
||||
bxInstruction_c i[1];
|
||||
#endif
|
||||
};
|
||||
|
||||
#define BX_ICACHE_INVALID_PHY_ADDRESS (bx_phy_address(-1))
|
||||
|
||||
class BOCHSAPI bxICache_c {
|
||||
public:
|
||||
bxICacheEntry_c entry[BxICacheEntries];
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
bxInstruction_c mpool[BxICacheMemPool];
|
||||
unsigned mpindex;
|
||||
|
||||
#define BX_ICACHE_PAGE_SPLIT_ENTRIES 8 /* must be power of two */
|
||||
struct pageSplitEntryIndex {
|
||||
bx_phy_address ppf; // Physical address of 2nd page of the trace
|
||||
bxICacheEntry_c *e; // Pointer to icache entry
|
||||
} pageSplitIndex[BX_ICACHE_PAGE_SPLIT_ENTRIES];
|
||||
int nextPageSplitIndex;
|
||||
#endif
|
||||
|
||||
public:
|
||||
bxICache_c() { flushICacheEntries(); }
|
||||
|
||||
BX_CPP_INLINE unsigned hash(bx_phy_address pAddr, unsigned fetchModeMask) const
|
||||
{
|
||||
// return ((pAddr + (pAddr << 2) + (pAddr>>6)) & (BxICacheEntries-1)) ^ fetchModeMask;
|
||||
return ((pAddr) & (BxICacheEntries-1)) ^ fetchModeMask;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
BX_CPP_INLINE void alloc_trace(bxICacheEntry_c *e)
|
||||
{
|
||||
if (mpindex + BX_MAX_TRACE_LENGTH > BxICacheMemPool) {
|
||||
flushICacheEntries();
|
||||
}
|
||||
e->i = &mpool[mpindex];
|
||||
e->tlen = 0;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void commit_trace(unsigned len) { mpindex += len; }
|
||||
|
||||
BX_CPP_INLINE void commit_page_split_trace(bx_phy_address paddr, bxICacheEntry_c *entry)
|
||||
{
|
||||
mpindex++; // commit_trace(1)
|
||||
|
||||
// register page split entry
|
||||
if (pageSplitIndex[nextPageSplitIndex].ppf != BX_ICACHE_INVALID_PHY_ADDRESS)
|
||||
pageSplitIndex[nextPageSplitIndex].e->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
|
||||
|
||||
pageSplitIndex[nextPageSplitIndex].ppf = paddr;
|
||||
pageSplitIndex[nextPageSplitIndex].e = entry;
|
||||
|
||||
nextPageSplitIndex = (nextPageSplitIndex+1) & (BX_ICACHE_PAGE_SPLIT_ENTRIES-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
BX_CPP_INLINE void handleSMC(bx_phy_address pAddr, Bit32u mask);
|
||||
|
||||
BX_CPP_INLINE void purgeICacheEntries(void);
|
||||
BX_CPP_INLINE void flushICacheEntries(void);
|
||||
|
||||
BX_CPP_INLINE bxICacheEntry_c* get_entry(bx_phy_address pAddr, unsigned fetchModeMask)
|
||||
{
|
||||
return &(entry[hash(pAddr, fetchModeMask)]);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
BX_CPP_INLINE void bxICache_c::flushICacheEntries(void)
|
||||
{
|
||||
bxICacheEntry_c* e = entry;
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<BxICacheEntries; i++, e++) {
|
||||
e->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
|
||||
e->traceMask = 0;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
for (i=0;i<BX_ICACHE_PAGE_SPLIT_ENTRIES;i++)
|
||||
pageSplitIndex[i].ppf = BX_ICACHE_INVALID_PHY_ADDRESS;
|
||||
|
||||
nextPageSplitIndex = 0;
|
||||
mpindex = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void bxICache_c::handleSMC(bx_phy_address pAddr, Bit32u mask)
|
||||
{
|
||||
// TODO: invalidate only entries in same page as pAddr
|
||||
|
||||
pAddr = LPFOf(pAddr);
|
||||
|
||||
#if BX_SUPPORT_TRACE_CACHE
|
||||
if (mask & 0x1) {
|
||||
// the store touched 1st cache line in the page, check for
|
||||
// page split traces to invalidate.
|
||||
for (unsigned i=0;i<BX_ICACHE_PAGE_SPLIT_ENTRIES;i++) {
|
||||
if (pAddr == pageSplitIndex[i].ppf) {
|
||||
pageSplitIndex[i].ppf = BX_ICACHE_INVALID_PHY_ADDRESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bxICacheEntry_c *e = get_entry(pAddr, 0);
|
||||
|
||||
for (unsigned n=0; n < 32; n++) {
|
||||
Bit32u line_mask = (1 << n);
|
||||
if (line_mask > mask) break;
|
||||
for (unsigned index=0; index < 128; index++, e++) {
|
||||
if (pAddr == LPFOf(e->pAddr) && (e->traceMask & mask) != 0) {
|
||||
e->pAddr = BX_ICACHE_INVALID_PHY_ADDRESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void flushICaches(void);
|
||||
|
||||
#endif
|
||||
1239
simulators/bochs/cpu/init.cc
Normal file
1239
simulators/bochs/cpu/init.cc
Normal file
File diff suppressed because it is too large
Load Diff
279
simulators/bochs/cpu/instr.h
Executable file
279
simulators/bochs/cpu/instr.h
Executable file
@ -0,0 +1,279 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_INSTR_H
|
||||
#define BX_INSTR_H
|
||||
|
||||
class bxInstruction_c;
|
||||
|
||||
// <TAG-TYPE-EXECUTEPTR-START>
|
||||
#if BX_USE_CPU_SMF
|
||||
typedef void (BX_CPP_AttrRegparmN(1) *BxExecutePtr_tR)(bxInstruction_c *);
|
||||
typedef bx_address (BX_CPP_AttrRegparmN(1) *BxResolvePtr_tR)(bxInstruction_c *);
|
||||
#else
|
||||
typedef void (BX_CPU_C::*BxExecutePtr_tR)(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
|
||||
typedef bx_address (BX_CPU_C::*BxResolvePtr_tR)(bxInstruction_c *) BX_CPP_AttrRegparmN(1);
|
||||
#endif
|
||||
// <TAG-TYPE-EXECUTEPTR-END>
|
||||
|
||||
extern bx_address bx_asize_mask[];
|
||||
|
||||
// <TAG-CLASS-INSTRUCTION-START>
|
||||
class bxInstruction_c {
|
||||
public:
|
||||
// Function pointers; a function to resolve the modRM address
|
||||
// given the current state of the CPU and the instruction data,
|
||||
// and a function to execute the instruction after resolving
|
||||
// the memory address (if any).
|
||||
BxExecutePtr_tR execute;
|
||||
BxExecutePtr_tR execute2;
|
||||
BxResolvePtr_tR ResolveModrm;
|
||||
|
||||
struct {
|
||||
// 15..0 opcode
|
||||
Bit16u ia_opcode;
|
||||
|
||||
// 7...4 (unused)
|
||||
// 3...0 ilen (0..15)
|
||||
Bit8u ilen;
|
||||
|
||||
// 7...6 repUsed (0=none, 2=0xF2, 3=0xF3)
|
||||
// 5...5 extend8bit
|
||||
// 4...4 mod==c0 (modrm)
|
||||
// 3...3 os64
|
||||
// 2...2 os32
|
||||
// 1...1 as64
|
||||
// 0...0 as32
|
||||
Bit8u metaInfo1;
|
||||
} metaInfo;
|
||||
|
||||
#define BX_INSTR_METADATA_SEG 0
|
||||
#define BX_INSTR_METADATA_B1 1
|
||||
#define BX_INSTR_METADATA_NNN 2
|
||||
#define BX_INSTR_METADATA_RM 3
|
||||
#define BX_INSTR_METADATA_BASE 4
|
||||
#define BX_INSTR_METADATA_INDEX 5
|
||||
#define BX_INSTR_METADATA_SCALE 6
|
||||
#define BX_INSTR_METADATA_MODRM 7
|
||||
|
||||
// using 5-bit field for registers (16 regs in 64-bit, RIP, NIL)
|
||||
Bit8u metaData[8];
|
||||
|
||||
union {
|
||||
// Form (longest case): [opcode+modrm+sib/displacement32/immediate32]
|
||||
struct {
|
||||
union {
|
||||
Bit32u Id;
|
||||
Bit16u Iw;
|
||||
Bit8u Ib;
|
||||
};
|
||||
union {
|
||||
Bit16u displ16u; // for 16-bit modrm forms
|
||||
Bit32u displ32u; // for 32-bit modrm forms
|
||||
|
||||
Bit16u Iw2;
|
||||
Bit8u Ib2;
|
||||
};
|
||||
} modRMForm;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
struct {
|
||||
Bit64u Iq; // for MOV Rx,imm64
|
||||
} IqForm;
|
||||
#endif
|
||||
};
|
||||
|
||||
BX_CPP_INLINE unsigned seg(void) const {
|
||||
return metaData[BX_INSTR_METADATA_SEG];
|
||||
}
|
||||
BX_CPP_INLINE void setSeg(unsigned val) {
|
||||
metaData[BX_INSTR_METADATA_SEG] = val;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE unsigned b1(void) const {
|
||||
return metaData[BX_INSTR_METADATA_B1];
|
||||
}
|
||||
BX_CPP_INLINE void setB1(unsigned b1) {
|
||||
metaData[BX_INSTR_METADATA_B1] = b1 & 0xff;
|
||||
}
|
||||
BX_CPP_INLINE void setModRM(unsigned modrm) {
|
||||
metaData[BX_INSTR_METADATA_MODRM] = modrm;
|
||||
}
|
||||
BX_CPP_INLINE unsigned modrm() const {
|
||||
return metaData[BX_INSTR_METADATA_MODRM];
|
||||
}
|
||||
BX_CPP_INLINE void setNnn(unsigned nnn) {
|
||||
metaData[BX_INSTR_METADATA_NNN] = nnn;
|
||||
}
|
||||
BX_CPP_INLINE unsigned nnn() const {
|
||||
return metaData[BX_INSTR_METADATA_NNN];
|
||||
}
|
||||
BX_CPP_INLINE void setRm(unsigned rm) {
|
||||
metaData[BX_INSTR_METADATA_RM] = rm;
|
||||
}
|
||||
BX_CPP_INLINE unsigned rm() const {
|
||||
return metaData[BX_INSTR_METADATA_RM];
|
||||
}
|
||||
BX_CPP_INLINE void setSibScale(unsigned scale) {
|
||||
metaData[BX_INSTR_METADATA_SCALE] = scale;
|
||||
}
|
||||
BX_CPP_INLINE unsigned sibScale() const {
|
||||
return metaData[BX_INSTR_METADATA_SCALE];
|
||||
}
|
||||
BX_CPP_INLINE void setSibIndex(unsigned index) {
|
||||
metaData[BX_INSTR_METADATA_INDEX] = index;
|
||||
}
|
||||
BX_CPP_INLINE unsigned sibIndex() const {
|
||||
return metaData[BX_INSTR_METADATA_INDEX];
|
||||
}
|
||||
BX_CPP_INLINE void setSibBase(unsigned base) {
|
||||
metaData[BX_INSTR_METADATA_BASE] = base;
|
||||
}
|
||||
BX_CPP_INLINE unsigned sibBase() const {
|
||||
return metaData[BX_INSTR_METADATA_BASE];
|
||||
}
|
||||
BX_CPP_INLINE Bit32s displ32s() const { return (Bit32s) modRMForm.displ32u; }
|
||||
BX_CPP_INLINE Bit16s displ16s() const { return (Bit16s) modRMForm.displ16u; }
|
||||
BX_CPP_INLINE Bit32u Id() const { return modRMForm.Id; }
|
||||
BX_CPP_INLINE Bit16u Iw() const { return modRMForm.Iw; }
|
||||
BX_CPP_INLINE Bit8u Ib() const { return modRMForm.Ib; }
|
||||
BX_CPP_INLINE Bit16u Iw2() const { return modRMForm.Iw2; }
|
||||
BX_CPP_INLINE Bit8u Ib2() const { return modRMForm.Ib2; }
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE Bit64u Iq() const { return IqForm.Iq; }
|
||||
#endif
|
||||
|
||||
// Info in the metaInfo field.
|
||||
// Note: the 'L' at the end of certain flags, means the value returned
|
||||
// is for Logical comparisons, eg if (i->os32L() && i->as32L()). If you
|
||||
// want a bx_bool value, use os32B() etc. This makes for smaller
|
||||
// code, when a strict 0 or 1 is not necessary.
|
||||
BX_CPP_INLINE void init(unsigned os32, unsigned as32, unsigned os64, unsigned as64)
|
||||
{
|
||||
metaInfo.metaInfo1 = (os32<<2) | (os64<<3) | (as32<<0) | (as64<<1);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE unsigned os32L(void) const {
|
||||
return metaInfo.metaInfo1 & (1<<2);
|
||||
}
|
||||
BX_CPP_INLINE void setOs32B(unsigned bit) {
|
||||
metaInfo.metaInfo1 = (metaInfo.metaInfo1 & ~(1<<2)) | (bit<<2);
|
||||
}
|
||||
BX_CPP_INLINE void assertOs32(void) {
|
||||
metaInfo.metaInfo1 |= (1<<2);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE unsigned os64L(void) const {
|
||||
return metaInfo.metaInfo1 & (1<<3);
|
||||
}
|
||||
BX_CPP_INLINE void assertOs64(void) {
|
||||
metaInfo.metaInfo1 |= (1<<3);
|
||||
}
|
||||
#else
|
||||
BX_CPP_INLINE unsigned os64L(void) const { return 0; }
|
||||
#endif
|
||||
|
||||
|
||||
BX_CPP_INLINE unsigned as32L(void) const {
|
||||
return metaInfo.metaInfo1 & 0x1;
|
||||
}
|
||||
BX_CPP_INLINE void setAs32B(unsigned bit) {
|
||||
metaInfo.metaInfo1 = (metaInfo.metaInfo1 & ~0x1) | (bit);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE unsigned as64L(void) const {
|
||||
return metaInfo.metaInfo1 & (1<<1);
|
||||
}
|
||||
BX_CPP_INLINE void clearAs64(void) {
|
||||
metaInfo.metaInfo1 &= ~(1<<1);
|
||||
}
|
||||
#else
|
||||
BX_CPP_INLINE unsigned as64L(void) const { return 0; }
|
||||
#endif
|
||||
|
||||
BX_CPP_INLINE unsigned asize(void) const {
|
||||
return metaInfo.metaInfo1 & 0x3;
|
||||
}
|
||||
BX_CPP_INLINE bx_address asize_mask(void) const {
|
||||
return bx_asize_mask[asize()];
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE unsigned extend8bitL(void) const {
|
||||
return metaInfo.metaInfo1 & (1<<5);
|
||||
}
|
||||
BX_CPP_INLINE void assertExtend8bit(void) {
|
||||
metaInfo.metaInfo1 |= (1<<5);
|
||||
}
|
||||
#endif
|
||||
|
||||
BX_CPP_INLINE unsigned ilen(void) const {
|
||||
return metaInfo.ilen;
|
||||
}
|
||||
BX_CPP_INLINE void setILen(unsigned ilen) {
|
||||
metaInfo.ilen = ilen;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE unsigned getIaOpcode(void) const {
|
||||
return metaInfo.ia_opcode;
|
||||
}
|
||||
BX_CPP_INLINE void setIaOpcode(Bit16u op) {
|
||||
metaInfo.ia_opcode = op;
|
||||
}
|
||||
|
||||
BX_CPP_INLINE unsigned repUsedL(void) const {
|
||||
return metaInfo.metaInfo1 >> 6;
|
||||
}
|
||||
BX_CPP_INLINE unsigned repUsedValue(void) const {
|
||||
return metaInfo.metaInfo1 >> 6;
|
||||
}
|
||||
BX_CPP_INLINE void setRepUsed(unsigned value) {
|
||||
metaInfo.metaInfo1 = (metaInfo.metaInfo1 & 0x3f) | (value << 6);
|
||||
}
|
||||
|
||||
BX_CPP_INLINE unsigned modC0() const
|
||||
{
|
||||
// This is a cheaper way to test for modRM instructions where
|
||||
// the mod field is 0xc0. FetchDecode flags this condition since
|
||||
// it is quite common to be tested for.
|
||||
return metaInfo.metaInfo1 & (1<<4);
|
||||
}
|
||||
BX_CPP_INLINE unsigned assertModC0()
|
||||
{
|
||||
return metaInfo.metaInfo1 |= (1<<4);
|
||||
}
|
||||
};
|
||||
// <TAG-CLASS-INSTRUCTION-END>
|
||||
|
||||
const char *get_bx_opcode_name(Bit16u ia_opcode);
|
||||
|
||||
enum {
|
||||
#define bx_define_opcode(a, b, c, d, e) a,
|
||||
#include "ia_opcodes.h"
|
||||
BX_IA_LAST
|
||||
};
|
||||
#undef bx_define_opcode
|
||||
|
||||
#endif
|
||||
868
simulators/bochs/cpu/io.cc
Normal file
868
simulators/bochs/cpu/io.cc
Normal file
@ -0,0 +1,868 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#include "iodev/iodev.h"
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier for merging cpu64 and cpu32 code.
|
||||
#define RDI EDI
|
||||
#define RSI ESI
|
||||
#define RAX EAX
|
||||
#define RCX ECX
|
||||
#endif
|
||||
|
||||
//
|
||||
// Repeat Speedups methods
|
||||
//
|
||||
|
||||
#if BX_SupportRepeatSpeedups
|
||||
Bit32u BX_CPU_C::FastRepINSW(bxInstruction_c *i, bx_address dstOff, Bit16u port, Bit32u wordCount)
|
||||
{
|
||||
Bit32u wordsFitDst;
|
||||
signed int pointerDelta;
|
||||
Bit8u *hostAddrDst;
|
||||
unsigned count;
|
||||
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
bx_segment_reg_t *dstSegPtr = &BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES];
|
||||
if (!(dstSegPtr->cache.valid & SegAccessWOK))
|
||||
return 0;
|
||||
if ((dstOff | 0xfff) > dstSegPtr->cache.u.segment.limit_scaled)
|
||||
return 0;
|
||||
|
||||
bx_address laddrDst = BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_ES, dstOff);
|
||||
// check that the address is word aligned
|
||||
if (laddrDst & 1) return 0;
|
||||
|
||||
hostAddrDst = v2h_write_byte(laddrDst, BX_CPU_THIS_PTR user_pl);
|
||||
// Check that native host access was not vetoed for that page
|
||||
if (!hostAddrDst) return 0;
|
||||
|
||||
// See how many words can fit in the rest of this page.
|
||||
if (BX_CPU_THIS_PTR get_DF()) {
|
||||
// Counting downward
|
||||
// 1st word must cannot cross page boundary because it is word aligned
|
||||
wordsFitDst = (2 + (PAGE_OFFSET(laddrDst))) >> 1;
|
||||
pointerDelta = -2;
|
||||
}
|
||||
else {
|
||||
// Counting upward
|
||||
wordsFitDst = (0x1000 - PAGE_OFFSET(laddrDst)) >> 1;
|
||||
pointerDelta = 2;
|
||||
}
|
||||
|
||||
// Restrict word count to the number that will fit in this page.
|
||||
if (wordCount > wordsFitDst)
|
||||
wordCount = wordsFitDst;
|
||||
|
||||
// If after all the restrictions, there is anything left to do...
|
||||
if (wordCount) {
|
||||
for (count=0; count<wordCount; ) {
|
||||
bx_devices.bulkIOQuantumsTransferred = 0;
|
||||
if (BX_CPU_THIS_PTR get_DF()==0) { // Only do accel for DF=0
|
||||
bx_devices.bulkIOHostAddr = hostAddrDst;
|
||||
bx_devices.bulkIOQuantumsRequested = (wordCount - count);
|
||||
}
|
||||
else
|
||||
bx_devices.bulkIOQuantumsRequested = 0;
|
||||
Bit16u temp16 = BX_INP(port, 2);
|
||||
if (bx_devices.bulkIOQuantumsTransferred) {
|
||||
hostAddrDst = bx_devices.bulkIOHostAddr;
|
||||
count += bx_devices.bulkIOQuantumsTransferred;
|
||||
}
|
||||
else {
|
||||
WriteHostWordToLittleEndian(hostAddrDst, temp16);
|
||||
hostAddrDst += pointerDelta;
|
||||
count++;
|
||||
}
|
||||
// Terminate early if there was an event.
|
||||
if (BX_CPU_THIS_PTR async_event) break;
|
||||
}
|
||||
|
||||
// Reset for next non-bulk IO
|
||||
bx_devices.bulkIOQuantumsRequested = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit32u BX_CPU_C::FastRepOUTSW(bxInstruction_c *i, unsigned srcSeg, bx_address srcOff, Bit16u port, Bit32u wordCount)
|
||||
{
|
||||
Bit32u wordsFitSrc;
|
||||
signed int pointerDelta;
|
||||
Bit8u *hostAddrSrc;
|
||||
unsigned count;
|
||||
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
bx_segment_reg_t *srcSegPtr = &BX_CPU_THIS_PTR sregs[srcSeg];
|
||||
if (!(srcSegPtr->cache.valid & SegAccessROK))
|
||||
return 0;
|
||||
if ((srcOff | 0xfff) > srcSegPtr->cache.u.segment.limit_scaled)
|
||||
return 0;
|
||||
|
||||
bx_address laddrSrc = BX_CPU_THIS_PTR get_laddr(srcSeg, srcOff);
|
||||
// check that the address is word aligned
|
||||
if (laddrSrc & 1) return 0;
|
||||
|
||||
hostAddrSrc = v2h_read_byte(laddrSrc, BX_CPU_THIS_PTR user_pl);
|
||||
|
||||
// Check that native host access was not vetoed for that page
|
||||
if (!hostAddrSrc) return 0;
|
||||
|
||||
// See how many words can fit in the rest of this page.
|
||||
if (BX_CPU_THIS_PTR get_DF()) {
|
||||
// Counting downward
|
||||
// 1st word must cannot cross page boundary because it is word aligned
|
||||
wordsFitSrc = (2 + (PAGE_OFFSET(laddrSrc))) >> 1;
|
||||
pointerDelta = (unsigned) -2;
|
||||
}
|
||||
else {
|
||||
// Counting upward
|
||||
wordsFitSrc = (0x1000 - PAGE_OFFSET(laddrSrc)) >> 1;
|
||||
pointerDelta = 2;
|
||||
}
|
||||
|
||||
// Restrict word count to the number that will fit in this page.
|
||||
if (wordCount > wordsFitSrc)
|
||||
wordCount = wordsFitSrc;
|
||||
|
||||
// If after all the restrictions, there is anything left to do...
|
||||
if (wordCount) {
|
||||
for (count=0; count<wordCount; ) {
|
||||
bx_devices.bulkIOQuantumsTransferred = 0;
|
||||
if (BX_CPU_THIS_PTR get_DF()==0) { // Only do accel for DF=0
|
||||
bx_devices.bulkIOHostAddr = hostAddrSrc;
|
||||
bx_devices.bulkIOQuantumsRequested = (wordCount - count);
|
||||
}
|
||||
else
|
||||
bx_devices.bulkIOQuantumsRequested = 0;
|
||||
Bit16u temp16;
|
||||
ReadHostWordFromLittleEndian(hostAddrSrc, temp16);
|
||||
BX_OUTP(port, temp16, 2);
|
||||
if (bx_devices.bulkIOQuantumsTransferred) {
|
||||
hostAddrSrc = bx_devices.bulkIOHostAddr;
|
||||
count += bx_devices.bulkIOQuantumsTransferred;
|
||||
}
|
||||
else {
|
||||
hostAddrSrc += pointerDelta;
|
||||
count++;
|
||||
}
|
||||
// Terminate early if there was an event.
|
||||
if (BX_CPU_THIS_PTR async_event) break;
|
||||
}
|
||||
|
||||
// Reset for next non-bulk IO
|
||||
bx_devices.bulkIOQuantumsRequested = 0;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// REP INS methods
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_INSB_YbDX(bxInstruction_c *i)
|
||||
{
|
||||
if (! allow_io(i, DX, 1)) {
|
||||
BX_DEBUG(("INSB_YbDX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSB64_YbDX);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSB32_YbDX);
|
||||
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RDI); // always clear upper part of RDI
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSB16_YbDX);
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSB16_YbDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit8u value8 = read_RMW_virtual_byte_32(BX_SEG_REG_ES, DI);
|
||||
|
||||
value8 = BX_INP(DX, 1);
|
||||
|
||||
write_RMW_virtual_byte(value8);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
DI--;
|
||||
else
|
||||
DI++;
|
||||
}
|
||||
|
||||
// 32-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSB32_YbDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit8u value8 = read_RMW_virtual_byte(BX_SEG_REG_ES, EDI);
|
||||
|
||||
value8 = BX_INP(DX, 1);
|
||||
|
||||
/* no seg override possible */
|
||||
write_RMW_virtual_byte(value8);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF()) {
|
||||
RDI = EDI - 1;
|
||||
}
|
||||
else {
|
||||
RDI = EDI + 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
// 64-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSB64_YbDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit8u value8 = read_RMW_virtual_byte_64(BX_SEG_REG_ES, RDI);
|
||||
|
||||
value8 = BX_INP(DX, 1);
|
||||
|
||||
write_RMW_virtual_byte(value8);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RDI--;
|
||||
else
|
||||
RDI++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_INSW_YwDX(bxInstruction_c *i)
|
||||
{
|
||||
if (! allow_io(i, DX, 2)) {
|
||||
BX_DEBUG(("INSW_YwDX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSW64_YwDX);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSW32_YwDX);
|
||||
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RDI); // always clear upper part of RDI
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSW16_YwDX);
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit operand size, 16-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSW16_YwDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit16u value16 = read_RMW_virtual_word_32(BX_SEG_REG_ES, DI);
|
||||
|
||||
value16 = BX_INP(DX, 2);
|
||||
|
||||
write_RMW_virtual_word(value16);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
DI -= 2;
|
||||
else
|
||||
DI += 2;
|
||||
}
|
||||
|
||||
// 16-bit operand size, 32-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSW32_YwDX(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u value16=0;
|
||||
Bit32u edi = EDI;
|
||||
unsigned incr = 2;
|
||||
|
||||
#if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0)
|
||||
/* If conditions are right, we can transfer IO to physical memory
|
||||
* in a batch, rather than one instruction at a time.
|
||||
*/
|
||||
if (i->repUsedL() && !BX_CPU_THIS_PTR async_event)
|
||||
{
|
||||
Bit32u wordCount = ECX;
|
||||
BX_ASSERT(wordCount > 0);
|
||||
wordCount = FastRepINSW(i, edi, DX, wordCount);
|
||||
if (wordCount) {
|
||||
// Decrement the ticks count by the number of iterations, minus
|
||||
// one, since the main cpu loop will decrement one. Also,
|
||||
// the count is predecremented before examined, so defintely
|
||||
// don't roll it under zero.
|
||||
BX_TICKN(wordCount-1);
|
||||
RCX = ECX - (wordCount-1);
|
||||
incr = wordCount << 1; // count * 2.
|
||||
}
|
||||
else {
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
value16 = read_RMW_virtual_word(BX_SEG_REG_ES, edi);
|
||||
|
||||
value16 = BX_INP(DX, 2);
|
||||
|
||||
write_RMW_virtual_word(value16);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
value16 = read_RMW_virtual_word_32(BX_SEG_REG_ES, edi);
|
||||
|
||||
value16 = BX_INP(DX, 2);
|
||||
|
||||
write_RMW_virtual_word(value16);
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RDI = EDI - incr;
|
||||
else
|
||||
RDI = EDI + incr;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
// 16-bit operand size, 64-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSW64_YwDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit16u value16 = read_RMW_virtual_word_64(BX_SEG_REG_ES, RDI);
|
||||
|
||||
value16 = BX_INP(DX, 2);
|
||||
|
||||
write_RMW_virtual_word(value16);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RDI -= 2;
|
||||
else
|
||||
RDI += 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_INSD_YdDX(bxInstruction_c *i)
|
||||
{
|
||||
if (! allow_io(i, DX, 4)) {
|
||||
BX_DEBUG(("INSD_YdDX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSD64_YdDX);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSD32_YdDX);
|
||||
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RDI); // always clear upper part of RDI
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::INSD16_YdDX);
|
||||
}
|
||||
}
|
||||
|
||||
// 32-bit operand size, 16-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSD16_YdDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit32u value32 = read_RMW_virtual_dword_32(BX_SEG_REG_ES, DI);
|
||||
|
||||
value32 = BX_INP(DX, 4);
|
||||
|
||||
write_RMW_virtual_dword(value32);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
DI -= 4;
|
||||
else
|
||||
DI += 4;
|
||||
}
|
||||
|
||||
// 32-bit operand size, 32-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSD32_YdDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit32u value32 = read_RMW_virtual_dword(BX_SEG_REG_ES, EDI);
|
||||
|
||||
value32 = BX_INP(DX, 4);
|
||||
|
||||
write_RMW_virtual_dword(value32);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RDI = EDI - 4;
|
||||
else
|
||||
RDI = EDI + 4;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
// 32-bit operand size, 64-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INSD64_YdDX(bxInstruction_c *i)
|
||||
{
|
||||
// trigger any segment or page faults before reading from IO port
|
||||
Bit32u value32 = read_RMW_virtual_dword_64(BX_SEG_REG_ES, RDI);
|
||||
|
||||
value32 = BX_INP(DX, 4);
|
||||
|
||||
write_RMW_virtual_dword(value32);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RDI -= 4;
|
||||
else
|
||||
RDI += 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// REP OUTS methods
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_OUTSB_DXXb(bxInstruction_c *i)
|
||||
{
|
||||
if (! allow_io(i, DX, 1)) {
|
||||
BX_DEBUG(("OUTSB_DXXb: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSB64_DXXb);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSB32_DXXb);
|
||||
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSI); // always clear upper part of RSI
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSB16_DXXb);
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSB16_DXXb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u value8 = read_virtual_byte_32(i->seg(), SI);
|
||||
BX_OUTP(DX, value8, 1);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
SI--;
|
||||
else
|
||||
SI++;
|
||||
}
|
||||
|
||||
// 32-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSB32_DXXb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u value8 = read_virtual_byte(i->seg(), ESI);
|
||||
BX_OUTP(DX, value8, 1);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RSI = ESI - 1;
|
||||
else
|
||||
RSI = ESI + 1;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
// 64-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSB64_DXXb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u value8 = read_virtual_byte_64(i->seg(), RSI);
|
||||
BX_OUTP(DX, value8, 1);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RSI--;
|
||||
else
|
||||
RSI++;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_OUTSW_DXXw(bxInstruction_c *i)
|
||||
{
|
||||
if (! allow_io(i, DX, 2)) {
|
||||
BX_DEBUG(("OUTSW_DXXw: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSW64_DXXw);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSW32_DXXw);
|
||||
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSI); // always clear upper part of RSI
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSW16_DXXw);
|
||||
}
|
||||
}
|
||||
|
||||
// 16-bit operand size, 16-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSW16_DXXw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u value16 = read_virtual_word_32(i->seg(), SI);
|
||||
BX_OUTP(DX, value16, 2);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
SI -= 2;
|
||||
else
|
||||
SI += 2;
|
||||
}
|
||||
|
||||
// 16-bit operand size, 32-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSW32_DXXw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u value16;
|
||||
Bit32u esi = ESI;
|
||||
unsigned incr = 2;
|
||||
|
||||
#if (BX_SupportRepeatSpeedups) && (BX_DEBUGGER == 0)
|
||||
/* If conditions are right, we can transfer IO to physical memory
|
||||
* in a batch, rather than one instruction at a time.
|
||||
*/
|
||||
if (i->repUsedL() && !BX_CPU_THIS_PTR async_event) {
|
||||
Bit32u wordCount = ECX;
|
||||
wordCount = FastRepOUTSW(i, i->seg(), esi, DX, wordCount);
|
||||
if (wordCount) {
|
||||
// Decrement eCX. Note, the main loop will decrement 1 also, so
|
||||
// decrement by one less than expected, like the case above.
|
||||
BX_TICKN(wordCount-1); // Main cpu loop also decrements one more.
|
||||
RCX = ECX - (wordCount-1);
|
||||
incr = wordCount << 1; // count * 2.
|
||||
}
|
||||
else {
|
||||
value16 = read_virtual_word(i->seg(), esi);
|
||||
BX_OUTP(DX, value16, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
value16 = read_virtual_word(i->seg(), esi);
|
||||
BX_OUTP(DX, value16, 2);
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RSI = ESI - incr;
|
||||
else
|
||||
RSI = ESI + incr;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
// 16-bit operand size, 64-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSW64_DXXw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u value16 = read_virtual_word_64(i->seg(), RSI);
|
||||
BX_OUTP(DX, value16, 2);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RSI -= 2;
|
||||
else
|
||||
RSI += 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::REP_OUTSD_DXXd(bxInstruction_c *i)
|
||||
{
|
||||
if (! allow_io(i, DX, 4)) {
|
||||
BX_DEBUG(("OUTSD_DXXd: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->as64L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSD64_DXXd);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->as32L()) {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSD32_DXXd);
|
||||
BX_CLEAR_64BIT_HIGH(BX_64BIT_REG_RSI); // always clear upper part of RSI
|
||||
}
|
||||
else {
|
||||
BX_CPU_THIS_PTR repeat(i, &BX_CPU_C::OUTSD16_DXXd);
|
||||
}
|
||||
}
|
||||
|
||||
// 32-bit operand size, 16-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSD16_DXXd(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u value32 = read_virtual_dword_32(i->seg(), SI);
|
||||
BX_OUTP(DX, value32, 4);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
SI -= 4;
|
||||
else
|
||||
SI += 4;
|
||||
}
|
||||
|
||||
// 32-bit operand size, 32-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSD32_DXXd(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u value32 = read_virtual_dword(i->seg(), ESI);
|
||||
BX_OUTP(DX, value32, 4);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RSI = ESI - 4;
|
||||
else
|
||||
RSI = ESI + 4;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
// 32-bit operand size, 64-bit address size
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUTSD64_DXXd(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u value32 = read_virtual_dword_64(i->seg(), RSI);
|
||||
BX_OUTP(DX, value32, 4);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_DF())
|
||||
RSI -= 4;
|
||||
else
|
||||
RSI += 4;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// non repeatable IN/OUT methods
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = i->Ib();
|
||||
|
||||
if (! allow_io(i, port, 1)) {
|
||||
BX_DEBUG(("IN_ALIb: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
AL = BX_INP(port, 1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_AXIb(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = i->Ib();
|
||||
|
||||
if (! allow_io(i, port, 2)) {
|
||||
BX_DEBUG(("IN_AXIb: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
AX = BX_INP(port, 2);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_EAXIb(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = i->Ib();
|
||||
|
||||
if (! allow_io(i, port, 4)) {
|
||||
BX_DEBUG(("IN_EAXIb: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RAX = BX_INP(port, 4);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_IbAL(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = i->Ib();
|
||||
|
||||
if (! allow_io(i, port, 1)) {
|
||||
BX_DEBUG(("OUT_IbAL: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_OUTP(port, AL, 1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_IbAX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = i->Ib();
|
||||
|
||||
if (! allow_io(i, port, 2)) {
|
||||
BX_DEBUG(("OUT_IbAX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_OUTP(port, AX, 2);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_IbEAX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = i->Ib();
|
||||
|
||||
if (! allow_io(i, port, 4)) {
|
||||
BX_DEBUG(("OUT_IbEAX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_OUTP(port, EAX, 4);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_ALDX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = DX;
|
||||
|
||||
if (! allow_io(i, port, 1)) {
|
||||
BX_DEBUG(("IN_ALDX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
AL = BX_INP(port, 1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_AXDX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = DX;
|
||||
|
||||
if (! allow_io(i, port, 2)) {
|
||||
BX_DEBUG(("IN_AXDX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
AX = BX_INP(port, 2);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IN_EAXDX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = DX;
|
||||
|
||||
if (! allow_io(i, port, 4)) {
|
||||
BX_DEBUG(("IN_EAXDX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RAX = BX_INP(port, 4);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_DXAL(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = DX;
|
||||
|
||||
if (! allow_io(i, port, 1)) {
|
||||
BX_DEBUG(("OUT_DXAL: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_OUTP(port, AL, 1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_DXAX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = DX;
|
||||
|
||||
if (! allow_io(i, port, 2)) {
|
||||
BX_DEBUG(("OUT_DXAX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_OUTP(port, AX, 2);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OUT_DXEAX(bxInstruction_c *i)
|
||||
{
|
||||
unsigned port = DX;
|
||||
|
||||
if (! allow_io(i, port, 4)) {
|
||||
BX_DEBUG(("OUT_DXEAX: I/O access not allowed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_OUTP(port, EAX, 4);
|
||||
}
|
||||
|
||||
bx_bool BX_CPP_AttrRegparmN(3) BX_CPU_C::allow_io(bxInstruction_c *i, Bit16u port, unsigned len)
|
||||
{
|
||||
/* If CPL <= IOPL, then all IO portesses are accessible.
|
||||
* Otherwise, must check the IO permission map on >286.
|
||||
* On the 286, there is no IO permissions map */
|
||||
|
||||
if (BX_CPU_THIS_PTR cr0.get_PE() && (BX_CPU_THIS_PTR get_VM() || (CPL>BX_CPU_THIS_PTR get_IOPL())))
|
||||
{
|
||||
if (BX_CPU_THIS_PTR tr.cache.valid==0 ||
|
||||
(BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_386_TSS))
|
||||
{
|
||||
BX_ERROR(("allow_io(): TR doesn't point to a valid 32bit TSS, TR.TYPE=%u", BX_CPU_THIS_PTR tr.cache.type));
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled < 103) {
|
||||
BX_ERROR(("allow_io(): TR.limit < 103"));
|
||||
return(0);
|
||||
}
|
||||
|
||||
Bit32u io_base = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + 102);
|
||||
|
||||
if ((io_base + port/8) >= BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
|
||||
BX_DEBUG(("allow_io(): IO port %x (len %d) outside TSS IO permission map (base=%x, limit=%x) #GP(0)",
|
||||
port, len, io_base, BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled));
|
||||
return(0);
|
||||
}
|
||||
|
||||
Bit16u permission16 = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + io_base + port/8);
|
||||
|
||||
unsigned bit_index = port & 0x7;
|
||||
unsigned mask = (1 << len) - 1;
|
||||
if ((permission16 >> bit_index) & mask)
|
||||
return(0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_IO(i, port, len);
|
||||
#endif
|
||||
|
||||
#if BX_X86_DEBUGGER
|
||||
iobreakpoint_match(port, len);
|
||||
#endif
|
||||
|
||||
return(1);
|
||||
}
|
||||
564
simulators/bochs/cpu/iret.cc
Executable file
564
simulators/bochs/cpu/iret.cc
Executable file
@ -0,0 +1,564 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier merging cpu64 & cpu code.
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::iret_protected(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u raw_cs_selector, raw_ss_selector;
|
||||
bx_selector_t cs_selector, ss_selector;
|
||||
Bit32u dword1, dword2;
|
||||
bx_descriptor_t cs_descriptor, ss_descriptor;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
long_iret(i);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (BX_CPU_THIS_PTR get_NT()) /* NT = 1: RETURN FROM NESTED TASK */
|
||||
{
|
||||
/* what's the deal with NT & VM ? */
|
||||
Bit16u raw_link_selector;
|
||||
bx_selector_t link_selector;
|
||||
bx_descriptor_t tss_descriptor;
|
||||
|
||||
if (BX_CPU_THIS_PTR get_VM())
|
||||
BX_PANIC(("iret_protected: VM sholdn't be set here !"));
|
||||
|
||||
BX_DEBUG(("IRET: nested task return"));
|
||||
|
||||
if (BX_CPU_THIS_PTR tr.cache.valid==0)
|
||||
BX_PANIC(("IRET: TR not valid"));
|
||||
|
||||
// examine back link selector in TSS addressed by current TR
|
||||
raw_link_selector = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base);
|
||||
|
||||
// must specify global, else #TS(new TSS selector)
|
||||
parse_selector(raw_link_selector, &link_selector);
|
||||
|
||||
if (link_selector.ti) {
|
||||
BX_ERROR(("iret: link selector.ti=1"));
|
||||
exception(BX_TS_EXCEPTION, raw_link_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// index must be within GDT limits, else #TS(new TSS selector)
|
||||
fetch_raw_descriptor(&link_selector, &dword1, &dword2, BX_TS_EXCEPTION);
|
||||
|
||||
// AR byte must specify TSS, else #TS(new TSS selector)
|
||||
// new TSS must be busy, else #TS(new TSS selector)
|
||||
parse_descriptor(dword1, dword2, &tss_descriptor);
|
||||
if (tss_descriptor.valid==0 || tss_descriptor.segment) {
|
||||
BX_ERROR(("iret: TSS selector points to bad TSS"));
|
||||
exception(BX_TS_EXCEPTION, raw_link_selector & 0xfffc);
|
||||
}
|
||||
if (tss_descriptor.type != BX_SYS_SEGMENT_BUSY_286_TSS &&
|
||||
tss_descriptor.type != BX_SYS_SEGMENT_BUSY_386_TSS)
|
||||
{
|
||||
BX_ERROR(("iret: TSS selector points to bad TSS"));
|
||||
exception(BX_TS_EXCEPTION, raw_link_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// TSS must be present, else #NP(new TSS selector)
|
||||
if (! IS_PRESENT(tss_descriptor)) {
|
||||
BX_ERROR(("iret: task descriptor.p == 0"));
|
||||
exception(BX_NP_EXCEPTION, raw_link_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// switch tasks (without nesting) to TSS specified by back link selector
|
||||
task_switch(i, &link_selector, &tss_descriptor,
|
||||
BX_TASK_FROM_IRET, dword1, dword2);
|
||||
|
||||
// mark the task just abandoned as not busy
|
||||
|
||||
// EIP must be within code seg limit, else #GP(0)
|
||||
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("iret: EIP > CS.limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* NT = 0: INTERRUPT RETURN ON STACK -or STACK_RETURN_TO_V86 */
|
||||
unsigned top_nbytes_same;
|
||||
Bit32u new_eip = 0, new_esp, temp_ESP, new_eflags = 0;
|
||||
Bit16u new_ip = 0, new_flags = 0;
|
||||
|
||||
/* 16bit opsize | 32bit opsize
|
||||
* ==============================
|
||||
* SS eSP+8 | SS eSP+16
|
||||
* SP eSP+6 | ESP eSP+12
|
||||
* -------------------------------
|
||||
* FLAGS eSP+4 | EFLAGS eSP+8
|
||||
* CS eSP+2 | CS eSP+4
|
||||
* IP eSP+0 | EIP eSP+0
|
||||
*/
|
||||
|
||||
if (i->os32L()) {
|
||||
top_nbytes_same = 12;
|
||||
}
|
||||
else {
|
||||
top_nbytes_same = 6;
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
temp_ESP = ESP;
|
||||
else
|
||||
temp_ESP = SP;
|
||||
|
||||
if (i->os32L()) {
|
||||
new_eflags = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 8);
|
||||
raw_cs_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 4);
|
||||
new_eip = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 0);
|
||||
|
||||
// if VM=1 in flags image on stack then STACK_RETURN_TO_V86
|
||||
if (new_eflags & EFlagsVMMask) {
|
||||
if (CPL == 0) {
|
||||
stack_return_to_v86(new_eip, raw_cs_selector, new_eflags);
|
||||
return;
|
||||
}
|
||||
else BX_INFO(("iret: VM set on stack, CPL!=0"));
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_flags = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 4);
|
||||
raw_cs_selector = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 2);
|
||||
new_ip = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 0);
|
||||
}
|
||||
|
||||
parse_selector(raw_cs_selector, &cs_selector);
|
||||
|
||||
// return CS selector must be non-null, else #GP(0)
|
||||
if ((raw_cs_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("iret: return CS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// selector index must be within descriptor table limits,
|
||||
// else #GP(return selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// return CS selector RPL must be >= CPL, else #GP(return selector)
|
||||
if (cs_selector.rpl < CPL) {
|
||||
BX_ERROR(("iret: return selector RPL < CPL"));
|
||||
exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// check code-segment descriptor
|
||||
check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);
|
||||
|
||||
if (cs_selector.rpl == CPL) { /* INTERRUPT RETURN TO SAME LEVEL */
|
||||
/* top 6/12 bytes on stack must be within limits, else #SS(0) */
|
||||
/* satisfied above */
|
||||
if (i->os32L()) {
|
||||
/* load CS-cache with new code segment descriptor */
|
||||
branch_far32(&cs_selector, &cs_descriptor, new_eip, cs_selector.rpl);
|
||||
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
|
||||
EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
changeMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
|
||||
#endif
|
||||
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
if (CPL == 0)
|
||||
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
|
||||
|
||||
// IF only changed if (CPL <= EFLAGS.IOPL)
|
||||
// VIF, VIP, IOPL only changed if CPL == 0
|
||||
// VM unaffected
|
||||
writeEFlags(new_eflags, changeMask);
|
||||
}
|
||||
else {
|
||||
/* load CS-cache with new code segment descriptor */
|
||||
branch_far32(&cs_selector, &cs_descriptor, (Bit32u) new_ip, cs_selector.rpl);
|
||||
|
||||
/* load flags with third word on stack */
|
||||
write_flags(new_flags, CPL==0, CPL<=BX_CPU_THIS_PTR get_IOPL());
|
||||
}
|
||||
|
||||
/* increment stack by 6/12 */
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
ESP += top_nbytes_same;
|
||||
else
|
||||
SP += top_nbytes_same;
|
||||
return;
|
||||
}
|
||||
else { /* INTERRUPT RETURN TO OUTER PRIVILEGE LEVEL */
|
||||
|
||||
/* 16bit opsize | 32bit opsize
|
||||
* ==============================
|
||||
* SS eSP+8 | SS eSP+16
|
||||
* SP eSP+6 | ESP eSP+12
|
||||
* FLAGS eSP+4 | EFLAGS eSP+8
|
||||
* CS eSP+2 | CS eSP+4
|
||||
* IP eSP+0 | EIP eSP+0
|
||||
*/
|
||||
|
||||
/* examine return SS selector and associated descriptor */
|
||||
if (i->os32L()) {
|
||||
raw_ss_selector = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 16);
|
||||
}
|
||||
else {
|
||||
raw_ss_selector = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 8);
|
||||
}
|
||||
|
||||
/* selector must be non-null, else #GP(0) */
|
||||
if ((raw_ss_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("iret: SS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(raw_ss_selector, &ss_selector);
|
||||
|
||||
/* selector RPL must = RPL of return CS selector,
|
||||
* else #GP(SS selector) */
|
||||
if (ss_selector.rpl != cs_selector.rpl) {
|
||||
BX_ERROR(("iret: SS.rpl != CS.rpl"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* selector index must be within its descriptor table limits,
|
||||
* else #GP(SS selector) */
|
||||
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
|
||||
parse_descriptor(dword1, dword2, &ss_descriptor);
|
||||
|
||||
/* AR byte must indicate a writable data segment,
|
||||
* else #GP(SS selector) */
|
||||
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
|
||||
IS_CODE_SEGMENT(ss_descriptor.type) ||
|
||||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("iret: SS AR byte not writable or code segment"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* stack segment DPL must equal the RPL of the return CS selector,
|
||||
* else #GP(SS selector) */
|
||||
if (ss_descriptor.dpl != cs_selector.rpl) {
|
||||
BX_ERROR(("iret: SS.dpl != CS selector RPL"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* SS must be present, else #NP(SS selector) */
|
||||
if (! IS_PRESENT(ss_descriptor)) {
|
||||
BX_ERROR(("iret: SS not present!"));
|
||||
exception(BX_NP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
if (i->os32L()) {
|
||||
new_esp = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 12);
|
||||
new_eflags = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 8);
|
||||
new_eip = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP + 0);
|
||||
}
|
||||
else {
|
||||
new_esp = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 6);
|
||||
new_eflags = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 4);
|
||||
new_eip = read_virtual_word_32(BX_SEG_REG_SS, temp_ESP + 0);
|
||||
}
|
||||
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
|
||||
EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
changeMask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
|
||||
#endif
|
||||
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
if (CPL == 0)
|
||||
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
|
||||
|
||||
if (! i->os32L()) // 16 bit
|
||||
changeMask &= 0xffff;
|
||||
|
||||
/* load CS:EIP from stack */
|
||||
/* load the CS-cache with CS descriptor */
|
||||
/* set CPL to the RPL of the return CS selector */
|
||||
branch_far32(&cs_selector, &cs_descriptor, new_eip, cs_selector.rpl);
|
||||
|
||||
// IF only changed if (prev_CPL <= EFLAGS.IOPL)
|
||||
// VIF, VIP, IOPL only changed if prev_CPL == 0
|
||||
// VM unaffected
|
||||
writeEFlags(new_eflags, changeMask);
|
||||
|
||||
// load SS:eSP from stack
|
||||
// load the SS-cache with SS descriptor
|
||||
load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);
|
||||
if (ss_descriptor.u.segment.d_b)
|
||||
ESP = new_esp;
|
||||
else
|
||||
SP = new_esp;
|
||||
|
||||
validate_seg_regs();
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::long_iret(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u raw_cs_selector, raw_ss_selector;
|
||||
bx_selector_t cs_selector, ss_selector;
|
||||
Bit32u dword1, dword2;
|
||||
bx_descriptor_t cs_descriptor, ss_descriptor;
|
||||
Bit32u new_eflags;
|
||||
Bit64u new_rip, new_rsp, temp_RSP;
|
||||
|
||||
BX_DEBUG (("LONG MODE IRET"));
|
||||
|
||||
if (BX_CPU_THIS_PTR get_NT()) {
|
||||
BX_ERROR(("iret64: return from nested task in x86-64 mode !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* 64bit opsize
|
||||
* ============
|
||||
* SS eSP+32
|
||||
* ESP eSP+24
|
||||
* -------------
|
||||
* EFLAGS eSP+16
|
||||
* CS eSP+8
|
||||
* EIP eSP+0
|
||||
*/
|
||||
|
||||
if (StackAddrSize64()) temp_RSP = RSP;
|
||||
else {
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) temp_RSP = ESP;
|
||||
else temp_RSP = SP;
|
||||
}
|
||||
|
||||
unsigned top_nbytes_same = 0; /* stop compiler warnings */
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
new_eflags = (Bit32u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 16);
|
||||
raw_cs_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 8);
|
||||
new_rip = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 0);
|
||||
top_nbytes_same = 24;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->os32L()) {
|
||||
new_eflags = read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 8);
|
||||
raw_cs_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 4);
|
||||
new_rip = (Bit64u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 0);
|
||||
top_nbytes_same = 12;
|
||||
}
|
||||
else {
|
||||
new_eflags = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 4);
|
||||
raw_cs_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 2);
|
||||
new_rip = (Bit64u) read_virtual_word(BX_SEG_REG_SS, temp_RSP + 0);
|
||||
top_nbytes_same = 6;
|
||||
}
|
||||
|
||||
// ignore VM flag in long mode
|
||||
new_eflags &= ~EFlagsVMMask;
|
||||
|
||||
parse_selector(raw_cs_selector, &cs_selector);
|
||||
|
||||
// return CS selector must be non-null, else #GP(0)
|
||||
if ((raw_cs_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("iret64: return CS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// selector index must be within descriptor table limits,
|
||||
// else #GP(return selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// return CS selector RPL must be >= CPL, else #GP(return selector)
|
||||
if (cs_selector.rpl < CPL) {
|
||||
BX_ERROR(("iret64: return selector RPL < CPL"));
|
||||
exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// check code-segment descriptor
|
||||
check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);
|
||||
|
||||
/* INTERRUPT RETURN TO SAME PRIVILEGE LEVEL */
|
||||
if (cs_selector.rpl == CPL && !i->os64L())
|
||||
{
|
||||
/* top 24 bytes on stack must be within limits, else #SS(0) */
|
||||
/* satisfied above */
|
||||
|
||||
/* load CS:EIP from stack */
|
||||
/* load CS-cache with new code segment descriptor */
|
||||
if(cs_descriptor.u.segment.l) {
|
||||
branch_far64(&cs_selector, &cs_descriptor, new_rip, CPL);
|
||||
}
|
||||
else {
|
||||
branch_far32(&cs_selector, &cs_descriptor, (Bit32u) new_rip, CPL);
|
||||
}
|
||||
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask |
|
||||
EFlagsNTMask | EFlagsRFMask | EFlagsIDMask | EFlagsACMask;
|
||||
if (CPL <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
if (CPL == 0)
|
||||
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
|
||||
|
||||
if (! i->os32L()) // 16 bit
|
||||
changeMask &= 0xffff;
|
||||
|
||||
// IF only changed if (CPL <= EFLAGS.IOPL)
|
||||
// VIF, VIP, IOPL only changed if CPL == 0
|
||||
// VM unaffected
|
||||
writeEFlags(new_eflags, changeMask);
|
||||
|
||||
/* we are NOT in 64-bit mode */
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
ESP += top_nbytes_same;
|
||||
else
|
||||
SP += top_nbytes_same;
|
||||
}
|
||||
else { /* INTERRUPT RETURN TO OUTER PRIVILEGE LEVEL or 64 BIT MODE */
|
||||
/* 64bit opsize
|
||||
* ============
|
||||
* SS eSP+32
|
||||
* ESP eSP+24
|
||||
* EFLAGS eSP+16
|
||||
* CS eSP+8
|
||||
* EIP eSP+0
|
||||
*/
|
||||
|
||||
/* examine return SS selector and associated descriptor */
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
raw_ss_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 32);
|
||||
new_rsp = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 24);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (i->os32L()) {
|
||||
raw_ss_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 16);
|
||||
new_rsp = (Bit64u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 12);
|
||||
}
|
||||
else {
|
||||
raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 8);
|
||||
new_rsp = (Bit64u) read_virtual_word(BX_SEG_REG_SS, temp_RSP + 6);
|
||||
}
|
||||
}
|
||||
|
||||
if ((raw_ss_selector & 0xfffc) == 0) {
|
||||
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_selector.rpl == 3) {
|
||||
BX_ERROR(("iret64: SS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
parse_selector(raw_ss_selector, &ss_selector);
|
||||
|
||||
/* selector RPL must = RPL of return CS selector,
|
||||
* else #GP(SS selector) */
|
||||
if (ss_selector.rpl != cs_selector.rpl) {
|
||||
BX_ERROR(("iret64: SS.rpl != CS.rpl"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* selector index must be within its descriptor table limits,
|
||||
* else #GP(SS selector) */
|
||||
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &ss_descriptor);
|
||||
|
||||
/* AR byte must indicate a writable data segment,
|
||||
* else #GP(SS selector) */
|
||||
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
|
||||
IS_CODE_SEGMENT(ss_descriptor.type) ||
|
||||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("iret64: SS AR byte not writable or code segment"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* stack segment DPL must equal the RPL of the return CS selector,
|
||||
* else #GP(SS selector) */
|
||||
if (ss_descriptor.dpl != cs_selector.rpl) {
|
||||
BX_ERROR(("iret64: SS.dpl != CS selector RPL"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* SS must be present, else #NP(SS selector) */
|
||||
if (! IS_PRESENT(ss_descriptor)) {
|
||||
BX_ERROR(("iret64: SS not present!"));
|
||||
exception(BX_NP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
Bit8u prev_cpl = CPL; /* previous CPL */
|
||||
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsDFMask |
|
||||
EFlagsNTMask | EFlagsRFMask | EFlagsIDMask | EFlagsACMask;
|
||||
if (prev_cpl <= BX_CPU_THIS_PTR get_IOPL())
|
||||
changeMask |= EFlagsIFMask;
|
||||
if (prev_cpl == 0)
|
||||
changeMask |= EFlagsVIPMask | EFlagsVIFMask | EFlagsIOPLMask;
|
||||
|
||||
if (! i->os32L()) // 16 bit
|
||||
changeMask &= 0xffff;
|
||||
|
||||
/* set CPL to the RPL of the return CS selector */
|
||||
branch_far64(&cs_selector, &cs_descriptor, new_rip, cs_selector.rpl);
|
||||
|
||||
// IF only changed if (prev_CPL <= EFLAGS.IOPL)
|
||||
// VIF, VIP, IOPL only changed if prev_CPL == 0
|
||||
// VM unaffected
|
||||
writeEFlags(new_eflags, changeMask);
|
||||
|
||||
if ((raw_ss_selector & 0xfffc) != 0) {
|
||||
// load SS:RSP from stack
|
||||
// load the SS-cache with SS descriptor
|
||||
load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);
|
||||
}
|
||||
else {
|
||||
// we are in 64-bit mode !
|
||||
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], raw_ss_selector);
|
||||
}
|
||||
|
||||
if (StackAddrSize64()) RSP = new_rsp;
|
||||
else {
|
||||
if (ss_descriptor.u.segment.d_b) ESP = (Bit32u) new_rsp;
|
||||
else SP = (Bit16u) new_rsp;
|
||||
}
|
||||
|
||||
if (prev_cpl != CPL) validate_seg_regs();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
292
simulators/bochs/cpu/jmp_far.cc
Executable file
292
simulators/bochs/cpu/jmp_far.cc
Executable file
@ -0,0 +1,292 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-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 B 02110-1301 USA
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier merging cpu64 & cpu code.
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::jump_protected(bxInstruction_c *i, Bit16u cs_raw, bx_address disp)
|
||||
{
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
/* destination selector is not null else #GP(0) */
|
||||
if ((cs_raw & 0xfffc) == 0) {
|
||||
BX_ERROR(("jump_protected: cs == 0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(cs_raw, &selector);
|
||||
|
||||
/* destination selector index is within its descriptor table
|
||||
limits else #GP(selector) */
|
||||
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
|
||||
/* examine AR byte of destination selector for legal values: */
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
if (descriptor.segment) {
|
||||
check_cs(&descriptor, cs_raw, BX_SELECTOR_RPL(cs_raw), CPL);
|
||||
branch_far64(&selector, &descriptor, disp, CPL);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// call gate DPL must be >= CPL else #GP(gate selector)
|
||||
if (descriptor.dpl < CPL) {
|
||||
BX_ERROR(("jump_protected: call gate.dpl < CPL"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
// call gate DPL must be >= gate selector RPL else #GP(gate selector)
|
||||
if (descriptor.dpl < selector.rpl) {
|
||||
BX_ERROR(("jump_protected: call gate.dpl < selector.rpl"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
if (descriptor.type != BX_386_CALL_GATE) {
|
||||
BX_ERROR(("jump_protected: gate type %u unsupported in long mode", (unsigned) descriptor.type));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
// gate must be present else #NP(gate selector)
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("jump_protected: call gate not present!"));
|
||||
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
jmp_call_gate64(&selector);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (descriptor.type) {
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
|
||||
if (descriptor.type==BX_SYS_SEGMENT_AVAIL_286_TSS)
|
||||
BX_DEBUG(("jump_protected: jump to 286 TSS"));
|
||||
else
|
||||
BX_DEBUG(("jump_protected: jump to 386 TSS"));
|
||||
|
||||
if (descriptor.valid==0 || selector.ti) {
|
||||
BX_ERROR(("jump_protected: jump to bad TSS selector !"));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
// TSS must be present, else #NP(TSS selector)
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("jump_protected: jump to not present TSS !"));
|
||||
exception(BX_NP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
|
||||
// SWITCH_TASKS _without_ nesting to TSS
|
||||
task_switch(i, &selector, &descriptor, BX_TASK_FROM_JUMP, dword1, dword2);
|
||||
|
||||
// EIP must be in code seg limit, else #GP(0)
|
||||
if (EIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("jump_protected: EIP not within CS limits"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
return;
|
||||
|
||||
case BX_TASK_GATE:
|
||||
task_gate(i, &selector, &descriptor, BX_TASK_FROM_JUMP);
|
||||
return;
|
||||
|
||||
case BX_286_CALL_GATE:
|
||||
case BX_386_CALL_GATE:
|
||||
jmp_call_gate(&selector, &descriptor);
|
||||
return;
|
||||
|
||||
default:
|
||||
BX_ERROR(("jump_protected: gate type %u unsupported", (unsigned) descriptor.type));
|
||||
exception(BX_GP_EXCEPTION, cs_raw & 0xfffc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPU_C::task_gate(bxInstruction_c *i, bx_selector_t *selector, bx_descriptor_t *gate_descriptor, unsigned source)
|
||||
{
|
||||
Bit16u raw_tss_selector;
|
||||
bx_selector_t tss_selector;
|
||||
bx_descriptor_t tss_descriptor;
|
||||
Bit32u dword1, dword2;
|
||||
Bit32u temp_eIP;
|
||||
|
||||
// task gate must be present else #NP(gate selector)
|
||||
if (! gate_descriptor->p) {
|
||||
BX_ERROR(("task_gate: task gate not present"));
|
||||
exception(BX_NP_EXCEPTION, selector->value & 0xfffc);
|
||||
}
|
||||
|
||||
// examine selector to TSS, given in Task Gate descriptor
|
||||
// must specify global in the local/global bit else #GP(TSS selector)
|
||||
raw_tss_selector = gate_descriptor->u.taskgate.tss_selector;
|
||||
parse_selector(raw_tss_selector, &tss_selector);
|
||||
|
||||
if (tss_selector.ti) {
|
||||
BX_ERROR(("task_gate: tss_selector.ti=1"));
|
||||
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// index must be within GDT limits else #GP(TSS selector)
|
||||
fetch_raw_descriptor(&tss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
|
||||
// descriptor AR byte must specify available TSS
|
||||
// else #GP(TSS selector)
|
||||
parse_descriptor(dword1, dword2, &tss_descriptor);
|
||||
|
||||
if (tss_descriptor.valid==0 || tss_descriptor.segment) {
|
||||
BX_ERROR(("task_gate: TSS selector points to bad TSS"));
|
||||
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
if (tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
|
||||
tss_descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS)
|
||||
{
|
||||
BX_ERROR(("task_gate: TSS selector points to bad TSS"));
|
||||
exception(BX_GP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// task state segment must be present, else #NP(tss selector)
|
||||
if (! IS_PRESENT(tss_descriptor)) {
|
||||
BX_ERROR(("task_gate: TSS descriptor.p == 0"));
|
||||
exception(BX_NP_EXCEPTION, raw_tss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// SWITCH_TASKS _without_ nesting to TSS
|
||||
task_switch(i, &tss_selector, &tss_descriptor, source, dword1, dword2);
|
||||
|
||||
// EIP must be within code segment limit, else #GP(0)
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b)
|
||||
temp_eIP = EIP;
|
||||
else
|
||||
temp_eIP = IP;
|
||||
|
||||
if (temp_eIP > BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("task_gate: EIP > CS.limit"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::jmp_call_gate(bx_selector_t *selector, bx_descriptor_t *gate_descriptor)
|
||||
{
|
||||
bx_selector_t gate_cs_selector;
|
||||
bx_descriptor_t gate_cs_descriptor;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
if (gate_descriptor->type==BX_286_CALL_GATE)
|
||||
BX_DEBUG(("jmp_call_gate: jump to 286 CALL GATE"));
|
||||
else
|
||||
BX_DEBUG(("jmp_call_gate: jump to 386 CALL GATE"));
|
||||
|
||||
// task gate must be present else #NP(gate selector)
|
||||
if (! gate_descriptor->p) {
|
||||
BX_ERROR(("jmp_call_gate: call gate not present!"));
|
||||
exception(BX_NP_EXCEPTION, selector->value & 0xfffc);
|
||||
}
|
||||
|
||||
// examine selector to code segment given in call gate descriptor
|
||||
// selector must not be null, else #GP(0)
|
||||
Bit16u gate_cs_raw = gate_descriptor->u.gate.dest_selector;
|
||||
|
||||
if ((gate_cs_raw & 0xfffc) == 0) {
|
||||
BX_ERROR(("jmp_call_gate: CS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(gate_cs_raw, &gate_cs_selector);
|
||||
// selector must be within its descriptor table limits else #GP(CS selector)
|
||||
fetch_raw_descriptor(&gate_cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &gate_cs_descriptor);
|
||||
|
||||
// check code-segment descriptor
|
||||
check_cs(&gate_cs_descriptor, gate_cs_raw, 0, CPL);
|
||||
|
||||
Bit32u temp_EIP = gate_descriptor->u.gate.dest_offset;
|
||||
branch_far32(&gate_cs_selector, &gate_cs_descriptor, temp_EIP, CPL);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::jmp_call_gate64(bx_selector_t *gate_selector)
|
||||
{
|
||||
bx_selector_t cs_selector;
|
||||
Bit32u dword1, dword2, dword3;
|
||||
bx_descriptor_t cs_descriptor;
|
||||
bx_descriptor_t gate_descriptor;
|
||||
|
||||
BX_DEBUG(("jmp_call_gate64: jump to CALL GATE 64"));
|
||||
|
||||
fetch_raw_descriptor_64(gate_selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &gate_descriptor);
|
||||
|
||||
Bit16u dest_selector = gate_descriptor.u.gate.dest_selector;
|
||||
// selector must not be null else #GP(0)
|
||||
if ((dest_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("jmp_call_gate64: selector in gate null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(dest_selector, &cs_selector);
|
||||
// selector must be within its descriptor table limits,
|
||||
// else #GP(code segment selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// find the RIP in the gate_descriptor
|
||||
Bit64u new_RIP = gate_descriptor.u.gate.dest_offset;
|
||||
new_RIP |= ((Bit64u)dword3 << 32);
|
||||
|
||||
// AR byte of selected descriptor must indicate code segment,
|
||||
// else #GP(code segment selector)
|
||||
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
|
||||
IS_DATA_SEGMENT(cs_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("jmp_call_gate64: not code segment in 64-bit call gate"));
|
||||
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// In long mode, only 64-bit call gates are allowed, and they must point
|
||||
// to 64-bit code segments, else #GP(selector)
|
||||
if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b)
|
||||
{
|
||||
BX_ERROR(("jmp_call_gate64: not 64-bit code segment in 64-bit call gate"));
|
||||
exception(BX_GP_EXCEPTION, dest_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// check code-segment descriptor
|
||||
check_cs(&cs_descriptor, dest_selector, 0, CPL);
|
||||
// and transfer the control
|
||||
branch_far64(&cs_selector, &cs_descriptor, new_RIP, CPL);
|
||||
}
|
||||
#endif
|
||||
299
simulators/bochs/cpu/lazy_flags.cc
Normal file
299
simulators/bochs/cpu/lazy_flags.cc
Normal file
@ -0,0 +1,299 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// This array defines a look-up table for the even parity-ness
|
||||
// of an 8bit quantity, for optimal assignment of the parity bit
|
||||
// in the EFLAGS register
|
||||
const Bit8u bx_parity_lookup[256] = {
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
|
||||
};
|
||||
|
||||
#define op1_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.op1))
|
||||
#define op2_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.op2))
|
||||
#define result_8 ((Bit8u)(BX_CPU_THIS_PTR oszapc.result))
|
||||
|
||||
#define op1_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.op1))
|
||||
#define op2_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.op2))
|
||||
#define result_16 ((Bit16u)(BX_CPU_THIS_PTR oszapc.result))
|
||||
|
||||
#define op1_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.op1))
|
||||
#define op2_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.op2))
|
||||
#define result_32 ((Bit32u)(BX_CPU_THIS_PTR oszapc.result))
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define op1_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.op1))
|
||||
#define op2_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.op2))
|
||||
#define result_64 ((Bit64u)(BX_CPU_THIS_PTR oszapc.result))
|
||||
#endif
|
||||
|
||||
bx_bool BX_CPU_C::get_CFLazy(void)
|
||||
{
|
||||
unsigned cf;
|
||||
|
||||
switch (BX_CPU_THIS_PTR oszapc.instr) {
|
||||
case BX_LF_INSTR_ADD8:
|
||||
case BX_LF_INSTR_ADD16:
|
||||
case BX_LF_INSTR_ADD32:
|
||||
cf = (result_32 < op1_32);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_ADD64:
|
||||
cf = (result_64 < op1_64);
|
||||
break;
|
||||
#endif
|
||||
// used only if CF = 1 when executing ADC instruction
|
||||
case BX_LF_INSTR_ADC8:
|
||||
case BX_LF_INSTR_ADC16:
|
||||
case BX_LF_INSTR_ADC32:
|
||||
cf = (result_32 <= op1_32);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
// used only if CF = 1 when executing ADC instruction
|
||||
case BX_LF_INSTR_ADC64:
|
||||
cf = (result_64 <= op1_64);
|
||||
break;
|
||||
#endif
|
||||
case BX_LF_INSTR_SUB8:
|
||||
case BX_LF_INSTR_SUB16:
|
||||
case BX_LF_INSTR_SUB32:
|
||||
cf = (op1_32 < op2_32);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_SUB64:
|
||||
cf = (op1_64 < op2_64);
|
||||
break;
|
||||
#endif
|
||||
// used only if CF = 1 when executing SBB instruction
|
||||
case BX_LF_INSTR_SBB8:
|
||||
cf = (op1_8 < result_8) || (op2_8==0xff);
|
||||
break;
|
||||
// used only if CF = 1 when executing SBB instruction
|
||||
case BX_LF_INSTR_SBB16:
|
||||
cf = (op1_16 < result_16) || (op2_16==0xffff);
|
||||
break;
|
||||
// used only if CF = 1 when executing SBB instruction
|
||||
case BX_LF_INSTR_SBB32:
|
||||
cf = (op1_32 < result_32) || (op2_32==0xffffffff);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
// used only if CF = 1 when executing SBB instruction
|
||||
case BX_LF_INSTR_SBB64:
|
||||
cf = (op1_64 < result_64) || (op2_64==BX_CONST64(0xffffffffffffffff));
|
||||
break;
|
||||
#endif
|
||||
case BX_LF_INSTR_NEG8:
|
||||
case BX_LF_INSTR_NEG16:
|
||||
case BX_LF_INSTR_NEG32:
|
||||
cf = (result_32 != 0);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_NEG64:
|
||||
cf = (result_64 != 0);
|
||||
break;
|
||||
#endif
|
||||
case BX_LF_INSTR_LOGIC8:
|
||||
case BX_LF_INSTR_LOGIC16:
|
||||
case BX_LF_INSTR_LOGIC32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_LOGIC64:
|
||||
#endif
|
||||
cf = 0;
|
||||
break;
|
||||
default:
|
||||
cf = 0; // Keep compiler quiet.
|
||||
BX_PANIC(("get_CF: OSZAPC: unknown instr %u",
|
||||
(unsigned) BX_CPU_THIS_PTR oszapc.instr));
|
||||
}
|
||||
|
||||
return(cf);
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::get_AFLazy(void)
|
||||
{
|
||||
unsigned af;
|
||||
|
||||
switch (BX_CPU_THIS_PTR oszapc.instr) {
|
||||
case BX_LF_INSTR_ADD8:
|
||||
case BX_LF_INSTR_ADC8:
|
||||
case BX_LF_INSTR_SUB8:
|
||||
case BX_LF_INSTR_SBB8:
|
||||
case BX_LF_INSTR_ADD16:
|
||||
case BX_LF_INSTR_ADC16:
|
||||
case BX_LF_INSTR_SUB16:
|
||||
case BX_LF_INSTR_SBB16:
|
||||
case BX_LF_INSTR_ADD32:
|
||||
case BX_LF_INSTR_ADC32:
|
||||
case BX_LF_INSTR_SUB32:
|
||||
case BX_LF_INSTR_SBB32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_ADD64:
|
||||
case BX_LF_INSTR_ADC64:
|
||||
case BX_LF_INSTR_SUB64:
|
||||
case BX_LF_INSTR_SBB64:
|
||||
#endif
|
||||
af = ((op1_8 ^ op2_8) ^ result_8) & 0x10;
|
||||
break;
|
||||
case BX_LF_INSTR_NEG8:
|
||||
case BX_LF_INSTR_NEG16:
|
||||
case BX_LF_INSTR_NEG32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_NEG64:
|
||||
#endif
|
||||
af = (result_8 & 0xf) != 0;
|
||||
break;
|
||||
case BX_LF_INSTR_INC8:
|
||||
case BX_LF_INSTR_INC16:
|
||||
case BX_LF_INSTR_INC32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_INC64:
|
||||
#endif
|
||||
af = (result_8 & 0xf) == 0;
|
||||
break;
|
||||
case BX_LF_INSTR_DEC8:
|
||||
case BX_LF_INSTR_DEC16:
|
||||
case BX_LF_INSTR_DEC32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_DEC64:
|
||||
#endif
|
||||
af = (result_8 & 0xf) == 0xf;
|
||||
break;
|
||||
case BX_LF_INSTR_LOGIC8:
|
||||
case BX_LF_INSTR_LOGIC16:
|
||||
case BX_LF_INSTR_LOGIC32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_LOGIC64:
|
||||
#endif
|
||||
af = 0;
|
||||
break;
|
||||
default:
|
||||
af = 0; // Keep compiler quiet.
|
||||
BX_PANIC(("get_AF: OSZAPC: unknown instr %u", (unsigned) BX_CPU_THIS_PTR oszapc.instr));
|
||||
}
|
||||
|
||||
return(af);
|
||||
}
|
||||
|
||||
#define GET_ADD_OVERFLOW(op1, op2, result, mask) \
|
||||
(((((op1) ^ (result)) & ((op2) ^ (result))) & (mask)) != 0)
|
||||
|
||||
#define GET_SUB_OVERFLOW(op1, op2, result, mask) \
|
||||
(((((op1) ^ (op2)) & ((op1) ^ (result))) & (mask)) != 0)
|
||||
|
||||
bx_bool BX_CPU_C::get_OFLazy(void)
|
||||
{
|
||||
unsigned of;
|
||||
|
||||
switch (BX_CPU_THIS_PTR oszapc.instr) {
|
||||
case BX_LF_INSTR_ADD8:
|
||||
case BX_LF_INSTR_ADC8:
|
||||
case BX_LF_INSTR_ADD16:
|
||||
case BX_LF_INSTR_ADC16:
|
||||
case BX_LF_INSTR_ADD32:
|
||||
case BX_LF_INSTR_ADC32:
|
||||
of = GET_ADD_OVERFLOW(op1_32, op2_32, result_32, 0x80000000);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_ADD64:
|
||||
case BX_LF_INSTR_ADC64:
|
||||
of = GET_ADD_OVERFLOW(op1_64, op2_64, result_64, BX_CONST64(0x8000000000000000));
|
||||
break;
|
||||
#endif
|
||||
case BX_LF_INSTR_SUB8:
|
||||
case BX_LF_INSTR_SBB8:
|
||||
case BX_LF_INSTR_SUB16:
|
||||
case BX_LF_INSTR_SBB16:
|
||||
case BX_LF_INSTR_SUB32:
|
||||
case BX_LF_INSTR_SBB32:
|
||||
of = GET_SUB_OVERFLOW(op1_32, op2_32, result_32, 0x80000000);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_SUB64:
|
||||
case BX_LF_INSTR_SBB64:
|
||||
of = GET_SUB_OVERFLOW(op1_64, op2_64, result_64, BX_CONST64(0x8000000000000000));
|
||||
break;
|
||||
#endif
|
||||
case BX_LF_INSTR_LOGIC8:
|
||||
case BX_LF_INSTR_LOGIC16:
|
||||
case BX_LF_INSTR_LOGIC32:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_LOGIC64:
|
||||
#endif
|
||||
of = 0;
|
||||
break;
|
||||
case BX_LF_INSTR_NEG8:
|
||||
case BX_LF_INSTR_INC8:
|
||||
of = (result_8 == 0x80);
|
||||
break;
|
||||
case BX_LF_INSTR_NEG16:
|
||||
case BX_LF_INSTR_INC16:
|
||||
of = (result_16 == 0x8000);
|
||||
break;
|
||||
case BX_LF_INSTR_NEG32:
|
||||
case BX_LF_INSTR_INC32:
|
||||
of = (result_32 == 0x80000000);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_NEG64:
|
||||
case BX_LF_INSTR_INC64:
|
||||
of = (result_64 == BX_CONST64(0x8000000000000000));
|
||||
break;
|
||||
#endif
|
||||
case BX_LF_INSTR_DEC8:
|
||||
of = (result_8 == 0x7F);
|
||||
break;
|
||||
case BX_LF_INSTR_DEC16:
|
||||
of = (result_16 == 0x7FFF);
|
||||
break;
|
||||
case BX_LF_INSTR_DEC32:
|
||||
of = (result_32 == 0x7FFFFFFF);
|
||||
break;
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_LF_INSTR_DEC64:
|
||||
of = (result_64 == BX_CONST64(0x7FFFFFFFFFFFFFFF));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
of = 0; // Keep compiler happy.
|
||||
BX_PANIC(("get_OF: OSZAPC: unknown instr"));
|
||||
}
|
||||
|
||||
return(of);
|
||||
}
|
||||
254
simulators/bochs/cpu/lazy_flags.h
Normal file
254
simulators/bochs/cpu/lazy_flags.h
Normal file
@ -0,0 +1,254 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_LAZY_FLAGS_DEF
|
||||
#define BX_LAZY_FLAGS_DEF
|
||||
|
||||
#define BX_LF_INSTR_ADD8 1
|
||||
#define BX_LF_INSTR_ADC8 2
|
||||
|
||||
#define BX_LF_INSTR_ADD16 3
|
||||
#define BX_LF_INSTR_ADC16 4
|
||||
|
||||
#define BX_LF_INSTR_ADD32 5
|
||||
#define BX_LF_INSTR_ADC32 6
|
||||
|
||||
#define BX_LF_INSTR_ADD64 7
|
||||
#define BX_LF_INSTR_ADC64 8
|
||||
|
||||
#define BX_LF_INSTR_ADD_ADC8(cf) (1 + (cf))
|
||||
#define BX_LF_INSTR_ADD_ADC16(cf) (3 + (cf))
|
||||
#define BX_LF_INSTR_ADD_ADC32(cf) (5 + (cf))
|
||||
#define BX_LF_INSTR_ADD_ADC64(cf) (7 + (cf))
|
||||
|
||||
#define BX_LF_INSTR_SUB8 9
|
||||
#define BX_LF_INSTR_SBB8 10
|
||||
|
||||
#define BX_LF_INSTR_SUB16 11
|
||||
#define BX_LF_INSTR_SBB16 12
|
||||
|
||||
#define BX_LF_INSTR_SUB32 13
|
||||
#define BX_LF_INSTR_SBB32 14
|
||||
|
||||
#define BX_LF_INSTR_SUB64 15
|
||||
#define BX_LF_INSTR_SBB64 16
|
||||
|
||||
#define BX_LF_INSTR_SUB_SBB8(cf) (9 + (cf))
|
||||
#define BX_LF_INSTR_SUB_SBB16(cf) (11 + (cf))
|
||||
#define BX_LF_INSTR_SUB_SBB32(cf) (13 + (cf))
|
||||
#define BX_LF_INSTR_SUB_SBB64(cf) (15 + (cf))
|
||||
|
||||
#define BX_LF_INSTR_INC8 17
|
||||
#define BX_LF_INSTR_INC16 18
|
||||
#define BX_LF_INSTR_INC32 19
|
||||
#define BX_LF_INSTR_INC64 20
|
||||
|
||||
#define BX_LF_INSTR_DEC8 21
|
||||
#define BX_LF_INSTR_DEC16 22
|
||||
#define BX_LF_INSTR_DEC32 23
|
||||
#define BX_LF_INSTR_DEC64 24
|
||||
|
||||
#define BX_LF_INSTR_NEG8 25
|
||||
#define BX_LF_INSTR_NEG16 26
|
||||
#define BX_LF_INSTR_NEG32 27
|
||||
#define BX_LF_INSTR_NEG64 28
|
||||
|
||||
#define BX_LF_INSTR_LOGIC8 29
|
||||
#define BX_LF_INSTR_LOGIC16 30
|
||||
#define BX_LF_INSTR_LOGIC32 31
|
||||
#define BX_LF_INSTR_LOGIC64 32
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define BX_LF_SIGN_BIT 63
|
||||
#else
|
||||
#define BX_LF_SIGN_BIT 31
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
bx_address op1;
|
||||
bx_address op2;
|
||||
bx_address result;
|
||||
unsigned instr;
|
||||
} bx_lf_flags_entry;
|
||||
|
||||
// *******************
|
||||
// OSZAPC
|
||||
// *******************
|
||||
|
||||
/* op1, op2, result */
|
||||
#define SET_FLAGS_OSZAPC_SIZE(size, lf_op1, lf_op2, lf_result, ins) { \
|
||||
BX_CPU_THIS_PTR oszapc.op1 = (bx_address)(Bit##size##s)(lf_op1); \
|
||||
BX_CPU_THIS_PTR oszapc.op2 = (bx_address)(Bit##size##s)(lf_op2); \
|
||||
BX_CPU_THIS_PTR oszapc.result = (bx_address)(Bit##size##s)(lf_result); \
|
||||
BX_CPU_THIS_PTR oszapc.instr = (ins); \
|
||||
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
|
||||
}
|
||||
|
||||
#define SET_FLAGS_OSZAPC_8(op1, op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_SIZE(8, op1, op2, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_16(op1, op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_SIZE(16, op1, op2, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_32(op1, op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_SIZE(32, op1, op2, result, ins)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_64(op1, op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_SIZE(64, op1, op2, result, ins)
|
||||
#endif
|
||||
|
||||
/* op1 and result only */
|
||||
#define SET_FLAGS_OSZAPC_S1_SIZE(size, lf_op1, lf_result, ins) { \
|
||||
BX_CPU_THIS_PTR oszapc.op1 = (bx_address)(Bit##size##s)(lf_op1); \
|
||||
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
|
||||
BX_CPU_THIS_PTR oszapc.instr = (ins); \
|
||||
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
|
||||
}
|
||||
|
||||
#define SET_FLAGS_OSZAPC_S1_8(op1, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S1_SIZE(8, op1, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_S1_16(op1, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S1_SIZE(16, op1, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_S1_32(op1, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S1_SIZE(32, op1, result, ins)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_S1_64(op1, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S1_SIZE(64, op1, result, ins)
|
||||
#endif
|
||||
|
||||
/* op2 and result only */
|
||||
#define SET_FLAGS_OSZAPC_S2_SIZE(size, lf_op2, lf_result, ins) { \
|
||||
BX_CPU_THIS_PTR oszapc.op2 = (bx_address)(Bit##size##s)(lf_op2); \
|
||||
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
|
||||
BX_CPU_THIS_PTR oszapc.instr = (ins); \
|
||||
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
|
||||
}
|
||||
|
||||
#define SET_FLAGS_OSZAPC_S2_8(op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S2_SIZE(8, op2, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_S2_16(op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S2_SIZE(16, op2, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_S2_32(op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S2_SIZE(32, op2, result, ins)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_S2_64(op2, result, ins) \
|
||||
SET_FLAGS_OSZAPC_S2_SIZE(64, op2, result, ins)
|
||||
#endif
|
||||
|
||||
/* result only */
|
||||
#define SET_FLAGS_OSZAPC_RESULT_SIZE(size, lf_result, ins) { \
|
||||
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
|
||||
BX_CPU_THIS_PTR oszapc.instr = (ins); \
|
||||
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPCMask; \
|
||||
}
|
||||
|
||||
#define SET_FLAGS_OSZAPC_RESULT_8(result, ins) \
|
||||
SET_FLAGS_OSZAPC_RESULT_SIZE(8, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_RESULT_16(result, ins) \
|
||||
SET_FLAGS_OSZAPC_RESULT_SIZE(16, result, ins)
|
||||
#define SET_FLAGS_OSZAPC_RESULT_32(result, ins) \
|
||||
SET_FLAGS_OSZAPC_RESULT_SIZE(32, result, ins)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_RESULT_64(result, ins) \
|
||||
SET_FLAGS_OSZAPC_RESULT_SIZE(64, result, ins)
|
||||
#endif
|
||||
|
||||
// *******************
|
||||
// OSZAP
|
||||
// *******************
|
||||
|
||||
/* result only */
|
||||
#define SET_FLAGS_OSZAP_RESULT_SIZE(size, lf_result, ins) { \
|
||||
force_CF(); \
|
||||
BX_CPU_THIS_PTR oszapc.result = (Bit##size##s)(lf_result); \
|
||||
BX_CPU_THIS_PTR oszapc.instr = (ins); \
|
||||
BX_CPU_THIS_PTR lf_flags_status = EFlagsOSZAPMask; \
|
||||
}
|
||||
|
||||
#define SET_FLAGS_OSZAP_RESULT_8(result, ins) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(8, result, ins)
|
||||
#define SET_FLAGS_OSZAP_RESULT_16(result, ins) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(16, result, ins)
|
||||
#define SET_FLAGS_OSZAP_RESULT_32(result, ins) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(32, result, ins)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAP_RESULT_64(result, ins) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(64, result, ins)
|
||||
#endif
|
||||
|
||||
// transition to new lazy flags code
|
||||
#define SET_FLAGS_OSZAPC_LOGIC_8(result_8) \
|
||||
SET_FLAGS_OSZAPC_RESULT_8((result_8), BX_LF_INSTR_LOGIC8)
|
||||
#define SET_FLAGS_OSZAPC_LOGIC_16(result_16) \
|
||||
SET_FLAGS_OSZAPC_RESULT_16((result_16), BX_LF_INSTR_LOGIC16)
|
||||
#define SET_FLAGS_OSZAPC_LOGIC_32(result_32) \
|
||||
SET_FLAGS_OSZAPC_RESULT_32((result_32), BX_LF_INSTR_LOGIC32)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_LOGIC_64(result_64) \
|
||||
SET_FLAGS_OSZAPC_RESULT_64((result_64), BX_LF_INSTR_LOGIC64)
|
||||
#endif
|
||||
|
||||
#define SET_FLAGS_OSZAPC_ADD_8(op1_8, op2_8, sum_8) \
|
||||
SET_FLAGS_OSZAPC_8((op1_8), (op2_8), (sum_8), BX_LF_INSTR_ADD8)
|
||||
#define SET_FLAGS_OSZAPC_ADD_16(op1_16, op2_16, sum_16) \
|
||||
SET_FLAGS_OSZAPC_16((op1_16), (op2_16), (sum_16), BX_LF_INSTR_ADD16)
|
||||
#define SET_FLAGS_OSZAPC_ADD_32(op1_32, op2_32, sum_32) \
|
||||
SET_FLAGS_OSZAPC_32((op1_32), (op2_32), (sum_32), BX_LF_INSTR_ADD32)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_ADD_64(op1_64, op2_64, sum_64) \
|
||||
SET_FLAGS_OSZAPC_64((op1_64), (op2_64), (sum_64), BX_LF_INSTR_ADD64)
|
||||
#endif
|
||||
|
||||
#define SET_FLAGS_OSZAPC_SUB_8(op1_8, op2_8, diff_8) \
|
||||
SET_FLAGS_OSZAPC_8((op1_8), (op2_8), (diff_8), BX_LF_INSTR_SUB8)
|
||||
#define SET_FLAGS_OSZAPC_SUB_16(op1_16, op2_16, diff_16) \
|
||||
SET_FLAGS_OSZAPC_16((op1_16), (op2_16), (diff_16), BX_LF_INSTR_SUB16)
|
||||
#define SET_FLAGS_OSZAPC_SUB_32(op1_32, op2_32, diff_32) \
|
||||
SET_FLAGS_OSZAPC_32((op1_32), (op2_32), (diff_32), BX_LF_INSTR_SUB32)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_SUB_64(op1_64, op2_64, diff_64) \
|
||||
SET_FLAGS_OSZAPC_64((op1_64), (op2_64), (diff_64), BX_LF_INSTR_SUB64)
|
||||
#endif
|
||||
|
||||
#define SET_FLAGS_OSZAPC_INC_8(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(8, (result), BX_LF_INSTR_INC8)
|
||||
#define SET_FLAGS_OSZAPC_INC_16(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(16, (result), BX_LF_INSTR_INC16)
|
||||
#define SET_FLAGS_OSZAPC_INC_32(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(32, (result), BX_LF_INSTR_INC32)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_INC_64(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(64, (result), BX_LF_INSTR_INC64)
|
||||
#endif
|
||||
|
||||
#define SET_FLAGS_OSZAPC_DEC_8(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(8, (result), BX_LF_INSTR_DEC8)
|
||||
#define SET_FLAGS_OSZAPC_DEC_16(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(16, (result), BX_LF_INSTR_DEC16)
|
||||
#define SET_FLAGS_OSZAPC_DEC_32(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(32, (result), BX_LF_INSTR_DEC32)
|
||||
#if BX_SUPPORT_X86_64
|
||||
#define SET_FLAGS_OSZAPC_DEC_64(result) \
|
||||
SET_FLAGS_OSZAP_RESULT_SIZE(64, (result), BX_LF_INSTR_DEC64)
|
||||
#endif
|
||||
|
||||
BOCHSAPI extern const Bit8u bx_parity_lookup[256];
|
||||
|
||||
#endif // BX_LAZY_FLAGS_DEF
|
||||
121
simulators/bochs/cpu/load.cc
Executable file
121
simulators/bochs/cpu/load.cc
Executable file
@ -0,0 +1,121 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-2011 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Eb(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
TMP8L = read_virtual_byte(i->seg(), eaddr);
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Ew(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
TMP16 = read_virtual_word(i->seg(), eaddr);
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Ed(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
TMP32 = read_virtual_dword(i->seg(), eaddr);
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Eq(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
TMP64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Ww(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
Bit16u val_16 = read_virtual_word(i->seg(), eaddr);
|
||||
BX_WRITE_XMM_REG_LO_WORD(BX_TMP_REGISTER, val_16);
|
||||
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Wss(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
Bit32u val_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
BX_WRITE_XMM_REG_LO_DWORD(BX_TMP_REGISTER, val_32);
|
||||
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Wsd(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
Bit64u val_64 = read_virtual_qword(i->seg(), eaddr);
|
||||
BX_WRITE_XMM_REG_LO_QWORD(BX_TMP_REGISTER, val_64);
|
||||
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOAD_Wdq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op;
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
#if BX_SUPPORT_MISALIGNED_SSE
|
||||
if (BX_CPU_THIS_PTR mxcsr.get_MM())
|
||||
read_virtual_dqword(i->seg(), eaddr, &op);
|
||||
else
|
||||
#endif
|
||||
read_virtual_dqword_aligned(i->seg(), eaddr, &op);
|
||||
|
||||
BX_WRITE_XMM_REG(BX_TMP_REGISTER, op);
|
||||
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LOADU_Wdq(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op;
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
read_virtual_dqword(i->seg(), eaddr, &op);
|
||||
BX_WRITE_XMM_REG(BX_TMP_REGISTER, op);
|
||||
|
||||
BX_CPU_CALL_METHOD(i->execute2, (i));
|
||||
#endif
|
||||
}
|
||||
248
simulators/bochs/cpu/logical16.cc
Normal file
248
simulators/bochs/cpu/logical16.cc
Normal file
@ -0,0 +1,248 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op1_16 ^= op2_16;
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 ^= op2_16;
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op1_16 ^= i->Iw();
|
||||
AX = op1_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16 ^= i->Iw();
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 ^= i->Iw();
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16 |= i->Iw();
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 |= i->Iw();
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16 = ~op1_16;
|
||||
write_RMW_virtual_word(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 = ~op1_16;
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op1_16 |= op2_16;
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 |= op2_16;
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
op1_16 |= op2_16;
|
||||
AX = op1_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op1_16 &= op2_16;
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 &= op2_16;
|
||||
BX_WRITE_16BIT_REG(i->nnn(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
op1_16 &= op2_16;
|
||||
AX = op1_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EwIwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
op1_16 &= i->Iw();
|
||||
write_RMW_virtual_word(op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 &= i->Iw();
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
op1_16 &= op2_16;
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_AXIw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16;
|
||||
|
||||
op1_16 = AX;
|
||||
op2_16 = i->Iw();
|
||||
op1_16 &= op2_16;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op1_16 &= i->Iw();
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(op1_16);
|
||||
}
|
||||
254
simulators/bochs/cpu/logical32.cc
Normal file
254
simulators/bochs/cpu/logical32.cc
Normal file
@ -0,0 +1,254 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier for merging cpu64 and cpu32 code.
|
||||
#define RAX EAX
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op1_32 ^= op2_32;
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 ^= op2_32;
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op1_32 ^= i->Id();
|
||||
RAX = op1_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32 ^= i->Id();
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 ^= i->Id();
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32 |= i->Id();
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 |= i->Id();
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EdM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32 = ~op1_32;
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 = ~op1_32;
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op1_32 |= op2_32;
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 |= op2_32;
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op2_32 = i->Id();
|
||||
op1_32 |= op2_32;
|
||||
RAX = op1_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op1_32 &= op2_32;
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 &= op2_32;
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op2_32 = i->Id();
|
||||
op1_32 &= op2_32;
|
||||
RAX = op1_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EdIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
op1_32 &= i->Id();
|
||||
write_RMW_virtual_dword(op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 &= i->Id();
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), op1_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
op1_32 &= op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32;
|
||||
|
||||
op1_32 = EAX;
|
||||
op2_32 = i->Id();
|
||||
op1_32 &= op2_32;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op1_32 &= i->Id();
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(op1_32);
|
||||
}
|
||||
272
simulators/bochs/cpu/logical64.cc
Normal file
272
simulators/bochs/cpu/logical64.cc
Normal file
@ -0,0 +1,272 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op1_64 ^= op2_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 ^= op2_64;
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
op1_64 ^= op2_64;
|
||||
|
||||
RAX = op1_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64 ^= op2_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 ^= op2_64;
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64 |= op2_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 |= op2_64;
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64 = ~op1_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 = ~op1_64;
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op1_64 |= op2_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 |= op2_64;
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
op1_64 |= op2_64;
|
||||
|
||||
RAX = op1_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op1_64 &= op2_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 &= op2_64;
|
||||
|
||||
/* now write result back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
op1_64 &= op2_64;
|
||||
RAX = op1_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EqIdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
op1_64 &= op2_64;
|
||||
write_RMW_virtual_qword(op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64 = (Bit32s) i->Id();
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op1_64 &= op2_64;
|
||||
BX_WRITE_64BIT_REG(i->rm(), op1_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
op1_64 &= op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_RAXId(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = RAX;
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
op1_64 &= op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = (Bit32s) i->Id();
|
||||
op1_64 &= op2_64;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(op1_64);
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
253
simulators/bochs/cpu/logical8.cc
Normal file
253
simulators/bochs/cpu/logical8.cc
Normal file
@ -0,0 +1,253 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op1 ^= op2;
|
||||
write_RMW_virtual_byte(op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 ^= op2;
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1 = AL;
|
||||
op1 ^= i->Ib();
|
||||
AL = op1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1 ^= op2;
|
||||
write_RMW_virtual_byte(op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XOR_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib();
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 ^= op2;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1 |= op2;
|
||||
write_RMW_virtual_byte(op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib();
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 |= op2;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EbM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1_8 = ~op1_8;
|
||||
write_RMW_virtual_byte(op1_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::NOT_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1_8 = ~op1_8;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1_8);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op1 |= op2;
|
||||
write_RMW_virtual_byte(op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 |= op2;
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::OR_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = AL;
|
||||
op2 = i->Ib();
|
||||
op1 |= op2;
|
||||
AL = op1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EbGbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op1 &= op2;
|
||||
write_RMW_virtual_byte(op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_GbEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 &= op2;
|
||||
BX_WRITE_8BIT_REGx(i->nnn(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = AL;
|
||||
op2 = i->Ib();
|
||||
op1 &= op2;
|
||||
AL = op1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EbIbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
op1 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
op1 &= op2;
|
||||
write_RMW_virtual_byte(op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::AND_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2 = i->Ib();
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 &= op2;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), op1);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EbGbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op2 = BX_READ_8BIT_REGx(i->nnn(), i->extend8bitL());
|
||||
op1 &= op2;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_ALIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1, op2;
|
||||
|
||||
op1 = AL;
|
||||
op2 = i->Ib();
|
||||
op1 &= op2;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::TEST_EbIbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
op1 &= i->Ib();
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(op1);
|
||||
}
|
||||
2768
simulators/bochs/cpu/mmx.cc
Normal file
2768
simulators/bochs/cpu/mmx.cc
Normal file
File diff suppressed because it is too large
Load Diff
235
simulators/bochs/cpu/model_specific.h
Executable file
235
simulators/bochs/cpu/model_specific.h
Executable file
@ -0,0 +1,235 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_CPU_MODEL_SPECIFIC
|
||||
#define BX_CPU_MODEL_SPECIFIC
|
||||
|
||||
// CPUID defines - STD features CPUID[0x00000001].EDX
|
||||
// ----------------------------
|
||||
|
||||
// [0:0] FPU on chip
|
||||
// [1:1] VME: Virtual-8086 Mode enhancements
|
||||
// [2:2] DE: Debug Extensions (I/O breakpoints)
|
||||
// [3:3] PSE: Page Size Extensions
|
||||
// [4:4] TSC: Time Stamp Counter
|
||||
// [5:5] MSR: RDMSR and WRMSR support
|
||||
// [6:6] PAE: Physical Address Extensions
|
||||
// [7:7] MCE: Machine Check Exception
|
||||
// [8:8] CXS: CMPXCHG8B instruction
|
||||
// [9:9] APIC: APIC on Chip
|
||||
// [10:10] Reserved
|
||||
// [11:11] SYSENTER/SYSEXIT support
|
||||
// [12:12] MTRR: Memory Type Range Reg
|
||||
// [13:13] PGE/PTE Global Bit
|
||||
// [14:14] MCA: Machine Check Architecture
|
||||
// [15:15] CMOV: Cond Mov/Cmp Instructions
|
||||
// [16:16] PAT: Page Attribute Table
|
||||
// [17:17] PSE-36: Physical Address Extensions
|
||||
// [18:18] PSN: Processor Serial Number
|
||||
// [19:19] CLFLUSH: CLFLUSH Instruction support
|
||||
// [20:20] Reserved
|
||||
// [21:21] DS: Debug Store
|
||||
// [22:22] ACPI: Thermal Monitor and Software Controlled Clock Facilities
|
||||
// [23:23] MMX Technology
|
||||
// [24:24] FXSR: FXSAVE/FXRSTOR (also indicates CR4.OSFXSR is available)
|
||||
// [25:25] SSE: SSE Extensions
|
||||
// [26:26] SSE2: SSE2 Extensions
|
||||
// [27:27] Self Snoop
|
||||
// [28:28] Hyper Threading Technology
|
||||
// [29:29] TM: Thermal Monitor
|
||||
// [30:30] Reserved
|
||||
// [31:31] PBE: Pending Break Enable
|
||||
|
||||
#define BX_CPUID_STD_X87 (1 << 0)
|
||||
#define BX_CPUID_STD_VME (1 << 1)
|
||||
#define BX_CPUID_STD_DEBUG_EXTENSIONS (1 << 2)
|
||||
#define BX_CPUID_STD_PSE (1 << 3)
|
||||
#define BX_CPUID_STD_TSC (1 << 4)
|
||||
#define BX_CPUID_STD_MSR (1 << 5)
|
||||
#define BX_CPUID_STD_PAE (1 << 6)
|
||||
#define BX_CPUID_STD_MCE (1 << 7)
|
||||
#define BX_CPUID_STD_CMPXCHG8B (1 << 8)
|
||||
#define BX_CPUID_STD_APIC (1 << 9)
|
||||
#define BX_CPUID_STD_RESERVED10 (1 << 10)
|
||||
#define BX_CPUID_STD_SYSENTER_SYSEXIT (1 << 11)
|
||||
#define BX_CPUID_STD_MTRR (1 << 12)
|
||||
#define BX_CPUID_STD_GLOBAL_PAGES (1 << 13)
|
||||
#define BX_CPUID_STD_MCA (1 << 14)
|
||||
#define BX_CPUID_STD_CMOV (1 << 15)
|
||||
#define BX_CPUID_STD_PAT (1 << 16)
|
||||
#define BX_CPUID_STD_PSE36 (1 << 17)
|
||||
#define BX_CPUID_STD_PROCESSOR_SERIAL_NUMBER (1 << 18)
|
||||
#define BX_CPUID_STD_CLFLUSH (1 << 19)
|
||||
#define BX_CPUID_STD_RESERVED20 (1 << 20)
|
||||
#define BX_CPUID_STD_DEBUG_STORE (1 << 21)
|
||||
#define BX_CPUID_STD_ACPI (1 << 22)
|
||||
#define BX_CPUID_STD_MMX (1 << 23)
|
||||
#define BX_CPUID_STD_FXSAVE_FXRSTOR (1 << 24)
|
||||
#define BX_CPUID_STD_SSE (1 << 25)
|
||||
#define BX_CPUID_STD_SSE2 (1 << 26)
|
||||
#define BX_CPUID_STD_SELF_SNOOP (1 << 27)
|
||||
#define BX_CPUID_STD_HT (1 << 28)
|
||||
#define BX_CPUID_STD_THERMAL_MONITOR (1 << 29)
|
||||
#define BX_CPUID_STD_RESERVED30 (1 << 30)
|
||||
#define BX_CPUID_STD_PBE (1 << 31)
|
||||
|
||||
// CPUID defines - EXT features CPUID[0x00000001].ECX
|
||||
// ----------------------------
|
||||
|
||||
// [0:0] SSE3: SSE3 Instructions
|
||||
// [1:1] PCLMULQDQ Instruction support
|
||||
// [2:2] DTES64: 64-bit DS area
|
||||
// [3:3] MONITOR/MWAIT support
|
||||
// [4:4] DS-CPL: CPL qualified debug store
|
||||
// [5:5] VMX: Virtual Machine Technology
|
||||
// [6:6] SMX: Secure Virtual Machine Technology
|
||||
// [7:7] EST: Enhanced Intel SpeedStep Technology
|
||||
// [8:8] TM2: Thermal Monitor 2
|
||||
// [9:9] SSSE3: SSSE3 Instructions
|
||||
// [10:10] CNXT-ID: L1 context ID
|
||||
// [11:11] reserved
|
||||
// [12:12] FMA Instructions support
|
||||
// [13:13] CMPXCHG16B: CMPXCHG16B instruction support
|
||||
// [14:14] xTPR update control
|
||||
// [15:15] PDCM - Perfon and Debug Capability MSR
|
||||
// [16:16] reserved
|
||||
// [17:17] PCID: Process Context Identifiers
|
||||
// [18:18] DCA - Direct Cache Access
|
||||
// [19:19] SSE4.1 Instructions
|
||||
// [20:20] SSE4.2 Instructions
|
||||
// [21:21] X2APIC
|
||||
// [22:22] MOVBE instruction
|
||||
// [23:23] POPCNT instruction
|
||||
// [24:24] TSC Deadline
|
||||
// [25:25] AES Instructions
|
||||
// [26:26] XSAVE extensions support
|
||||
// [27:27] OSXSAVE support
|
||||
// [28:28] AVX extensions support
|
||||
// [29:29] F16C - Float16 conversion support
|
||||
// [30:30] RDRAND instruction
|
||||
// [31:31] reserved
|
||||
|
||||
#define BX_CPUID_EXT_SSE3 (1 << 0)
|
||||
#define BX_CPUID_EXT_PCLMULQDQ (1 << 1)
|
||||
#define BX_CPUID_EXT_DTES64 (1 << 2)
|
||||
#define BX_CPUID_EXT_MONITOR_MWAIT (1 << 3)
|
||||
#define BX_CPUID_EXT_DS_CPL (1 << 4)
|
||||
#define BX_CPUID_EXT_VMX (1 << 5)
|
||||
#define BX_CPUID_EXT_SMX (1 << 6)
|
||||
#define BX_CPUID_EXT_EST (1 << 7)
|
||||
#define BX_CPUID_EXT_THERMAL_MONITOR2 (1 << 8)
|
||||
#define BX_CPUID_EXT_SSSE3 (1 << 9)
|
||||
#define BX_CPUID_EXT_CNXT_ID (1 << 10)
|
||||
#define BX_CPUID_EXT_RESERVED11 (1 << 11)
|
||||
#define BX_CPUID_EXT_FMA (1 << 12)
|
||||
#define BX_CPUID_EXT_CMPXCHG16B (1 << 13)
|
||||
#define BX_CPUID_EXT_xTPR (1 << 14)
|
||||
#define BX_CPUID_EXT_PDCM (1 << 15)
|
||||
#define BX_CPUID_EXT_RESERVED16 (1 << 16)
|
||||
#define BX_CPUID_EXT_PCID (1 << 17)
|
||||
#define BX_CPUID_EXT_DCA (1 << 18)
|
||||
#define BX_CPUID_EXT_SSE4_1 (1 << 19)
|
||||
#define BX_CPUID_EXT_SSE4_2 (1 << 20)
|
||||
#define BX_CPUID_EXT_X2APIC (1 << 21)
|
||||
#define BX_CPUID_EXT_MOVBE (1 << 22)
|
||||
#define BX_CPUID_EXT_POPCNT (1 << 23)
|
||||
#define BX_CPUID_EXT_TSC_DEADLINE (1 << 24)
|
||||
#define BX_CPUID_EXT_AES (1 << 25)
|
||||
#define BX_CPUID_EXT_XSAVE (1 << 26)
|
||||
#define BX_CPUID_EXT_OSXSAVE (1 << 27)
|
||||
#define BX_CPUID_EXT_AVX (1 << 28)
|
||||
#define BX_CPUID_EXT_F16C (1 << 29)
|
||||
#define BX_CPUID_EXT_RDRAND (1 << 30)
|
||||
#define BX_CPUID_EXT_RESERVED31 (1 << 31)
|
||||
|
||||
// CPUID defines - STD2 features CPUID[0x80000001].EDX
|
||||
// -----------------------------
|
||||
|
||||
// ...
|
||||
#define BX_CPUID_STD2_SYSCALL_SYSRET (1 << 11)
|
||||
// ...
|
||||
#define BX_CPUID_STD2_NX (1 << 20)
|
||||
#define BX_CPUID_STD2_RESERVED21 (1 << 21)
|
||||
#define BX_CPUID_STD2_AMD_MMX_EXT (1 << 22)
|
||||
#define BX_CPUID_STD2_RESERVED23 (1 << 23)
|
||||
#define BX_CPUID_STD2_RESERVED24 (1 << 24)
|
||||
#define BX_CPUID_STD2_FFXSR (1 << 25)
|
||||
#define BX_CPUID_STD2_1G_PAGES (1 << 26)
|
||||
#define BX_CPUID_STD2_RDTSCP (1 << 27)
|
||||
#define BX_CPUID_STD2_RESERVED28 (1 << 28)
|
||||
#define BX_CPUID_STD2_LONG_MODE (1 << 29)
|
||||
#define BX_CPUID_STD2_3DNOW_EXT (1 << 30)
|
||||
#define BX_CPUID_STD2_3DNOW (1 << 31)
|
||||
|
||||
// CPUID defines - EXT2 features CPUID[0x80000001].ECX
|
||||
// -----------------------------
|
||||
|
||||
// [0:0] LAHF/SAHF instructions support in 64-bit mode
|
||||
// [1:1] CMP_Legacy: Core multi-processing legacy mode (AMD)
|
||||
// [2:2] SVM: Secure Virtual Machine (AMD)
|
||||
// [3:3] Extended APIC Space
|
||||
// [4:4] AltMovCR8: LOCK MOV CR0 means MOV CR8
|
||||
// [5:5] LZCNT: LZCNT instruction support
|
||||
// [6:6] SSE4A: SSE4A Instructions support
|
||||
// [7:7] Misaligned SSE support
|
||||
// [8:8] PREFETCHW: PREFETCHW instruction support
|
||||
// [9:9] OSVW: OS visible workarounds (AMD)
|
||||
// [10:10] IBS: Instruction based sampling
|
||||
// [11:11] XOP: Extended Operations Support and XOP Prefix
|
||||
// [12:12] SKINIT support
|
||||
// [13:13] WDT: Watchdog timer support
|
||||
// [14:14] reserved
|
||||
// [15:15] LWP: Light weight profiling
|
||||
// [16:16] FMA4: Four-operand FMA instructions support
|
||||
// [18:17] reserved
|
||||
// [19:19] NodeId: Indicates support for NodeId MSR (0xc001100c)
|
||||
// [20:20] reserved
|
||||
// [21:21] TBM: trailing bit manipulation instruction support
|
||||
// [22:22] Topology extensions support
|
||||
// [31:23] reserved
|
||||
|
||||
#define BX_CPUID_EXT2_LAHF_SAHF (1 << 0)
|
||||
#define BX_CPUID_EXT2_CMP_LEGACY (1 << 1)
|
||||
#define BX_CPUID_EXT2_SVM (1 << 2)
|
||||
#define BX_CPUID_EXT2_EXT_APIC_SPACE (1 << 3)
|
||||
#define BX_CPUID_EXT2_ALT_MOV_CR8 (1 << 4)
|
||||
#define BX_CPUID_EXT2_LZCNT (1 << 5)
|
||||
#define BX_CPUID_EXT2_SSE4A (1 << 6)
|
||||
#define BX_CPUID_EXT2_MISALIGNED_SSE (1 << 7)
|
||||
#define BX_CPUID_EXT2_PREFETCHW (1 << 8)
|
||||
#define BX_CPUID_EXT2_OSVW (1 << 9)
|
||||
#define BX_CPUID_EXT2_IBS (1 << 10)
|
||||
#define BX_CPUID_EXT2_XOP (1 << 11)
|
||||
#define BX_CPUID_EXT2_SKINIT (1 << 12)
|
||||
#define BX_CPUID_EXT2_WDT (1 << 13)
|
||||
#define BX_CPUID_EXT2_RESERVED14 (1 << 14)
|
||||
#define BX_CPUID_EXT2_LWP (1 << 15)
|
||||
#define BX_CPUID_EXT2_FMA4 (1 << 16)
|
||||
#define BX_CPUID_EXT2_RESERVED17 (1 << 17)
|
||||
#define BX_CPUID_EXT2_RESERVED18 (1 << 18)
|
||||
#define BX_CPUID_EXT2_NODEID (1 << 19)
|
||||
#define BX_CPUID_EXT2_RESERVED20 (1 << 20)
|
||||
#define BX_CPUID_EXT2_TBM (1 << 21)
|
||||
#define BX_CPUID_EXT2_TOPOLOGY_EXTENSIONS (1 << 22)
|
||||
|
||||
#endif
|
||||
807
simulators/bochs/cpu/msr.cc
Executable file
807
simulators/bochs/cpu/msr.cc
Executable file
@ -0,0 +1,807 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier for merging code.
|
||||
#define RAX EAX
|
||||
#define RDX EDX
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::rdmsr(Bit32u index, Bit64u *msr)
|
||||
{
|
||||
Bit64u val64 = 0;
|
||||
|
||||
if ((index & 0x3FFFFFFF) >= BX_MSR_MAX_INDEX)
|
||||
return 0;
|
||||
|
||||
#if BX_SUPPORT_X2APIC
|
||||
if (index >= 0x800 && index <= 0xBFF) {
|
||||
if (BX_CPU_THIS_PTR msr.apicbase & 0x400) // X2APIC mode
|
||||
return BX_CPU_THIS_PTR lapic.read_x2apic(index, msr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(index) {
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
case BX_MSR_SYSENTER_CS:
|
||||
if (! bx_cpuid_support_sep()) {
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("RDMSR MSR_SYSENTER_CS: SYSENTER/SYSEXIT feature not enabled !"));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
val64 = BX_CPU_THIS_PTR msr.sysenter_cs_msr;
|
||||
break;
|
||||
|
||||
case BX_MSR_SYSENTER_ESP:
|
||||
if (! bx_cpuid_support_sep()) {
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("RDMSR MSR_SYSENTER_ESP: SYSENTER/SYSEXIT feature not enabled !"));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
val64 = BX_CPU_THIS_PTR msr.sysenter_esp_msr;
|
||||
break;
|
||||
|
||||
case BX_MSR_SYSENTER_EIP:
|
||||
if (! bx_cpuid_support_sep()) {
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("RDMSR MSR_SYSENTER_EIP: SYSENTER/SYSEXIT feature not enabled !"));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
val64 = BX_CPU_THIS_PTR msr.sysenter_eip_msr;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
case BX_MSR_MTRRCAP: // read only MSR
|
||||
val64 = BX_CONST64(0x0000000000000508);
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRRPHYSBASE0:
|
||||
case BX_MSR_MTRRPHYSMASK0:
|
||||
case BX_MSR_MTRRPHYSBASE1:
|
||||
case BX_MSR_MTRRPHYSMASK1:
|
||||
case BX_MSR_MTRRPHYSBASE2:
|
||||
case BX_MSR_MTRRPHYSMASK2:
|
||||
case BX_MSR_MTRRPHYSBASE3:
|
||||
case BX_MSR_MTRRPHYSMASK3:
|
||||
case BX_MSR_MTRRPHYSBASE4:
|
||||
case BX_MSR_MTRRPHYSMASK4:
|
||||
case BX_MSR_MTRRPHYSBASE5:
|
||||
case BX_MSR_MTRRPHYSMASK5:
|
||||
case BX_MSR_MTRRPHYSBASE6:
|
||||
case BX_MSR_MTRRPHYSMASK6:
|
||||
case BX_MSR_MTRRPHYSBASE7:
|
||||
case BX_MSR_MTRRPHYSMASK7:
|
||||
val64 = BX_CPU_THIS_PTR msr.mtrrphys[index - BX_MSR_MTRRPHYSBASE0];
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRRFIX64K_00000:
|
||||
val64 = BX_CPU_THIS_PTR msr.mtrrfix64k_00000;
|
||||
break;
|
||||
case BX_MSR_MTRRFIX16K_80000:
|
||||
case BX_MSR_MTRRFIX16K_A0000:
|
||||
val64 = BX_CPU_THIS_PTR msr.mtrrfix16k[index - BX_MSR_MTRRFIX16K_80000];
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRRFIX4K_C0000:
|
||||
case BX_MSR_MTRRFIX4K_C8000:
|
||||
case BX_MSR_MTRRFIX4K_D0000:
|
||||
case BX_MSR_MTRRFIX4K_D8000:
|
||||
case BX_MSR_MTRRFIX4K_E0000:
|
||||
case BX_MSR_MTRRFIX4K_E8000:
|
||||
case BX_MSR_MTRRFIX4K_F0000:
|
||||
case BX_MSR_MTRRFIX4K_F8000:
|
||||
val64 = BX_CPU_THIS_PTR msr.mtrrfix4k[index - BX_MSR_MTRRFIX4K_C0000];
|
||||
break;
|
||||
|
||||
case BX_MSR_PAT:
|
||||
val64 = BX_CPU_THIS_PTR msr.pat;
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRR_DEFTYPE:
|
||||
val64 = BX_CPU_THIS_PTR msr.mtrr_deftype;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case BX_MSR_TSC:
|
||||
val64 = BX_CPU_THIS_PTR get_TSC();
|
||||
break;
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
case BX_MSR_APICBASE:
|
||||
val64 = BX_CPU_THIS_PTR msr.apicbase;
|
||||
BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", GET32H(val64), GET32L(val64)));
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
/*
|
||||
case BX_MSR_IA32_SMM_MONITOR_CTL:
|
||||
BX_PANIC(("Dual-monitor treatment of SMI and SMM is not implemented"));
|
||||
break;
|
||||
*/
|
||||
case BX_MSR_IA32_FEATURE_CONTROL:
|
||||
val64 = BX_CPU_THIS_PTR msr.ia32_feature_ctrl;
|
||||
break;
|
||||
case BX_MSR_VMX_BASIC:
|
||||
val64 = VMX_MSR_VMX_BASIC;
|
||||
break;
|
||||
case BX_MSR_VMX_PINBASED_CTRLS:
|
||||
val64 = VMX_MSR_VMX_PINBASED_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_PROCBASED_CTRLS:
|
||||
val64 = VMX_MSR_VMX_PROCBASED_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_VMEXIT_CTRLS:
|
||||
val64 = VMX_MSR_VMX_VMEXIT_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_VMENTRY_CTRLS:
|
||||
val64 = VMX_MSR_VMX_VMENTRY_CTRLS;
|
||||
break;
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case BX_MSR_VMX_PROCBASED_CTRLS2:
|
||||
val64 = VMX_MSR_VMX_PROCBASED_CTRLS2;
|
||||
break;
|
||||
case BX_MSR_VMX_TRUE_PINBASED_CTRLS:
|
||||
val64 = VMX_MSR_VMX_TRUE_PINBASED_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_TRUE_PROCBASED_CTRLS:
|
||||
val64 = VMX_MSR_VMX_TRUE_PROCBASED_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_TRUE_VMEXIT_CTRLS:
|
||||
val64 = VMX_MSR_VMX_TRUE_VMEXIT_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_TRUE_VMENTRY_CTRLS:
|
||||
val64 = VMX_MSR_VMX_TRUE_VMENTRY_CTRLS;
|
||||
break;
|
||||
case BX_MSR_VMX_MSR_VMX_EPT_VPID_CAP:
|
||||
val64 = VMX_MSR_VMX_EPT_VPID_CAP;
|
||||
break;
|
||||
#endif
|
||||
case BX_MSR_VMX_MISC:
|
||||
val64 = VMX_MSR_MISC;
|
||||
break;
|
||||
case BX_MSR_VMX_CR0_FIXED0:
|
||||
val64 = VMX_MSR_CR0_FIXED0;
|
||||
break;
|
||||
case BX_MSR_VMX_CR0_FIXED1:
|
||||
val64 = VMX_MSR_CR0_FIXED1;
|
||||
break;
|
||||
case BX_MSR_VMX_CR4_FIXED0:
|
||||
val64 = VMX_MSR_CR4_FIXED0;
|
||||
break;
|
||||
case BX_MSR_VMX_CR4_FIXED1:
|
||||
val64 = VMX_MSR_CR4_FIXED1;
|
||||
break;
|
||||
case BX_MSR_VMX_VMCS_ENUM:
|
||||
val64 = VMX_MSR_VMCS_ENUM;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_MSR_EFER:
|
||||
val64 = BX_CPU_THIS_PTR efer.get32();
|
||||
break;
|
||||
|
||||
case BX_MSR_STAR:
|
||||
val64 = MSR_STAR;
|
||||
break;
|
||||
|
||||
case BX_MSR_LSTAR:
|
||||
val64 = MSR_LSTAR;
|
||||
break;
|
||||
|
||||
case BX_MSR_CSTAR:
|
||||
val64 = MSR_CSTAR;
|
||||
break;
|
||||
|
||||
case BX_MSR_FMASK:
|
||||
val64 = MSR_FMASK;
|
||||
break;
|
||||
|
||||
case BX_MSR_FSBASE:
|
||||
val64 = MSR_FSBASE;
|
||||
break;
|
||||
|
||||
case BX_MSR_GSBASE:
|
||||
val64 = MSR_GSBASE;
|
||||
break;
|
||||
|
||||
case BX_MSR_KERNELGSBASE:
|
||||
val64 = MSR_KERNELGSBASE;
|
||||
break;
|
||||
|
||||
case BX_MSR_TSC_AUX:
|
||||
val64 = MSR_TSC_AUX; // 32 bit MSR
|
||||
break;
|
||||
#endif // #if BX_SUPPORT_X86_64
|
||||
|
||||
default:
|
||||
#if BX_CONFIGURE_MSRS
|
||||
if (index < BX_MSR_MAX_INDEX && BX_CPU_THIS_PTR msrs[index]) {
|
||||
val64 = BX_CPU_THIS_PTR msrs[index]->get64();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("RDMSR: Unknown register %#x", index));
|
||||
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
|
||||
BX_DEBUG(("RDMSR: read %08x:%08x from MSR %x", GET32H(val64), GET32L(val64), index));
|
||||
|
||||
*msr = val64;
|
||||
return 1;
|
||||
}
|
||||
#endif // BX_CPU_LEVEL >= 5
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RDMSR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (!real_mode() && CPL != 0) {
|
||||
BX_ERROR(("RDMSR: CPL != 0 not in real mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit32u index = ECX;
|
||||
Bit64u val64 = 0;
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_MSR(i, VMX_VMEXIT_RDMSR, index);
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest && index == 0x808) {
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE)) {
|
||||
RAX = VMX_Read_VTPR() & 0xff;
|
||||
RDX = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!rdmsr(index, &val64))
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
|
||||
RAX = GET32L(val64);
|
||||
RDX = GET32H(val64);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
bx_bool isMemTypeValidMTRR(unsigned memtype)
|
||||
{
|
||||
switch(memtype) {
|
||||
case BX_MEMTYPE_UC:
|
||||
case BX_MEMTYPE_WC:
|
||||
case BX_MEMTYPE_WT:
|
||||
case BX_MEMTYPE_WP:
|
||||
case BX_MEMTYPE_WB:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPP_INLINE bx_bool isMemTypeValidPAT(unsigned memtype)
|
||||
{
|
||||
return (memtype == 0x07) /* UC- */ || isMemTypeValidMTRR(memtype);
|
||||
}
|
||||
|
||||
bx_bool isValidMSR_PAT(Bit64u pat_msr)
|
||||
{
|
||||
if (! isMemTypeValidPAT(pat_msr & 0xFF) ||
|
||||
! isMemTypeValidPAT((pat_msr >> 8) & 0xFF) ||
|
||||
! isMemTypeValidPAT((pat_msr >> 16) & 0xFF) ||
|
||||
! isMemTypeValidPAT((pat_msr >> 24) & 0xFF) ||
|
||||
! isMemTypeValidPAT((pat_msr >> 32) & 0xFF) ||
|
||||
! isMemTypeValidPAT((pat_msr >> 40) & 0xFF) ||
|
||||
! isMemTypeValidPAT((pat_msr >> 48) & 0xFF) ||
|
||||
! isMemTypeValidPAT(pat_msr >> 56)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bx_bool isValidMSR_FixedMTRR(Bit64u fixed_mtrr_msr)
|
||||
{
|
||||
if (! isMemTypeValidMTRR(fixed_mtrr_msr & 0xFF) ||
|
||||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 8) & 0xFF) ||
|
||||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 16) & 0xFF) ||
|
||||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 24) & 0xFF) ||
|
||||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 32) & 0xFF) ||
|
||||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 40) & 0xFF) ||
|
||||
! isMemTypeValidMTRR((fixed_mtrr_msr >> 48) & 0xFF) ||
|
||||
! isMemTypeValidMTRR(fixed_mtrr_msr >> 56)) return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
bx_bool BX_CPP_AttrRegparmN(2) BX_CPU_C::wrmsr(Bit32u index, Bit64u val_64)
|
||||
{
|
||||
Bit32u val32_lo = GET32L(val_64);
|
||||
Bit32u val32_hi = GET32H(val_64);
|
||||
|
||||
BX_INSTR_WRMSR(BX_CPU_ID, index, val_64);
|
||||
|
||||
BX_DEBUG(("WRMSR: write %08x:%08x to MSR %x", val32_hi, val32_lo, index));
|
||||
|
||||
if ((index & 0x3FFFFFFF) >= BX_MSR_MAX_INDEX)
|
||||
return 0;
|
||||
|
||||
#if BX_SUPPORT_X2APIC
|
||||
if (index >= 0x800 && index <= 0xBFF) {
|
||||
if (BX_CPU_THIS_PTR msr.apicbase & 0x400) // X2APIC mode
|
||||
return BX_CPU_THIS_PTR lapic.write_x2apic(index, val_64);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
switch(index) {
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
case BX_MSR_SYSENTER_CS:
|
||||
if (! bx_cpuid_support_sep()) {
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("WRMSR MSR_SYSENTER_CS: SYSENTER/SYSEXIT feature not enabled !"));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.sysenter_cs_msr = val32_lo;
|
||||
break;
|
||||
|
||||
case BX_MSR_SYSENTER_ESP:
|
||||
if (! bx_cpuid_support_sep()) {
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("WRMSR MSR_SYSENTER_ESP: SYSENTER/SYSEXIT feature not enabled !"));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_ESP !"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
BX_CPU_THIS_PTR msr.sysenter_esp_msr = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_SYSENTER_EIP:
|
||||
if (! bx_cpuid_support_sep()) {
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("WRMSR MSR_SYSENTER_EIP: SYSENTER/SYSEXIT feature not enabled !"));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_SYSENTER_EIP !"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
BX_CPU_THIS_PTR msr.sysenter_eip_msr = val_64;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
case BX_MSR_MTRRCAP:
|
||||
BX_ERROR(("WRMSR: MTRRCAP is read only MSR"));
|
||||
return 0;
|
||||
|
||||
case BX_MSR_MTRRPHYSBASE0:
|
||||
case BX_MSR_MTRRPHYSBASE1:
|
||||
case BX_MSR_MTRRPHYSBASE2:
|
||||
case BX_MSR_MTRRPHYSBASE3:
|
||||
case BX_MSR_MTRRPHYSBASE4:
|
||||
case BX_MSR_MTRRPHYSBASE5:
|
||||
case BX_MSR_MTRRPHYSBASE6:
|
||||
case BX_MSR_MTRRPHYSBASE7:
|
||||
if (! IsValidPhyAddr(val_64)) {
|
||||
BX_ERROR(("WRMSR[0x%08x]: attempt to write invalid phy addr to variable range MTRR %08x:%08x", index, val32_hi, val32_lo));
|
||||
return 0;
|
||||
}
|
||||
// handle 8-11 reserved bits
|
||||
if (! isMemTypeValidMTRR(val32_lo & 0xFFF)) {
|
||||
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to BX_MSR_MTRRPHYSBASE"));
|
||||
return 0;
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.mtrrphys[index - BX_MSR_MTRRPHYSBASE0] = val_64;
|
||||
break;
|
||||
case BX_MSR_MTRRPHYSMASK0:
|
||||
case BX_MSR_MTRRPHYSMASK1:
|
||||
case BX_MSR_MTRRPHYSMASK2:
|
||||
case BX_MSR_MTRRPHYSMASK3:
|
||||
case BX_MSR_MTRRPHYSMASK4:
|
||||
case BX_MSR_MTRRPHYSMASK5:
|
||||
case BX_MSR_MTRRPHYSMASK6:
|
||||
case BX_MSR_MTRRPHYSMASK7:
|
||||
if (! IsValidPhyAddr(val_64)) {
|
||||
BX_ERROR(("WRMSR[0x%08x]: attempt to write invalid phy addr to variable range MTRR %08x:%08x", index, val32_hi, val32_lo));
|
||||
return 0;
|
||||
}
|
||||
// handle 10-0 reserved bits
|
||||
if (val32_lo & 0x7ff) {
|
||||
BX_ERROR(("WRMSR[0x%08x]: variable range MTRR reserved bits violation %08x:%08x", index, val32_hi, val32_lo));
|
||||
return 0;
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.mtrrphys[index - BX_MSR_MTRRPHYSBASE0] = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRRFIX64K_00000:
|
||||
if (! isValidMSR_FixedMTRR(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX64K_00000 !"));
|
||||
return 0;
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.mtrrfix64k_00000 = val_64;
|
||||
break;
|
||||
case BX_MSR_MTRRFIX16K_80000:
|
||||
case BX_MSR_MTRRFIX16K_A0000:
|
||||
if (! isValidMSR_FixedMTRR(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRRFIX16K regsiter !"));
|
||||
return 0;
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.mtrrfix16k[index - BX_MSR_MTRRFIX16K_80000] = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRRFIX4K_C0000:
|
||||
case BX_MSR_MTRRFIX4K_C8000:
|
||||
case BX_MSR_MTRRFIX4K_D0000:
|
||||
case BX_MSR_MTRRFIX4K_D8000:
|
||||
case BX_MSR_MTRRFIX4K_E0000:
|
||||
case BX_MSR_MTRRFIX4K_E8000:
|
||||
case BX_MSR_MTRRFIX4K_F0000:
|
||||
case BX_MSR_MTRRFIX4K_F8000:
|
||||
if (! isValidMSR_FixedMTRR(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to fixed memory range MTRR !"));
|
||||
return 0;
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.mtrrfix4k[index - BX_MSR_MTRRFIX4K_C0000] = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_PAT:
|
||||
if (! isValidMSR_PAT(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_PAT"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR msr.pat = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_MTRR_DEFTYPE:
|
||||
if (! isMemTypeValidMTRR(val32_lo & 0xFF)) {
|
||||
BX_ERROR(("WRMSR: attempt to write invalid Memory Type to MSR_MTRR_DEFTYPE"));
|
||||
return 0;
|
||||
}
|
||||
if (val32_hi || (val32_lo & 0xfffff300)) {
|
||||
BX_ERROR(("WRMSR: attempt to reserved bits in MSR_MTRR_DEFTYPE"));
|
||||
return 0;
|
||||
}
|
||||
BX_CPU_THIS_PTR msr.mtrr_deftype = val32_lo;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case BX_MSR_TSC:
|
||||
BX_INFO(("WRMSR: write 0x%08x%08x to MSR_TSC", val32_hi, val32_lo));
|
||||
BX_CPU_THIS_PTR set_TSC(val_64);
|
||||
break;
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
case BX_MSR_APICBASE:
|
||||
return relocate_apic(val_64);
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
// Support only two bits: lock bit (bit 0) and VMX enable (bit 2)
|
||||
case BX_MSR_IA32_FEATURE_CONTROL:
|
||||
if (BX_CPU_THIS_PTR msr.ia32_feature_ctrl & 0x1) {
|
||||
BX_ERROR(("WRMSR: IA32_FEATURE_CONTROL_MSR VMX lock bit is set !"));
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
if (val_64 & ~((Bit64u)(BX_IA32_FEATURE_CONTROL_BITS))) {
|
||||
BX_ERROR(("WRMSR: attempt to set reserved bits of IA32_FEATURE_CONTROL_MSR !"));
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
BX_CPU_THIS_PTR msr.ia32_feature_ctrl = val32_lo;
|
||||
break;
|
||||
|
||||
case BX_MSR_VMX_BASIC:
|
||||
case BX_MSR_VMX_PINBASED_CTRLS:
|
||||
case BX_MSR_VMX_PROCBASED_CTRLS:
|
||||
case BX_MSR_VMX_PROCBASED_CTRLS2:
|
||||
case BX_MSR_VMX_VMEXIT_CTRLS:
|
||||
case BX_MSR_VMX_VMENTRY_CTRLS:
|
||||
case BX_MSR_VMX_MISC:
|
||||
case BX_MSR_VMX_CR0_FIXED0:
|
||||
case BX_MSR_VMX_CR0_FIXED1:
|
||||
case BX_MSR_VMX_CR4_FIXED0:
|
||||
case BX_MSR_VMX_CR4_FIXED1:
|
||||
case BX_MSR_VMX_VMCS_ENUM:
|
||||
case BX_MSR_VMX_MSR_VMX_EPT_VPID_CAP:
|
||||
case BX_MSR_VMX_TRUE_PINBASED_CTRLS:
|
||||
case BX_MSR_VMX_TRUE_PROCBASED_CTRLS:
|
||||
case BX_MSR_VMX_TRUE_VMEXIT_CTRLS:
|
||||
case BX_MSR_VMX_TRUE_VMENTRY_CTRLS:
|
||||
BX_ERROR(("WRMSR: VMX read only MSR"));
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
case BX_MSR_EFER:
|
||||
if (val_64 & ~BX_EFER_SUPPORTED_BITS) {
|
||||
BX_ERROR(("WRMSR: attempt to set reserved bits of EFER MSR !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* #GP(0) if changing EFER.LME when cr0.pg = 1 */
|
||||
if ((BX_CPU_THIS_PTR efer.get_LME() != ((val32_lo >> 8) & 1)) &&
|
||||
BX_CPU_THIS_PTR cr0.get_PG())
|
||||
{
|
||||
BX_ERROR(("WRMSR: attempt to change LME when CR0.PG=1"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR efer.set32((val32_lo & BX_EFER_SUPPORTED_BITS & ~BX_EFER_LMA_MASK)
|
||||
| (BX_CPU_THIS_PTR efer.get32() & BX_EFER_LMA_MASK)); // keep LMA untouched
|
||||
break;
|
||||
|
||||
case BX_MSR_STAR:
|
||||
MSR_STAR = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_LSTAR:
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_LSTAR !"));
|
||||
return 0;
|
||||
}
|
||||
MSR_LSTAR = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_CSTAR:
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_CSTAR !"));
|
||||
return 0;
|
||||
}
|
||||
MSR_CSTAR = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_FMASK:
|
||||
MSR_FMASK = (Bit32u) val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_FSBASE:
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_FSBASE !"));
|
||||
return 0;
|
||||
}
|
||||
MSR_FSBASE = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_GSBASE:
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_GSBASE !"));
|
||||
return 0;
|
||||
}
|
||||
MSR_GSBASE = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_KERNELGSBASE:
|
||||
if (! IsCanonical(val_64)) {
|
||||
BX_ERROR(("WRMSR: attempt to write non-canonical value to MSR_KERNELGSBASE !"));
|
||||
return 0;
|
||||
}
|
||||
MSR_KERNELGSBASE = val_64;
|
||||
break;
|
||||
|
||||
case BX_MSR_TSC_AUX:
|
||||
MSR_TSC_AUX = val32_lo;
|
||||
break;
|
||||
#endif // #if BX_SUPPORT_X86_64
|
||||
|
||||
default:
|
||||
#if BX_CONFIGURE_MSRS
|
||||
if (index < BX_MSR_MAX_INDEX && BX_CPU_THIS_PTR msrs[index]) {
|
||||
if (! BX_CPU_THIS_PTR msrs[index]->set64(val_64)) {
|
||||
BX_ERROR(("WRMSR: Write failed to MSR %#x - #GP fault", index));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
// failed to find the MSR, could #GP or ignore it silently
|
||||
BX_ERROR(("WRMSR: Unknown register %#x", index));
|
||||
if (! BX_CPU_THIS_PTR ignore_bad_msrs)
|
||||
return 0; // will result in #GP fault due to unknown MSR
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif // BX_CPU_LEVEL >= 5
|
||||
|
||||
#if BX_SUPPORT_APIC
|
||||
bx_bool BX_CPU_C::relocate_apic(Bit64u val_64)
|
||||
{
|
||||
/* MSR_APICBASE
|
||||
* [0:7] Reserved
|
||||
* [8] This is set if CPU is BSP
|
||||
* [9] Reserved
|
||||
* [10] X2APIC mode bit (1=enabled 0=disabled)
|
||||
* [11] APIC Global Enable bit (1=enabled 0=disabled)
|
||||
* [12:M] APIC Base Address (physical)
|
||||
* [M:63] Reserved
|
||||
*/
|
||||
|
||||
#define BX_MSR_APICBASE_RESERVED_BITS (0x2ff | (BX_SUPPORT_X2APIC ? 0 : 0x400))
|
||||
|
||||
if (BX_CPU_THIS_PTR msr.apicbase & 0x800) {
|
||||
Bit32u val32_hi = GET32H(val_64), val32_lo = GET32L(val_64);
|
||||
BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", val32_hi, val32_lo));
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (! IsValidPhyAddr(val_64)) {
|
||||
BX_ERROR(("relocate_apic: invalid physical address"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (val32_lo & BX_MSR_APICBASE_RESERVED_BITS) {
|
||||
BX_ERROR(("relocate_apic: attempt to set reserved bits"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X2APIC
|
||||
unsigned apic_state = (BX_CPU_THIS_PTR msr.apicbase >> 10) & 3;
|
||||
unsigned new_state = (val32_lo >> 10) & 3;
|
||||
if (new_state == BX_APIC_STATE_INVALID) {
|
||||
BX_ERROR(("relocate_apic: attempt to set invalid apic state"));
|
||||
return 0;
|
||||
}
|
||||
if (apic_state == BX_APIC_X2APIC_MODE && new_state != BX_APIC_GLOBALLY_DISABLED) {
|
||||
BX_ERROR(("relocate_apic: attempt to switch from x2apic -> xapic"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
BX_CPU_THIS_PTR msr.apicbase = (bx_phy_address) val_64;
|
||||
BX_CPU_THIS_PTR lapic.set_base(BX_CPU_THIS_PTR msr.apicbase);
|
||||
// TLB flush is required for emulation correctness
|
||||
TLB_flush(); // don't care about performance of apic relocation
|
||||
|
||||
if ((val32_lo & 0x800) == 0) {
|
||||
// APIC global enable bit cleared, clear APIC on chip CPUID feature flag
|
||||
BX_CPU_THIS_PTR cpuid_std_function[0x1].edx &= ~(1<<9);
|
||||
BX_CPU_THIS_PTR cpuid_ext_function[0x1].edx &= ~(1<<9);
|
||||
}
|
||||
}
|
||||
else {
|
||||
BX_INFO(("WRMSR: MSR_APICBASE APIC global enable bit cleared !"));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::WRMSR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (!real_mode() && CPL != 0) {
|
||||
BX_ERROR(("WRMSR: CPL != 0 not in real mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit64u val_64 = ((Bit64u) EDX << 32) | EAX;
|
||||
Bit32u index = ECX;
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_MSR(i, VMX_VMEXIT_WRMSR, index);
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest && index == 0x808) {
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_X2APIC_MODE)) {
|
||||
VMX_Write_VTPR(AL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (! wrmsr(index, val_64))
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BX_CONFIGURE_MSRS
|
||||
|
||||
int BX_CPU_C::load_MSRs(const char *file)
|
||||
{
|
||||
char line[512];
|
||||
unsigned linenum = 0;
|
||||
Bit32u index, type;
|
||||
Bit32u reset_hi, reset_lo;
|
||||
Bit32u rsrv_hi, rsrv_lo;
|
||||
Bit32u ignr_hi, ignr_lo;
|
||||
|
||||
FILE *fd = fopen (file, "r");
|
||||
if (fd == NULL) return -1;
|
||||
int retval = 0;
|
||||
do {
|
||||
linenum++;
|
||||
char* ret = fgets(line, sizeof(line)-1, fd);
|
||||
line[sizeof(line) - 1] = '\0';
|
||||
size_t len = strlen(line);
|
||||
if (len>0 && line[len-1] < ' ')
|
||||
line[len-1] = '\0';
|
||||
|
||||
if (ret != NULL && strlen(line)) {
|
||||
if (line[0] == '#') continue;
|
||||
retval = sscanf(line, "%x %d %08x %08x %08x %08x %08x %08x",
|
||||
&index, &type, &reset_hi, &reset_lo, &rsrv_hi, &rsrv_lo, &ignr_hi, &ignr_lo);
|
||||
|
||||
if (retval < 8) {
|
||||
retval = -1;
|
||||
BX_PANIC(("%s:%d > error parsing MSRs config file!", file, linenum));
|
||||
break; // quit parsing after first error
|
||||
}
|
||||
if (index >= BX_MSR_MAX_INDEX) {
|
||||
BX_PANIC(("%s:%d > MSR index is too big !", file, linenum));
|
||||
continue;
|
||||
}
|
||||
if (BX_CPU_THIS_PTR msrs[index]) {
|
||||
BX_PANIC(("%s:%d > MSR[0x%03x] is already defined!", file, linenum, index));
|
||||
continue;
|
||||
}
|
||||
if (type > 2) {
|
||||
BX_PANIC(("%s:%d > MSR[0x%03x] unknown type !", file, linenum, index));
|
||||
continue;
|
||||
}
|
||||
|
||||
BX_INFO(("loaded MSR[0x%03x] type=%d %08x:%08x %08x:%08x %08x:%08x", index, type,
|
||||
reset_hi, reset_lo, rsrv_hi, rsrv_lo, ignr_hi, ignr_lo));
|
||||
|
||||
BX_CPU_THIS_PTR msrs[index] = new MSR(index, type,
|
||||
((Bit64u)(reset_hi) << 32) | reset_lo,
|
||||
((Bit64u) (rsrv_hi) << 32) | rsrv_lo,
|
||||
((Bit64u) (ignr_hi) << 32) | ignr_lo);
|
||||
}
|
||||
} while (!feof(fd));
|
||||
|
||||
fclose(fd);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
159
simulators/bochs/cpu/mult16.cc
Normal file
159
simulators/bochs/cpu/mult16.cc
Normal file
@ -0,0 +1,159 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_AXEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16 = AX;
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
Bit32u product_32 = ((Bit32u) op1_16) * ((Bit32u) op2_16);
|
||||
Bit16u product_16l = (product_32 & 0xFFFF);
|
||||
Bit16u product_16h = product_32 >> 16;
|
||||
|
||||
/* now write product back to destination */
|
||||
AX = product_16l;
|
||||
DX = product_16h;
|
||||
|
||||
/* set EFLAGS */
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(product_16l);
|
||||
if(product_16h != 0)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_AXEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16s op1_16 = AX;
|
||||
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
Bit32s product_32 = ((Bit32s) op1_16) * ((Bit32s) op2_16);
|
||||
Bit16u product_16l = (product_32 & 0xFFFF);
|
||||
Bit16u product_16h = product_32 >> 16;
|
||||
|
||||
/* now write product back to destination */
|
||||
AX = product_16l;
|
||||
DX = product_16h;
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r/m16: condition for clearing CF & OF:
|
||||
* DX:AX = sign-extend of AX
|
||||
*/
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(product_16l);
|
||||
if(product_32 != (Bit16s)product_32)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_AXEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
if (op2_16 == 0)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit32u op1_32 = (((Bit32u) DX) << 16) | ((Bit32u) AX);
|
||||
|
||||
Bit32u quotient_32 = op1_32 / op2_16;
|
||||
Bit16u remainder_16 = op1_32 % op2_16;
|
||||
Bit16u quotient_16l = quotient_32 & 0xFFFF;
|
||||
|
||||
if (quotient_32 != quotient_16l)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
/* now write quotient back to destination */
|
||||
AX = quotient_16l;
|
||||
DX = remainder_16;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_AXEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32s op1_32 = ((((Bit32u) DX) << 16) | ((Bit32u) AX));
|
||||
|
||||
/* check MIN_INT case */
|
||||
if (op1_32 == ((Bit32s)0x80000000))
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if (op2_16 == 0)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit32s quotient_32 = op1_32 / op2_16;
|
||||
Bit16s remainder_16 = op1_32 % op2_16;
|
||||
Bit16s quotient_16l = quotient_32 & 0xFFFF;
|
||||
|
||||
if (quotient_32 != quotient_16l)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
/* now write quotient back to destination */
|
||||
AX = quotient_16l;
|
||||
DX = remainder_16;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GwEwIwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
Bit16s op3_16 = i->Iw();
|
||||
|
||||
Bit32s product_32 = op2_16 * op3_16;
|
||||
Bit16u product_16 = (product_32 & 0xFFFF);
|
||||
|
||||
/* now write product back to destination */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), product_16);
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r16,r/m16,imm16: condition for clearing CF & OF:
|
||||
* result exactly fits within r16
|
||||
*/
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(product_16);
|
||||
if(product_32 != (Bit16s) product_32)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GwEwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16s op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
Bit16s op2_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
Bit32s product_32 = op1_16 * op2_16;
|
||||
Bit16u product_16 = (product_32 & 0xFFFF);
|
||||
|
||||
/* now write product back to destination */
|
||||
BX_WRITE_16BIT_REG(i->nnn(), product_16);
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r16,r/m16: condition for clearing CF & OF:
|
||||
* result exactly fits within r16
|
||||
*/
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(product_16);
|
||||
if(product_32 != (Bit16s) product_32)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
177
simulators/bochs/cpu/mult32.cc
Normal file
177
simulators/bochs/cpu/mult32.cc
Normal file
@ -0,0 +1,177 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RAX EAX
|
||||
#define RDX EDX
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_EAXEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32 = EAX;
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
Bit64u product_64 = ((Bit64u) op1_32) * ((Bit64u) op2_32);
|
||||
Bit32u product_32l = GET32L(product_64);
|
||||
Bit32u product_32h = GET32H(product_64);
|
||||
|
||||
/* now write product back to destination */
|
||||
RAX = product_32l;
|
||||
RDX = product_32h;
|
||||
|
||||
/* set EFLAGS */
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(product_32l);
|
||||
if(product_32h != 0)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_EAXEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32s op1_32 = EAX;
|
||||
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
Bit64s product_64 = ((Bit64s) op1_32) * ((Bit64s) op2_32);
|
||||
Bit32u product_32l = GET32L(product_64);
|
||||
Bit32u product_32h = GET32H(product_64);
|
||||
|
||||
/* now write product back to destination */
|
||||
RAX = product_32l;
|
||||
RDX = product_32h;
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r/m32: condition for clearing CF & OF:
|
||||
* EDX:EAX = sign-extend of EAX
|
||||
*/
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(product_32l);
|
||||
if(product_64 != (Bit32s)product_64)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_EAXEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
if (op2_32 == 0) {
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit64u op1_64 = (((Bit64u) EDX) << 32) + ((Bit64u) EAX);
|
||||
|
||||
Bit64u quotient_64 = op1_64 / op2_32;
|
||||
Bit32u remainder_32 = (Bit32u) (op1_64 % op2_32);
|
||||
Bit32u quotient_32l = (Bit32u) (quotient_64 & 0xFFFFFFFF);
|
||||
|
||||
if (quotient_64 != quotient_32l)
|
||||
{
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* set EFLAGS:
|
||||
* DIV affects the following flags: O,S,Z,A,P,C are undefined
|
||||
*/
|
||||
|
||||
/* now write quotient back to destination */
|
||||
RAX = quotient_32l;
|
||||
RDX = remainder_32;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_EAXEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64s op1_64 = (((Bit64u) EDX) << 32) | ((Bit64u) EAX);
|
||||
|
||||
/* check MIN_INT case */
|
||||
if (op1_64 == ((Bit64s)BX_CONST64(0x8000000000000000)))
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
if (op2_32 == 0)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit64s quotient_64 = op1_64 / op2_32;
|
||||
Bit32s remainder_32 = (Bit32s) (op1_64 % op2_32);
|
||||
Bit32s quotient_32l = (Bit32s) (quotient_64 & 0xFFFFFFFF);
|
||||
|
||||
if (quotient_64 != quotient_32l)
|
||||
{
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* set EFLAGS:
|
||||
* IDIV affects the following flags: O,S,Z,A,P,C are undefined
|
||||
*/
|
||||
|
||||
/* now write quotient back to destination */
|
||||
RAX = (Bit32u) quotient_32l;
|
||||
RDX = (Bit32u) remainder_32;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GdEdIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
Bit32s op3_32 = i->Id();
|
||||
|
||||
Bit64s product_64 = ((Bit64s) op2_32) * ((Bit64s) op3_32);
|
||||
Bit32u product_32 = (Bit32u)(product_64 & 0xFFFFFFFF);
|
||||
|
||||
/* now write product back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), product_32);
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r32,r/m32,imm32: condition for clearing CF & OF:
|
||||
* result exactly fits within r32
|
||||
*/
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(product_32);
|
||||
if(product_64 != (Bit32s) product_64)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GdEdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32s op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
Bit32s op2_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
Bit64s product_64 = ((Bit64s) op1_32) * ((Bit64s) op2_32);
|
||||
Bit32u product_32 = (Bit32u)(product_64 & 0xFFFFFFFF);
|
||||
|
||||
/* now write product back to destination */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), product_32);
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r32,r/m32: condition for clearing CF & OF:
|
||||
* result exactly fits within r32
|
||||
*/
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(product_32);
|
||||
if(product_64 != (Bit32s) product_64)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
367
simulators/bochs/cpu/mult64.cc
Normal file
367
simulators/bochs/cpu/mult64.cc
Normal file
@ -0,0 +1,367 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
static unsigned partial_add(Bit32u *sum,Bit32u b)
|
||||
{
|
||||
Bit32u t = *sum;
|
||||
*sum += b;
|
||||
return (*sum < t);
|
||||
}
|
||||
|
||||
void long_mul(Bit128u *product, Bit64u op1, Bit64u op2)
|
||||
{
|
||||
Bit32u op_1[2],op_2[2];
|
||||
Bit32u result[5];
|
||||
Bit64u nn;
|
||||
unsigned c;
|
||||
|
||||
int i,j,k;
|
||||
|
||||
op_1[0] = (Bit32u)(op1 & 0xffffffff);
|
||||
op_1[1] = (Bit32u)(op1 >> 32);
|
||||
op_2[0] = (Bit32u)(op2 & 0xffffffff);
|
||||
op_2[1] = (Bit32u)(op2 >> 32);
|
||||
|
||||
for (i = 0; i < 4; i++) result[i] = 0;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
nn = (Bit64u) op_1[i] * (Bit64u) op_2[j];
|
||||
k = i + j;
|
||||
c = partial_add(&result[k++], (Bit32u)(nn & 0xffffffff));
|
||||
c = partial_add(&result[k++], (Bit32u)(nn >> 32) + c);
|
||||
while (k < 4 && c != 0) {
|
||||
c = partial_add(&result[k++], c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
product->lo = result[0] + ((Bit64u) result[1] << 32);
|
||||
product->hi = result[2] + ((Bit64u) result[3] << 32);
|
||||
}
|
||||
|
||||
void long_neg(Bit128s *n)
|
||||
{
|
||||
Bit64u t = n->lo;
|
||||
n->lo = - (Bit64s)(n->lo);
|
||||
if (t - 1 > t) --n->hi;
|
||||
n->hi = ~n->hi;
|
||||
}
|
||||
|
||||
void long_imul(Bit128s *product, Bit64s op1, Bit64s op2)
|
||||
{
|
||||
unsigned s1,s2;
|
||||
|
||||
if ((s1 = (op1 < 0))) op1 = -op1;
|
||||
if ((s2 = (op2 < 0))) op2 = -op2;
|
||||
long_mul((Bit128u*)product,(Bit64u)op1,(Bit64u)op2);
|
||||
if (s1 ^ s2)
|
||||
long_neg(product);
|
||||
}
|
||||
|
||||
void long_shl(Bit128u *a)
|
||||
{
|
||||
Bit64u c = a->lo >> 63;
|
||||
a->lo <<= 1;
|
||||
a->hi <<= 1;
|
||||
a->hi |= c;
|
||||
}
|
||||
|
||||
void long_shr(Bit128u *a)
|
||||
{
|
||||
Bit64u c;
|
||||
c = a->hi << 63;
|
||||
a->hi >>= 1;
|
||||
a->lo >>= 1;
|
||||
a->lo |= c;
|
||||
}
|
||||
|
||||
unsigned long_sub(Bit128u *a,Bit128u *b)
|
||||
{
|
||||
Bit64u t = a->lo;
|
||||
a->lo -= b->lo;
|
||||
int c = (a->lo > t);
|
||||
t = a -> hi;
|
||||
a->hi -= b->hi + c;
|
||||
return(a->hi > t);
|
||||
}
|
||||
|
||||
int long_le(Bit128u *a,Bit128u *b)
|
||||
{
|
||||
if (a->hi == b->hi) {
|
||||
return(a->lo <= b->lo);
|
||||
} else {
|
||||
return(a->hi <= b->hi);
|
||||
}
|
||||
}
|
||||
|
||||
void long_div(Bit128u *quotient,Bit64u *remainder,const Bit128u *dividend,Bit64u divisor)
|
||||
{
|
||||
/*
|
||||
n := 0;
|
||||
while (divisor <= dividend) do
|
||||
inc(n);
|
||||
divisor := divisor * 2;
|
||||
end;
|
||||
quotient := 0;
|
||||
while n > 0 do
|
||||
divisor := divisor div 2;
|
||||
quotient := quotient * 2;
|
||||
temp := dividend;
|
||||
dividend := dividend - divisor;
|
||||
if temp > dividend then
|
||||
dividend := temp;
|
||||
else
|
||||
inc(quotient);
|
||||
end;
|
||||
dec(n);
|
||||
end;
|
||||
remainder := dividend;
|
||||
*/
|
||||
|
||||
Bit128u d,acc,q,temp;
|
||||
int n,c;
|
||||
|
||||
d.lo = divisor;
|
||||
d.hi = 0;
|
||||
acc.lo = dividend->lo;
|
||||
acc.hi = dividend->hi;
|
||||
q.lo = 0;
|
||||
q.hi = 0;
|
||||
n = 0;
|
||||
|
||||
while (long_le(&d,&acc) && n < 128) {
|
||||
long_shl(&d);
|
||||
n++;
|
||||
}
|
||||
|
||||
while (n > 0) {
|
||||
long_shr(&d);
|
||||
long_shl(&q);
|
||||
temp.lo = acc.lo;
|
||||
temp.hi = acc.hi;
|
||||
c = long_sub(&acc,&d);
|
||||
if (c) {
|
||||
acc.lo = temp.lo;
|
||||
acc.hi = temp.hi;
|
||||
} else {
|
||||
q.lo++;
|
||||
}
|
||||
n--;
|
||||
}
|
||||
|
||||
*remainder = acc.lo;
|
||||
quotient->lo = q.lo;
|
||||
quotient->hi = q.hi;
|
||||
}
|
||||
|
||||
void long_idiv(Bit128s *quotient,Bit64s *remainder,Bit128s *dividend,Bit64s divisor)
|
||||
{
|
||||
unsigned s1,s2;
|
||||
Bit128s temp;
|
||||
|
||||
temp = *dividend;
|
||||
if ((s1 = (temp.hi < 0))) {
|
||||
long_neg(&temp);
|
||||
}
|
||||
if ((s2 = (divisor < 0))) divisor = -divisor;
|
||||
long_div((Bit128u*)quotient,(Bit64u*)remainder,(Bit128u*)&temp,divisor);
|
||||
if (s1 ^ s2) {
|
||||
long_neg(quotient);
|
||||
}
|
||||
if (s1) {
|
||||
*remainder = -*remainder;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_RAXEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit128u product_128;
|
||||
|
||||
Bit64u op1_64 = RAX;
|
||||
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
// product_128 = ((Bit128u) op1_64) * ((Bit128u) op2_64);
|
||||
// product_64l = (Bit64u) (product_128 & 0xFFFFFFFFFFFFFFFF);
|
||||
// product_64h = (Bit64u) (product_128 >> 64);
|
||||
|
||||
long_mul(&product_128,op1_64,op2_64);
|
||||
|
||||
/* now write product back to destination */
|
||||
RAX = product_128.lo;
|
||||
RDX = product_128.hi;
|
||||
|
||||
/* set EFLAGS */
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
|
||||
if(product_128.hi != 0)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_RAXEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit128s product_128;
|
||||
|
||||
Bit64s op1_64 = RAX;
|
||||
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
// product_128 = ((Bit128s) op1_64) * ((Bit128s) op2_64);
|
||||
// product_64l = (Bit64u) (product_128 & 0xFFFFFFFFFFFFFFFF);
|
||||
// product_64h = (Bit64u) (product_128 >> 64);
|
||||
|
||||
long_imul(&product_128,op1_64,op2_64);
|
||||
|
||||
/* now write product back to destination */
|
||||
RAX = product_128.lo;
|
||||
RDX = product_128.hi;
|
||||
|
||||
/* set eflags:
|
||||
* IMUL r/m64: condition for clearing CF & OF:
|
||||
* RDX:RAX = sign-extend of RAX
|
||||
*/
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
|
||||
|
||||
/* magic compare between RDX:RAX and sign extended RAX */
|
||||
if (((Bit64u)(product_128.hi) + (product_128.lo >> 63)) != 0) {
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_RAXEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u remainder_64, quotient_64l;
|
||||
Bit128u op1_128, quotient_128;
|
||||
|
||||
Bit64u op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
if (op2_64 == 0) {
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
op1_128.lo = RAX;
|
||||
op1_128.hi = RDX;
|
||||
|
||||
// quotient_128 = op1_128 / op2_64;
|
||||
// remainder_64 = (Bit64u) (op1_128 % op2_64);
|
||||
// quotient_64l = (Bit64u) (quotient_128 & 0xFFFFFFFFFFFFFFFF);
|
||||
|
||||
long_div("ient_128,&remainder_64,&op1_128,op2_64);
|
||||
quotient_64l = quotient_128.lo;
|
||||
|
||||
if (quotient_128.hi != 0)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
/* set EFLAGS:
|
||||
* DIV affects the following flags: O,S,Z,A,P,C are undefined
|
||||
*/
|
||||
|
||||
/* now write quotient back to destination */
|
||||
RAX = quotient_64l;
|
||||
RDX = remainder_64;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_RAXEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64s remainder_64, quotient_64l;
|
||||
Bit128s op1_128, quotient_128;
|
||||
|
||||
op1_128.lo = RAX;
|
||||
op1_128.hi = RDX;
|
||||
|
||||
/* check MIN_INT case */
|
||||
if ((op1_128.hi == (Bit64s) BX_CONST64(0x8000000000000000)) && (!op1_128.lo))
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
if (op2_64 == 0) {
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// quotient_128 = op1_128 / op2_64;
|
||||
// remainder_64 = (Bit64s) (op1_128 % op2_64);
|
||||
// quotient_64l = (Bit64s) (quotient_128 & 0xFFFFFFFFFFFFFFFF);
|
||||
|
||||
long_idiv("ient_128,&remainder_64,&op1_128,op2_64);
|
||||
quotient_64l = quotient_128.lo;
|
||||
|
||||
if ((!(quotient_128.lo & BX_CONST64(0x8000000000000000)) && quotient_128.hi != (Bit64s) 0) ||
|
||||
(quotient_128.lo & BX_CONST64(0x8000000000000000)) && quotient_128.hi != (Bit64s) BX_CONST64(0xffffffffffffffff))
|
||||
{
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* set EFLAGS:
|
||||
* IDIV affects the following flags: O,S,Z,A,P,C are undefined
|
||||
*/
|
||||
|
||||
/* now write quotient back to destination */
|
||||
RAX = quotient_64l;
|
||||
RDX = remainder_64;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GqEqIdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit128s product_128;
|
||||
|
||||
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
Bit64s op3_64 = (Bit32s) i->Id();
|
||||
|
||||
long_imul(&product_128,op2_64,op3_64);
|
||||
|
||||
/* now write product back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), product_128.lo);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
|
||||
|
||||
if (((Bit64u)(product_128.hi) + (product_128.lo >> 63)) != 0) {
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_GqEqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit128s product_128;
|
||||
|
||||
Bit64s op1_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
Bit64s op2_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
long_imul(&product_128,op1_64,op2_64);
|
||||
|
||||
/* now write product back to destination */
|
||||
BX_WRITE_64BIT_REG(i->nnn(), product_128.lo);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(product_128.lo);
|
||||
|
||||
if (((Bit64u)(product_128.hi) + (product_128.lo >> 63)) != 0) {
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
117
simulators/bochs/cpu/mult8.cc
Normal file
117
simulators/bochs/cpu/mult8.cc
Normal file
@ -0,0 +1,117 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::MUL_ALEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op1 = AL;
|
||||
Bit8u op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
Bit32u product_16 = ((Bit16u) op1) * ((Bit16u) op2);
|
||||
|
||||
Bit8u product_8l = (product_16 & 0xFF);
|
||||
Bit8u product_8h = product_16 >> 8;
|
||||
|
||||
/* now write product back to destination */
|
||||
AX = product_16;
|
||||
|
||||
/* set EFLAGS */
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(product_8l);
|
||||
if(product_8h != 0)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IMUL_ALEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8s op1 = AL;
|
||||
Bit8s op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
Bit16s product_16 = op1 * op2;
|
||||
Bit8u product_8 = (product_16 & 0xFF);
|
||||
|
||||
/* now write product back to destination */
|
||||
AX = product_16;
|
||||
|
||||
/* set EFLAGS:
|
||||
* IMUL r/m8: condition for clearing CF & OF:
|
||||
* AX = sign-extend of AL to 16 bits
|
||||
*/
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(product_8);
|
||||
if(product_16 != (Bit8s) product_16)
|
||||
{
|
||||
ASSERT_FLAGS_OxxxxC();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::DIV_ALEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
if (op2 == 0) {
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit16u op1 = AX;
|
||||
|
||||
Bit16u quotient_16 = op1 / op2;
|
||||
Bit8u remainder_8 = op1 % op2;
|
||||
Bit8u quotient_8l = quotient_16 & 0xFF;
|
||||
|
||||
if (quotient_16 != quotient_8l)
|
||||
{
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* now write quotient back to destination */
|
||||
AL = quotient_8l;
|
||||
AH = remainder_8;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::IDIV_ALEbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16s op1 = AX;
|
||||
|
||||
/* check MIN_INT case */
|
||||
if (op1 == ((Bit16s)0x8000))
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit8s op2 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
if (op2 == 0)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
Bit16s quotient_16 = op1 / op2;
|
||||
Bit8s remainder_8 = op1 % op2;
|
||||
Bit8s quotient_8l = quotient_16 & 0xFF;
|
||||
|
||||
if (quotient_16 != quotient_8l)
|
||||
exception(BX_DE_EXCEPTION, 0);
|
||||
|
||||
/* now write quotient back to destination */
|
||||
AL = quotient_8l;
|
||||
AH = remainder_8;
|
||||
}
|
||||
1762
simulators/bochs/cpu/paging.cc
Normal file
1762
simulators/bochs/cpu/paging.cc
Normal file
File diff suppressed because it is too large
Load Diff
1102
simulators/bochs/cpu/proc_ctrl.cc
Normal file
1102
simulators/bochs/cpu/proc_ctrl.cc
Normal file
File diff suppressed because it is too large
Load Diff
899
simulators/bochs/cpu/protect_ctrl.cc
Normal file
899
simulators/bochs/cpu/protect_ctrl.cc
Normal file
@ -0,0 +1,899 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ARPL_EwGw(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op2_16, op1_16;
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_DEBUG(("ARPL: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* op1_16 is a register or memory reference */
|
||||
if (i->modC0()) {
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
if ((op1_16 & 0x03) < (op2_16 & 0x03)) {
|
||||
op1_16 = (op1_16 & 0xfffc) | (op2_16 & 0x03);
|
||||
/* now write back to destination */
|
||||
if (i->modC0()) {
|
||||
BX_WRITE_16BIT_REG(i->rm(), op1_16);
|
||||
}
|
||||
else {
|
||||
write_RMW_virtual_word(op1_16);
|
||||
}
|
||||
assert_ZF();
|
||||
}
|
||||
else {
|
||||
clear_ZF();
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LAR_GvEw(bxInstruction_c *i)
|
||||
{
|
||||
/* for 16 bit operand size mode */
|
||||
Bit16u raw_selector;
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit32u dword1, dword2;
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit32u dword3 = 0;
|
||||
#endif
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("LAR: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (i->modC0()) {
|
||||
raw_selector = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
raw_selector = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
/* if selector null, clear ZF and done */
|
||||
if ((raw_selector & 0xfffc) == 0) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
parse_selector(raw_selector, &selector);
|
||||
|
||||
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
||||
BX_DEBUG(("LAR: failed to fetch descriptor"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
if (descriptor.valid==0) {
|
||||
BX_DEBUG(("LAR: descriptor not valid"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
/* if source selector is visible at CPL & RPL,
|
||||
* within the descriptor table, and of type accepted by LAR instruction,
|
||||
* then load register with segment limit and set ZF
|
||||
*/
|
||||
|
||||
if (descriptor.segment) { /* normal segment */
|
||||
if (IS_CODE_SEGMENT(descriptor.type) && IS_CODE_SEGMENT_CONFORMING(descriptor.type)) {
|
||||
/* ignore DPL for conforming segments */
|
||||
}
|
||||
else {
|
||||
if (descriptor.dpl < CPL || descriptor.dpl < selector.rpl) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* system or gate segment */
|
||||
switch (descriptor.type) {
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
||||
case BX_286_CALL_GATE:
|
||||
case BX_TASK_GATE:
|
||||
if (long_mode()) {
|
||||
BX_DEBUG(("LAR: descriptor type in not accepted in long mode"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
case BX_SYS_SEGMENT_LDT:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
||||
case BX_386_CALL_GATE:
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long64_mode() || (descriptor.type == BX_386_CALL_GATE && long_mode()) ) {
|
||||
if (!fetch_raw_descriptor2_64(&selector, &dword1, &dword2, &dword3)) {
|
||||
BX_ERROR(("LAR: failed to fetch 64-bit descriptor"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
default: /* rest not accepted types to LAR */
|
||||
BX_DEBUG(("LAR: not accepted descriptor type"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
if (descriptor.dpl < CPL || descriptor.dpl < selector.rpl) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
assert_ZF();
|
||||
if (i->os32L()) {
|
||||
/* masked by 00FxFF00, where x is undefined */
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), dword2 & 0x00ffff00);
|
||||
}
|
||||
else {
|
||||
BX_WRITE_16BIT_REG(i->nnn(), dword2 & 0xff00);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSL_GvEw(bxInstruction_c *i)
|
||||
{
|
||||
/* for 16 bit operand size mode */
|
||||
Bit16u raw_selector;
|
||||
Bit32u limit32;
|
||||
bx_selector_t selector;
|
||||
Bit32u dword1, dword2;
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit32u dword3 = 0;
|
||||
#endif
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("LSL: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (i->modC0()) {
|
||||
raw_selector = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
raw_selector = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
/* if selector null, clear ZF and done */
|
||||
if ((raw_selector & 0xfffc) == 0) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
parse_selector(raw_selector, &selector);
|
||||
|
||||
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
||||
BX_DEBUG(("LSL: failed to fetch descriptor"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
Bit32u descriptor_dpl = (dword2 >> 13) & 0x03;
|
||||
|
||||
if ((dword2 & 0x00001000) == 0) { // system segment
|
||||
Bit32u type = (dword2 >> 8) & 0x0000000f;
|
||||
switch (type) {
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
||||
if (long_mode()) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
/* fall through */
|
||||
case BX_SYS_SEGMENT_LDT:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long64_mode()) {
|
||||
if (!fetch_raw_descriptor2_64(&selector, &dword1, &dword2, &dword3)) {
|
||||
BX_ERROR(("LSL: failed to fetch 64-bit descriptor"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (descriptor_dpl < CPL || descriptor_dpl < selector.rpl) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
|
||||
if (dword2 & 0x00800000)
|
||||
limit32 = (limit32 << 12) | 0x00000fff;
|
||||
break;
|
||||
default: /* rest not accepted types to LSL */
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else { // data & code segment
|
||||
limit32 = (dword1 & 0x0000ffff) | (dword2 & 0x000f0000);
|
||||
if (dword2 & 0x00800000)
|
||||
limit32 = (limit32 << 12) | 0x00000fff;
|
||||
if ((dword2 & 0x00000c00) != 0x00000c00) {
|
||||
// non-conforming code segment
|
||||
if (descriptor_dpl < CPL || descriptor_dpl < selector.rpl) {
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* all checks pass, limit32 is now byte granular, write to op1 */
|
||||
assert_ZF();
|
||||
|
||||
if (i->os32L()) {
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), limit32);
|
||||
}
|
||||
else {
|
||||
// chop off upper 16 bits
|
||||
BX_WRITE_16BIT_REG(i->nnn(), (Bit16u) limit32);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SLDT_Ew(bxInstruction_c *i)
|
||||
{
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("SLDT: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit16u val16 = BX_CPU_THIS_PTR ldtr.selector.value;
|
||||
if (i->modC0()) {
|
||||
if (i->os32L()) {
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), val16);
|
||||
}
|
||||
else {
|
||||
BX_WRITE_16BIT_REG(i->rm(), val16);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
write_virtual_word(i->seg(), eaddr, val16);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::STR_Ew(bxInstruction_c *i)
|
||||
{
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("STR: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit16u val16 = BX_CPU_THIS_PTR tr.selector.value;
|
||||
if (i->modC0()) {
|
||||
if (i->os32L()) {
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), val16);
|
||||
}
|
||||
else {
|
||||
BX_WRITE_16BIT_REG(i->rm(), val16);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
write_virtual_word(i->seg(), eaddr, val16);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LLDT_Ew(bxInstruction_c *i)
|
||||
{
|
||||
/* protected mode */
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit16u raw_selector;
|
||||
Bit32u dword1, dword2;
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit32u dword3 = 0;
|
||||
#endif
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("LLDT: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (CPL != 0) {
|
||||
BX_ERROR(("LLDT: The current priveledge level is not 0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
|
||||
#endif
|
||||
|
||||
if (i->modC0()) {
|
||||
raw_selector = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
raw_selector = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
/* if selector is NULL, invalidate and done */
|
||||
if ((raw_selector & 0xfffc) == 0) {
|
||||
BX_CPU_THIS_PTR ldtr.selector.value = raw_selector;
|
||||
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* parse fields in selector */
|
||||
parse_selector(raw_selector, &selector);
|
||||
|
||||
// #GP(selector) if the selector operand does not point into GDT
|
||||
if (selector.ti != 0) {
|
||||
BX_ERROR(("LLDT: selector.ti != 0"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* fetch descriptor; call handles out of limits checks */
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
||||
fetch_raw_descriptor_64(&selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
/* if selector doesn't point to an LDT descriptor #GP(selector) */
|
||||
if (descriptor.valid == 0 || descriptor.segment ||
|
||||
descriptor.type != BX_SYS_SEGMENT_LDT)
|
||||
{
|
||||
BX_ERROR(("LLDT: doesn't point to an LDT descriptor!"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* #NP(selector) if LDT descriptor is not present */
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("LLDT: LDT descriptor not present!"));
|
||||
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
||||
descriptor.u.segment.base |= ((Bit64u)(dword3) << 32);
|
||||
BX_DEBUG(("64 bit LDT base = 0x%08x%08x",
|
||||
GET32H(descriptor.u.segment.base), GET32L(descriptor.u.segment.base)));
|
||||
if (!IsCanonical(descriptor.u.segment.base)) {
|
||||
BX_ERROR(("LLDT: non-canonical LDT descriptor base!"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BX_CPU_THIS_PTR ldtr.selector = selector;
|
||||
BX_CPU_THIS_PTR ldtr.cache = descriptor;
|
||||
BX_CPU_THIS_PTR ldtr.cache.valid = 1;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LTR_Ew(bxInstruction_c *i)
|
||||
{
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit16u raw_selector;
|
||||
Bit32u dword1, dword2;
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit32u dword3 = 0;
|
||||
#endif
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("LTR: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (CPL != 0) {
|
||||
BX_ERROR(("LTR: The current priveledge level is not 0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_LDTR_TR_ACCESS);
|
||||
#endif
|
||||
|
||||
if (i->modC0()) {
|
||||
raw_selector = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
raw_selector = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
/* if selector is NULL, invalidate and done */
|
||||
if ((raw_selector & BX_SELECTOR_RPL_MASK) == 0) {
|
||||
BX_ERROR(("LTR: loading with NULL selector!"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
/* parse fields in selector, then check for null selector */
|
||||
parse_selector(raw_selector, &selector);
|
||||
|
||||
if (selector.ti) {
|
||||
BX_ERROR(("LTR: selector.ti != 0"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* fetch descriptor; call handles out of limits checks */
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
||||
fetch_raw_descriptor_64(&selector, &dword1, &dword2, &dword3, BX_GP_EXCEPTION);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
/* #GP(selector) if object is not a TSS or is already busy */
|
||||
if (descriptor.valid==0 || descriptor.segment ||
|
||||
(descriptor.type!=BX_SYS_SEGMENT_AVAIL_286_TSS &&
|
||||
descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS))
|
||||
{
|
||||
BX_ERROR(("LTR: doesn't point to an available TSS descriptor!"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode() && descriptor.type!=BX_SYS_SEGMENT_AVAIL_386_TSS) {
|
||||
BX_ERROR(("LTR: doesn't point to an available TSS386 descriptor in long mode!"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* #NP(selector) if TSS descriptor is not present */
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("LTR: TSS descriptor not present!"));
|
||||
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64) {
|
||||
descriptor.u.segment.base |= ((Bit64u)(dword3) << 32);
|
||||
BX_DEBUG(("64 bit TSS base = 0x%08x%08x",
|
||||
GET32H(descriptor.u.segment.base), GET32L(descriptor.u.segment.base)));
|
||||
if (!IsCanonical(descriptor.u.segment.base)) {
|
||||
BX_ERROR(("LTR: non-canonical TSS descriptor base!"));
|
||||
exception(BX_GP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
BX_CPU_THIS_PTR tr.selector = selector;
|
||||
BX_CPU_THIS_PTR tr.cache = descriptor;
|
||||
BX_CPU_THIS_PTR tr.cache.valid = 1;
|
||||
// tr.cache.type should not have busy bit, or it would not get
|
||||
// through the conditions above.
|
||||
BX_ASSERT((BX_CPU_THIS_PTR tr.cache.type & 2) == 0);
|
||||
BX_CPU_THIS_PTR tr.cache.type |= 2; // mark as busy
|
||||
|
||||
/* mark as busy */
|
||||
if (!(dword2 & 0x0200)) {
|
||||
dword2 |= 0x0200; /* set busy bit */
|
||||
access_write_linear(BX_CPU_THIS_PTR gdtr.base + selector.index*8 + 4, 4, 0, &dword2);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VERR_Ew(bxInstruction_c *i)
|
||||
{
|
||||
/* for 16 bit operand size mode */
|
||||
Bit16u raw_selector;
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("VERR: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (i->modC0()) {
|
||||
raw_selector = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
raw_selector = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
/* if selector null, clear ZF and done */
|
||||
if ((raw_selector & 0xfffc) == 0) {
|
||||
BX_DEBUG(("VERR: null selector"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
/* if source selector is visible at CPL & RPL,
|
||||
* within the descriptor table, and of type accepted by VERR instruction,
|
||||
* then load register with segment limit and set ZF */
|
||||
parse_selector(raw_selector, &selector);
|
||||
|
||||
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
||||
/* not within descriptor table */
|
||||
BX_DEBUG(("VERR: not within descriptor table"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
if (descriptor.segment==0) { /* system or gate descriptor */
|
||||
BX_DEBUG(("VERR: system descriptor"));
|
||||
clear_ZF(); /* inaccessible */
|
||||
return;
|
||||
}
|
||||
|
||||
if (descriptor.valid==0) {
|
||||
BX_DEBUG(("VERR: valid bit cleared"));
|
||||
clear_ZF(); /* inaccessible */
|
||||
return;
|
||||
}
|
||||
|
||||
/* normal data/code segment */
|
||||
if (IS_CODE_SEGMENT(descriptor.type)) { /* code segment */
|
||||
/* ignore DPL for readable conforming segments */
|
||||
if (IS_CODE_SEGMENT_CONFORMING(descriptor.type) &&
|
||||
IS_CODE_SEGMENT_READABLE(descriptor.type))
|
||||
{
|
||||
BX_DEBUG(("VERR: conforming code, OK"));
|
||||
assert_ZF(); /* accessible */
|
||||
return;
|
||||
}
|
||||
if (!IS_CODE_SEGMENT_READABLE(descriptor.type)) {
|
||||
BX_DEBUG(("VERR: code not readable"));
|
||||
clear_ZF(); /* inaccessible */
|
||||
return;
|
||||
}
|
||||
/* readable, non-conforming code segment */
|
||||
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
||||
BX_DEBUG(("VERR: non-conforming code not withing priv level"));
|
||||
clear_ZF(); /* inaccessible */
|
||||
}
|
||||
else {
|
||||
assert_ZF(); /* accessible */
|
||||
}
|
||||
}
|
||||
else { /* data segment */
|
||||
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
||||
BX_DEBUG(("VERR: data seg not withing priv level"));
|
||||
clear_ZF(); /* not accessible */
|
||||
}
|
||||
else {
|
||||
assert_ZF(); /* accessible */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VERW_Ew(bxInstruction_c *i)
|
||||
{
|
||||
/* for 16 bit operand size mode */
|
||||
Bit16u raw_selector;
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
if (! protected_mode()) {
|
||||
BX_ERROR(("VERW: not recognized in real or virtual-8086 mode"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (i->modC0()) {
|
||||
raw_selector = BX_READ_16BIT_REG(i->rm());
|
||||
}
|
||||
else {
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
raw_selector = read_virtual_word(i->seg(), eaddr);
|
||||
}
|
||||
|
||||
/* if selector null, clear ZF and done */
|
||||
if ((raw_selector & 0xfffc) == 0) {
|
||||
BX_DEBUG(("VERW: null selector"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
/* if source selector is visible at CPL & RPL,
|
||||
* within the descriptor table, and of type accepted by VERW instruction,
|
||||
* then load register with segment limit and set ZF */
|
||||
parse_selector(raw_selector, &selector);
|
||||
|
||||
if (!fetch_raw_descriptor2(&selector, &dword1, &dword2)) {
|
||||
/* not within descriptor table */
|
||||
BX_DEBUG(("VERW: not within descriptor table"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
/* rule out system segments & code segments */
|
||||
if (descriptor.segment==0 || IS_CODE_SEGMENT(descriptor.type)) {
|
||||
BX_DEBUG(("VERW: system seg or code"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
if (descriptor.valid==0) {
|
||||
BX_DEBUG(("VERW: valid bit cleared"));
|
||||
clear_ZF();
|
||||
return;
|
||||
}
|
||||
|
||||
/* data segment */
|
||||
if (IS_DATA_SEGMENT_WRITEABLE(descriptor.type)) { /* writable */
|
||||
if ((descriptor.dpl<CPL) || (descriptor.dpl<selector.rpl)) {
|
||||
BX_DEBUG(("VERW: writable data seg not within priv level"));
|
||||
clear_ZF(); /* not accessible */
|
||||
}
|
||||
else {
|
||||
assert_ZF(); /* accessible */
|
||||
}
|
||||
}
|
||||
else {
|
||||
BX_DEBUG(("VERW: data seg not writable"));
|
||||
clear_ZF(); /* not accessible */
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SGDT_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit16u limit_16 = BX_CPU_THIS_PTR gdtr.limit;
|
||||
Bit32u base_32 = (Bit32u) BX_CPU_THIS_PTR gdtr.base;
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word_32(i->seg(), eaddr, limit_16);
|
||||
write_virtual_dword_32(i->seg(), (eaddr+2) & i->asize_mask(), base_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SIDT_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit16u limit_16 = BX_CPU_THIS_PTR idtr.limit;
|
||||
Bit32u base_32 = (Bit32u) BX_CPU_THIS_PTR idtr.base;
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word_32(i->seg(), eaddr, limit_16);
|
||||
write_virtual_dword_32(i->seg(), (eaddr+2) & i->asize_mask(), base_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGDT_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
if (v8086_mode()) {
|
||||
BX_ERROR(("LGDT: not recognized in virtual-8086 mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (!real_mode() && CPL!=0) {
|
||||
BX_ERROR(("LGDT: CPL!=0 in protected mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u limit_16 = read_virtual_word_32(i->seg(), eaddr);
|
||||
Bit32u base_32 = read_virtual_dword_32(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
if (i->os32L() == 0) base_32 &= 0x00ffffff; /* ignore upper 8 bits */
|
||||
|
||||
BX_CPU_THIS_PTR gdtr.limit = limit_16;
|
||||
BX_CPU_THIS_PTR gdtr.base = base_32;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LIDT_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
if (v8086_mode()) {
|
||||
BX_ERROR(("LIDT: not recognized in virtual-8086 mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (!real_mode() && CPL!=0) {
|
||||
BX_ERROR(("LIDT: CPL!=0 in protected mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u limit_16 = read_virtual_word_32(i->seg(), eaddr);
|
||||
Bit32u base_32 = read_virtual_dword_32(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
if (i->os32L() == 0) base_32 &= 0x00ffffff; /* ignore upper 8 bits */
|
||||
|
||||
BX_CPU_THIS_PTR idtr.limit = limit_16;
|
||||
BX_CPU_THIS_PTR idtr.base = base_32;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SGDT64_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit16u limit_16 = BX_CPU_THIS_PTR gdtr.limit;
|
||||
Bit64u base_64 = BX_CPU_THIS_PTR gdtr.base;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word_64(i->seg(), eaddr, limit_16);
|
||||
write_virtual_qword_64(i->seg(), (eaddr+2) & i->asize_mask(), base_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SIDT64_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
Bit16u limit_16 = BX_CPU_THIS_PTR idtr.limit;
|
||||
Bit64u base_64 = BX_CPU_THIS_PTR idtr.base;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word_64(i->seg(), eaddr, limit_16);
|
||||
write_virtual_qword_64(i->seg(), (eaddr+2) & i->asize_mask(), base_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGDT64_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
if (CPL!=0) {
|
||||
BX_ERROR(("LGDT64_Ms: CPL != 0 in long mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u base_64 = read_virtual_qword_64(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
if (! IsCanonical(base_64)) {
|
||||
BX_ERROR(("LGDT64_Ms: loaded base64 address is not in canonical form!"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
Bit16u limit_16 = read_virtual_word_64(i->seg(), eaddr);
|
||||
|
||||
BX_CPU_THIS_PTR gdtr.limit = limit_16;
|
||||
BX_CPU_THIS_PTR gdtr.base = base_64;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LIDT64_Ms(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode == BX_MODE_LONG_64);
|
||||
|
||||
if (CPL != 0) {
|
||||
BX_ERROR(("LIDT64_Ms: CPL != 0 in long mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest)
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_DESCRIPTOR_TABLE_VMEXIT))
|
||||
VMexit_Instruction(i, VMX_VMEXIT_GDTR_IDTR_ACCESS);
|
||||
#endif
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u base_64 = read_virtual_qword_64(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
if (! IsCanonical(base_64)) {
|
||||
BX_ERROR(("LIDT64_Ms: loaded base64 address is not in canonical form!"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
Bit16u limit_16 = read_virtual_word_64(i->seg(), eaddr);
|
||||
|
||||
BX_CPU_THIS_PTR idtr.limit = limit_16;
|
||||
BX_CPU_THIS_PTR idtr.base = base_64;
|
||||
}
|
||||
|
||||
#endif
|
||||
69
simulators/bochs/cpu/resolver.cc
Normal file
69
simulators/bochs/cpu/resolver.cc
Normal file
@ -0,0 +1,69 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
//
|
||||
// 16 bit address size
|
||||
//
|
||||
|
||||
bx_address BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::BxResolve16BaseIndex(bxInstruction_c *i)
|
||||
{
|
||||
return (Bit16u) (BX_READ_16BIT_REG(i->sibBase()) + BX_READ_16BIT_REG(i->sibIndex()) + i->displ16s());
|
||||
}
|
||||
|
||||
//
|
||||
// 32 bit address size
|
||||
//
|
||||
|
||||
bx_address BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::BxResolve32Base(bxInstruction_c *i)
|
||||
{
|
||||
return (Bit32u) (BX_READ_32BIT_REG(i->sibBase()) + i->displ32s());
|
||||
}
|
||||
bx_address BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::BxResolve32BaseIndex(bxInstruction_c *i)
|
||||
{
|
||||
return (Bit32u) (BX_READ_32BIT_REG(i->sibBase()) + (BX_READ_32BIT_REG(i->sibIndex()) << i->sibScale()) + i->displ32s());
|
||||
}
|
||||
|
||||
//
|
||||
// 64 bit address size
|
||||
//
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
bx_address BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::BxResolve64Base(bxInstruction_c *i)
|
||||
{
|
||||
return BX_READ_64BIT_REG(i->sibBase()) + i->displ32s();
|
||||
}
|
||||
bx_address BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::BxResolve64BaseIndex(bxInstruction_c *i)
|
||||
{
|
||||
return BX_READ_64BIT_REG(i->sibBase()) + (BX_READ_64BIT_REG(i->sibIndex()) << i->sibScale()) + i->displ32s();
|
||||
}
|
||||
#endif
|
||||
236
simulators/bochs/cpu/ret_far.cc
Executable file
236
simulators/bochs/cpu/ret_far.cc
Executable file
@ -0,0 +1,236 @@
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2005-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 B 02110-1301 USA
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier merging cpu64 & cpu code.
|
||||
#define RIP EIP
|
||||
#define RSP ESP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::return_protected(bxInstruction_c *i, Bit16u pop_bytes)
|
||||
{
|
||||
Bit16u raw_cs_selector, raw_ss_selector;
|
||||
bx_selector_t cs_selector, ss_selector;
|
||||
bx_descriptor_t cs_descriptor, ss_descriptor;
|
||||
Bit32u stack_param_offset;
|
||||
bx_address return_RIP, return_RSP, temp_RSP;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
/* + 6+N*2: SS | +12+N*4: SS | +24+N*8 SS */
|
||||
/* + 4+N*2: SP | + 8+N*4: ESP | +16+N*8 RSP */
|
||||
/* parm N | + parm N | + parm N */
|
||||
/* parm 3 | + parm 3 | + parm 3 */
|
||||
/* parm 2 | + parm 2 | + parm 2 */
|
||||
/* + 4: parm 1 | + 8: parm 1 | +16: parm 1 */
|
||||
/* + 2: CS | + 4: CS | + 8: CS */
|
||||
/* + 0: IP | + 0: EIP | + 0: RIP */
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (StackAddrSize64()) temp_RSP = RSP;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) temp_RSP = ESP;
|
||||
else temp_RSP = SP;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
raw_cs_selector = (Bit16u) read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 8);
|
||||
return_RIP = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP);
|
||||
stack_param_offset = 16;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->os32L()) {
|
||||
raw_cs_selector = (Bit16u) read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 4);
|
||||
return_RIP = read_virtual_dword(BX_SEG_REG_SS, temp_RSP);
|
||||
stack_param_offset = 8;
|
||||
}
|
||||
else {
|
||||
raw_cs_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 2);
|
||||
return_RIP = read_virtual_word(BX_SEG_REG_SS, temp_RSP);
|
||||
stack_param_offset = 4;
|
||||
}
|
||||
|
||||
// selector must be non-null else #GP(0)
|
||||
if ((raw_cs_selector & 0xfffc) == 0) {
|
||||
BX_ERROR(("return_protected: CS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
parse_selector(raw_cs_selector, &cs_selector);
|
||||
|
||||
// selector index must be within its descriptor table limits,
|
||||
// else #GP(selector)
|
||||
fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
|
||||
// descriptor AR byte must indicate code segment, else #GP(selector)
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// return selector RPL must be >= CPL, else #GP(return selector)
|
||||
if (cs_selector.rpl < CPL) {
|
||||
BX_ERROR(("return_protected: CS.rpl < CPL"));
|
||||
exception(BX_GP_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// check code-segment descriptor
|
||||
check_cs(&cs_descriptor, raw_cs_selector, 0, cs_selector.rpl);
|
||||
|
||||
// if return selector RPL == CPL then
|
||||
// RETURN TO SAME PRIVILEGE LEVEL
|
||||
if (cs_selector.rpl == CPL)
|
||||
{
|
||||
BX_DEBUG(("return_protected: return to SAME PRIVILEGE LEVEL"));
|
||||
|
||||
branch_far64(&cs_selector, &cs_descriptor, return_RIP, CPL);
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (StackAddrSize64())
|
||||
RSP += stack_param_offset + pop_bytes;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
RSP = ESP + stack_param_offset + pop_bytes;
|
||||
else
|
||||
SP += stack_param_offset + pop_bytes;
|
||||
}
|
||||
}
|
||||
/* RETURN TO OUTER PRIVILEGE LEVEL */
|
||||
else {
|
||||
/* + 6+N*2: SS | +12+N*4: SS | +24+N*8 SS */
|
||||
/* + 4+N*2: SP | + 8+N*4: ESP | +16+N*8 RSP */
|
||||
/* parm N | + parm N | + parm N */
|
||||
/* parm 3 | + parm 3 | + parm 3 */
|
||||
/* parm 2 | + parm 2 | + parm 2 */
|
||||
/* + 4: parm 1 | + 8: parm 1 | +16: parm 1 */
|
||||
/* + 2: CS | + 4: CS | + 8: CS */
|
||||
/* + 0: IP | + 0: EIP | + 0: RIP */
|
||||
|
||||
BX_DEBUG(("return_protected: return to OUTER PRIVILEGE LEVEL"));
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
raw_ss_selector = read_virtual_word_64(BX_SEG_REG_SS, temp_RSP + 24 + pop_bytes);
|
||||
return_RSP = read_virtual_qword_64(BX_SEG_REG_SS, temp_RSP + 16 + pop_bytes);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (i->os32L()) {
|
||||
raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 12 + pop_bytes);
|
||||
return_RSP = read_virtual_dword(BX_SEG_REG_SS, temp_RSP + 8 + pop_bytes);
|
||||
}
|
||||
else {
|
||||
raw_ss_selector = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 6 + pop_bytes);
|
||||
return_RSP = read_virtual_word(BX_SEG_REG_SS, temp_RSP + 4 + pop_bytes);
|
||||
}
|
||||
|
||||
/* selector index must be within its descriptor table limits,
|
||||
* else #GP(selector) */
|
||||
parse_selector(raw_ss_selector, &ss_selector);
|
||||
|
||||
if ((raw_ss_selector & 0xfffc) == 0) {
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long_mode()) {
|
||||
if (! IS_LONG64_SEGMENT(cs_descriptor) || (cs_selector.rpl == 3)) {
|
||||
BX_ERROR(("return_protected: SS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
else // not in long or compatibility mode
|
||||
#endif
|
||||
{
|
||||
BX_ERROR(("return_protected: SS selector null"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &ss_descriptor);
|
||||
|
||||
/* selector RPL must = RPL of the return CS selector,
|
||||
* else #GP(selector) */
|
||||
if (ss_selector.rpl != cs_selector.rpl) {
|
||||
BX_ERROR(("return_protected: ss.rpl != cs.rpl"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* descriptor AR byte must indicate a writable data segment,
|
||||
* else #GP(selector) */
|
||||
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
|
||||
IS_CODE_SEGMENT(ss_descriptor.type) ||
|
||||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("return_protected: SS.AR byte not writable data"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* descriptor dpl must = RPL of the return CS selector,
|
||||
* else #GP(selector) */
|
||||
if (ss_descriptor.dpl != cs_selector.rpl) {
|
||||
BX_ERROR(("return_protected: SS.dpl != cs.rpl"));
|
||||
exception(BX_GP_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* segment must be present else #SS(selector) */
|
||||
if (! IS_PRESENT(ss_descriptor)) {
|
||||
BX_ERROR(("return_protected: ss.present == 0"));
|
||||
exception(BX_SS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
branch_far64(&cs_selector, &cs_descriptor, return_RIP, cs_selector.rpl);
|
||||
|
||||
if ((raw_ss_selector & 0xfffc) != 0) {
|
||||
// load SS:RSP from stack
|
||||
// load the SS-cache with SS descriptor
|
||||
load_ss(&ss_selector, &ss_descriptor, cs_selector.rpl);
|
||||
}
|
||||
#if BX_SUPPORT_X86_64
|
||||
else {
|
||||
// we are in 64-bit mode (checked above)
|
||||
load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], raw_ss_selector);
|
||||
}
|
||||
|
||||
if (StackAddrSize64())
|
||||
RSP = return_RSP + pop_bytes;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (ss_descriptor.u.segment.d_b)
|
||||
RSP = (Bit32u)(return_RSP + pop_bytes);
|
||||
else
|
||||
SP = (Bit16u)(return_RSP + pop_bytes);
|
||||
}
|
||||
|
||||
/* check ES, DS, FS, GS for validity */
|
||||
validate_seg_regs();
|
||||
}
|
||||
}
|
||||
200
simulators/bochs/cpu/segment_ctrl.cc
Normal file
200
simulators/bochs/cpu/segment_ctrl.cc
Normal file
@ -0,0 +1,200 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// LES/LDS can't be called from long64 mode
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LES_GwMp(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u reg_16 = read_virtual_word_32(i->seg(), eaddr);
|
||||
Bit16u es = read_virtual_word_32(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
|
||||
}
|
||||
|
||||
// LES/LDS can't be called from long64 mode
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LES_GdMp(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u es = read_virtual_word_32(i->seg(), (eaddr + 4) & i->asize_mask());
|
||||
Bit32u reg_32 = read_virtual_dword_32(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
|
||||
}
|
||||
|
||||
// LES/LDS can't be called from long64 mode
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LDS_GwMp(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u reg_16 = read_virtual_word_32(i->seg(), eaddr);
|
||||
Bit16u ds = read_virtual_word_32(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
|
||||
}
|
||||
|
||||
// LES/LDS can't be called from long64 mode
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LDS_GdMp(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u ds = read_virtual_word_32(i->seg(), (eaddr + 4) & i->asize_mask());
|
||||
Bit32u reg_32 = read_virtual_dword_32(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LFS_GwMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u reg_16 = read_virtual_word(i->seg(), eaddr);
|
||||
Bit16u fs = read_virtual_word(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LFS_GdMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u fs = read_virtual_word(i->seg(), (eaddr + 4) & i->asize_mask());
|
||||
Bit32u reg_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LFS_GqMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u fs = read_virtual_word_64(i->seg(), (eaddr + 8) & i->asize_mask());
|
||||
Bit64u reg_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
|
||||
|
||||
BX_WRITE_64BIT_REG(i->nnn(), reg_64);
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGS_GwMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u reg_16 = read_virtual_word(i->seg(), eaddr);
|
||||
Bit16u gs = read_virtual_word(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGS_GdMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u gs = read_virtual_word(i->seg(), (eaddr + 4) & i->asize_mask());
|
||||
Bit32u reg_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LGS_GqMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u gs = read_virtual_word_64(i->seg(), (eaddr + 8) & i->asize_mask());
|
||||
Bit64u reg_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
|
||||
|
||||
BX_WRITE_64BIT_REG(i->nnn(), reg_64);
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSS_GwMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u reg_16 = read_virtual_word(i->seg(), eaddr);
|
||||
Bit16u ss = read_virtual_word(i->seg(), (eaddr + 2) & i->asize_mask());
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
|
||||
|
||||
BX_WRITE_16BIT_REG(i->nnn(), reg_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSS_GdMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u ss = read_virtual_word(i->seg(), (eaddr + 4) & i->asize_mask());
|
||||
Bit32u reg_32 = read_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->nnn(), reg_32);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LSS_GqMp(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u ss = read_virtual_word_64(i->seg(), (eaddr + 8) & i->asize_mask());
|
||||
Bit64u reg_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
|
||||
|
||||
BX_WRITE_64BIT_REG(i->nnn(), reg_64);
|
||||
}
|
||||
#endif
|
||||
679
simulators/bochs/cpu/segment_ctrl_pro.cc
Normal file
679
simulators/bochs/cpu/segment_ctrl_pro.cc
Normal file
@ -0,0 +1,679 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::load_seg_reg(bx_segment_reg_t *seg, Bit16u new_value)
|
||||
{
|
||||
if (protected_mode())
|
||||
{
|
||||
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS])
|
||||
{
|
||||
bx_selector_t ss_selector;
|
||||
bx_descriptor_t descriptor;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
parse_selector(new_value, &ss_selector);
|
||||
|
||||
if ((new_value & 0xfffc) == 0) { /* null selector */
|
||||
#if BX_SUPPORT_X86_64
|
||||
// allow SS = 0 in 64 bit mode only with cpl != 3 and rpl=cpl
|
||||
if (long64_mode() && CPL != 3 && ss_selector.rpl == CPL) {
|
||||
load_null_selector(seg, new_value);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
BX_ERROR(("load_seg_reg(SS): loading null selector"));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
fetch_raw_descriptor(&ss_selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
|
||||
/* selector's RPL must = CPL, else #GP(selector) */
|
||||
if (ss_selector.rpl != CPL) {
|
||||
BX_ERROR(("load_seg_reg(SS): rpl != CPL"));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
if (descriptor.valid==0) {
|
||||
BX_ERROR(("load_seg_reg(SS): valid bit cleared"));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
/* AR byte must indicate a writable data segment else #GP(selector) */
|
||||
if (descriptor.segment==0 || IS_CODE_SEGMENT(descriptor.type) ||
|
||||
IS_DATA_SEGMENT_WRITEABLE(descriptor.type) == 0)
|
||||
{
|
||||
BX_ERROR(("load_seg_reg(SS): not writable data segment"));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
/* DPL in the AR byte must equal CPL else #GP(selector) */
|
||||
if (descriptor.dpl != CPL) {
|
||||
BX_ERROR(("load_seg_reg(SS): dpl != CPL"));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
/* segment must be marked PRESENT else #SS(selector) */
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("load_seg_reg(SS): not present"));
|
||||
exception(BX_SS_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
touch_segment(&ss_selector, &descriptor);
|
||||
|
||||
/* load SS with selector, load SS cache with descriptor */
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = ss_selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = descriptor;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
else if ((seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS]) ||
|
||||
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES]) ||
|
||||
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS]) ||
|
||||
(seg==&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS])
|
||||
)
|
||||
{
|
||||
bx_descriptor_t descriptor;
|
||||
bx_selector_t selector;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
if ((new_value & 0xfffc) == 0) { /* null selector */
|
||||
load_null_selector(seg, new_value);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_selector(new_value, &selector);
|
||||
fetch_raw_descriptor(&selector, &dword1, &dword2, BX_GP_EXCEPTION);
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
if (descriptor.valid==0) {
|
||||
BX_ERROR(("load_seg_reg(%s, 0x%04x): invalid segment", strseg(seg), new_value));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
/* AR byte must indicate data or readable code segment else #GP(selector) */
|
||||
if (descriptor.segment==0 || (IS_CODE_SEGMENT(descriptor.type) &&
|
||||
IS_CODE_SEGMENT_READABLE(descriptor.type) == 0))
|
||||
{
|
||||
BX_ERROR(("load_seg_reg(%s, 0x%04x): not data or readable code", strseg(seg), new_value));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
/* If data or non-conforming code, then both the RPL and the CPL
|
||||
* must be less than or equal to DPL in AR byte else #GP(selector) */
|
||||
if (IS_DATA_SEGMENT(descriptor.type) ||
|
||||
IS_CODE_SEGMENT_NON_CONFORMING(descriptor.type))
|
||||
{
|
||||
if ((selector.rpl > descriptor.dpl) || (CPL > descriptor.dpl)) {
|
||||
BX_ERROR(("load_seg_reg(%s, 0x%04x): RPL & CPL must be <= DPL", strseg(seg), new_value));
|
||||
exception(BX_GP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
/* segment must be marked PRESENT else #NP(selector) */
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("load_seg_reg(%s, 0x%04x): segment not present", strseg(seg), new_value));
|
||||
exception(BX_NP_EXCEPTION, new_value & 0xfffc);
|
||||
}
|
||||
|
||||
touch_segment(&selector, &descriptor);
|
||||
|
||||
/* load segment register with selector */
|
||||
/* load segment register-cache with descriptor */
|
||||
seg->selector = selector;
|
||||
seg->cache = descriptor;
|
||||
seg->cache.valid = 1;
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
BX_PANIC(("load_seg_reg(): invalid segment register passed!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* real or v8086 mode */
|
||||
|
||||
/* www.x86.org:
|
||||
According to Intel, each time any segment register is loaded in real
|
||||
mode, the base address is calculated as 16 times the segment value,
|
||||
while the access rights and size limit attributes are given fixed,
|
||||
"real-mode compatible" values. This is not true. In fact, only the CS
|
||||
descriptor caches for the 286, 386, and 486 get loaded with fixed
|
||||
values each time the segment register is loaded. Loading CS, or any
|
||||
other segment register in real mode, on later Intel processors doesn't
|
||||
change the access rights or the segment size limit attributes stored
|
||||
in the descriptor cache registers. For these segments, the access
|
||||
rights and segment size limit attributes from any previous setting are
|
||||
honored. */
|
||||
|
||||
seg->selector.value = new_value;
|
||||
seg->selector.rpl = real_mode() ? 0 : 3;
|
||||
seg->cache.valid = 1;
|
||||
seg->cache.u.segment.base = new_value << 4;
|
||||
seg->cache.segment = 1; /* regular segment */
|
||||
seg->cache.p = 1; /* present */
|
||||
|
||||
/* Do not modify segment limit and AR bytes when in real mode */
|
||||
/* Support for big real mode */
|
||||
if (!real_mode()) {
|
||||
seg->cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
||||
seg->cache.dpl = 3; /* we are in v8086 mode */
|
||||
seg->cache.u.segment.limit_scaled = 0xffff;
|
||||
seg->cache.u.segment.g = 0; /* byte granular */
|
||||
seg->cache.u.segment.d_b = 0; /* default 16bit size */
|
||||
#if BX_SUPPORT_X86_64
|
||||
seg->cache.u.segment.l = 0; /* default 16bit size */
|
||||
#endif
|
||||
seg->cache.u.segment.avl = 0;
|
||||
}
|
||||
|
||||
if (seg == &BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS]) {
|
||||
invalidate_prefetch_q();
|
||||
updateFetchModeMask(/* CS reloaded */);
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck(/* CPL change */);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::load_null_selector(bx_segment_reg_t *seg, unsigned value)
|
||||
{
|
||||
BX_ASSERT((value & 0xfffc) == 0);
|
||||
|
||||
seg->selector.index = 0;
|
||||
seg->selector.ti = 0;
|
||||
seg->selector.rpl = BX_SELECTOR_RPL(value);
|
||||
seg->selector.value = value;
|
||||
|
||||
seg->cache.valid = 0; /* invalidate null selector */
|
||||
seg->cache.p = 0;
|
||||
seg->cache.dpl = 0;
|
||||
seg->cache.segment = 1; /* data/code segment */
|
||||
seg->cache.type = 0;
|
||||
|
||||
seg->cache.u.segment.base = 0;
|
||||
seg->cache.u.segment.limit_scaled = 0;
|
||||
seg->cache.u.segment.g = 0;
|
||||
seg->cache.u.segment.d_b = 0;
|
||||
seg->cache.u.segment.avl = 0;
|
||||
#if BX_SUPPORT_X86_64
|
||||
seg->cache.u.segment.l = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void BX_CPU_C::validate_seg_reg(unsigned seg)
|
||||
{
|
||||
/*
|
||||
FOR (seg = ES, DS, FS, GS)
|
||||
DO
|
||||
IF ((seg.attr.dpl < CPL) && ((seg.attr.type = 'data')
|
||||
|| (seg.attr.type = 'non-conforming-code')))
|
||||
{
|
||||
seg = NULL // can't use lower dpl data segment at higher cpl
|
||||
}
|
||||
END
|
||||
*/
|
||||
|
||||
bx_segment_reg_t *segment = &BX_CPU_THIS_PTR sregs[seg];
|
||||
|
||||
if (segment->cache.dpl < CPL)
|
||||
{
|
||||
// invalidate if data or non-conforming code segment
|
||||
if (segment->cache.valid==0 || segment->cache.segment==0 ||
|
||||
IS_DATA_SEGMENT(segment->cache.type) ||
|
||||
IS_CODE_SEGMENT_NON_CONFORMING(segment->cache.type))
|
||||
{
|
||||
segment->selector.value = 0;
|
||||
segment->cache.valid = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPU_C::validate_seg_regs(void)
|
||||
{
|
||||
validate_seg_reg(BX_SEG_REG_ES);
|
||||
validate_seg_reg(BX_SEG_REG_DS);
|
||||
validate_seg_reg(BX_SEG_REG_FS);
|
||||
validate_seg_reg(BX_SEG_REG_GS);
|
||||
}
|
||||
|
||||
void parse_selector(Bit16u raw_selector, bx_selector_t *selector)
|
||||
{
|
||||
selector->value = raw_selector;
|
||||
selector->index = raw_selector >> 3;
|
||||
selector->ti = (raw_selector >> 2) & 0x01;
|
||||
selector->rpl = raw_selector & 0x03;
|
||||
}
|
||||
|
||||
Bit8u get_ar_byte(const bx_descriptor_t *d)
|
||||
{
|
||||
return (d->type) |
|
||||
(d->segment << 4) |
|
||||
(d->dpl << 5) |
|
||||
(d->p << 7);
|
||||
}
|
||||
|
||||
void set_ar_byte(bx_descriptor_t *d, Bit8u ar_byte)
|
||||
{
|
||||
d->p = (ar_byte >> 7) & 0x01;
|
||||
d->dpl = (ar_byte >> 5) & 0x03;
|
||||
d->segment = (ar_byte >> 4) & 0x01;
|
||||
d->type = (ar_byte & 0x0f);
|
||||
}
|
||||
|
||||
Bit32u BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::get_descriptor_l(const bx_descriptor_t *d)
|
||||
{
|
||||
Bit32u limit = d->u.segment.limit_scaled;
|
||||
if (d->u.segment.g)
|
||||
limit >>= 12;
|
||||
|
||||
Bit32u val = ((d->u.segment.base & 0xffff) << 16) | (limit & 0xffff);
|
||||
|
||||
if (d->segment) {
|
||||
return(val);
|
||||
}
|
||||
else {
|
||||
switch (d->type) {
|
||||
case BX_SYS_SEGMENT_LDT:
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
||||
return(val);
|
||||
|
||||
default:
|
||||
BX_ERROR(("#get_descriptor_l(): type %d not finished", d->type));
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bit32u BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::get_descriptor_h(const bx_descriptor_t *d)
|
||||
{
|
||||
Bit32u val;
|
||||
|
||||
Bit32u limit = d->u.segment.limit_scaled;
|
||||
if (d->u.segment.g)
|
||||
limit >>= 12;
|
||||
|
||||
if (d->segment) {
|
||||
val = (d->u.segment.base & 0xff000000) |
|
||||
((d->u.segment.base >> 16) & 0x000000ff) |
|
||||
(d->type << 8) |
|
||||
(d->segment << 12) |
|
||||
(d->dpl << 13) |
|
||||
(d->p << 15) | (limit & 0xf0000) |
|
||||
(d->u.segment.avl << 20) |
|
||||
#if BX_SUPPORT_X86_64
|
||||
(d->u.segment.l << 21) |
|
||||
#endif
|
||||
(d->u.segment.d_b << 22) |
|
||||
(d->u.segment.g << 23);
|
||||
return(val);
|
||||
}
|
||||
else {
|
||||
switch (d->type) {
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
||||
case BX_SYS_SEGMENT_LDT:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
||||
val = ((d->u.segment.base >> 16) & 0xff) |
|
||||
(d->type << 8) |
|
||||
(d->dpl << 13) |
|
||||
(d->p << 15) | (limit & 0xf0000) |
|
||||
(d->u.segment.avl << 20) |
|
||||
(d->u.segment.d_b << 22) |
|
||||
(d->u.segment.g << 23) |
|
||||
(d->u.segment.base & 0xff000000);
|
||||
return(val);
|
||||
|
||||
default:
|
||||
BX_ERROR(("#get_descriptor_h(): type %d not finished", d->type));
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::set_segment_ar_data(bx_segment_reg_t *seg, bx_bool valid,
|
||||
Bit16u raw_selector, bx_address base, Bit32u limit_scaled, Bit16u ar_data)
|
||||
{
|
||||
parse_selector(raw_selector, &seg->selector);
|
||||
|
||||
bx_descriptor_t *d = &seg->cache;
|
||||
|
||||
d->p = (ar_data >> 7) & 0x1;
|
||||
d->dpl = (ar_data >> 5) & 0x3;
|
||||
d->segment = (ar_data >> 4) & 0x1;
|
||||
d->type = (ar_data & 0x0f);
|
||||
|
||||
d->valid = valid;
|
||||
|
||||
if (d->segment) { /* data/code segment descriptors */
|
||||
d->u.segment.g = (ar_data >> 15) & 0x1;
|
||||
d->u.segment.d_b = (ar_data >> 14) & 0x1;
|
||||
#if BX_SUPPORT_X86_64
|
||||
d->u.segment.l = (ar_data >> 13) & 0x1;
|
||||
#endif
|
||||
d->u.segment.avl = (ar_data >> 12) & 0x1;
|
||||
|
||||
d->u.segment.base = base;
|
||||
d->u.segment.limit_scaled = limit_scaled;
|
||||
}
|
||||
else {
|
||||
switch(d->type) {
|
||||
case BX_SYS_SEGMENT_LDT:
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
||||
d->u.segment.avl = (ar_data >> 12) & 0x1;
|
||||
d->u.segment.d_b = (ar_data >> 14) & 0x1;
|
||||
d->u.segment.g = (ar_data >> 15) & 0x1;
|
||||
d->u.segment.base = base;
|
||||
d->u.segment.limit_scaled = limit_scaled;
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_ERROR(("set_segment_ar_data(): case %u unsupported, valid=%d", (unsigned) d->type, d->valid));
|
||||
}
|
||||
}
|
||||
|
||||
return d->valid;
|
||||
}
|
||||
|
||||
void parse_descriptor(Bit32u dword1, Bit32u dword2, bx_descriptor_t *temp)
|
||||
{
|
||||
Bit8u AR_byte;
|
||||
Bit32u limit;
|
||||
|
||||
AR_byte = dword2 >> 8;
|
||||
temp->p = (AR_byte >> 7) & 0x1;
|
||||
temp->dpl = (AR_byte >> 5) & 0x3;
|
||||
temp->segment = (AR_byte >> 4) & 0x1;
|
||||
temp->type = (AR_byte & 0xf);
|
||||
temp->valid = 0; /* start out invalid */
|
||||
|
||||
if (temp->segment) { /* data/code segment descriptors */
|
||||
limit = (dword1 & 0xffff) | (dword2 & 0x000F0000);
|
||||
|
||||
temp->u.segment.base = (dword1 >> 16) | ((dword2 & 0xFF) << 16);
|
||||
temp->u.segment.g = (dword2 & 0x00800000) > 0;
|
||||
temp->u.segment.d_b = (dword2 & 0x00400000) > 0;
|
||||
#if BX_SUPPORT_X86_64
|
||||
temp->u.segment.l = (dword2 & 0x00200000) > 0;
|
||||
#endif
|
||||
temp->u.segment.avl = (dword2 & 0x00100000) > 0;
|
||||
temp->u.segment.base |= (dword2 & 0xFF000000);
|
||||
|
||||
if (temp->u.segment.g)
|
||||
temp->u.segment.limit_scaled = (limit << 12) | 0xfff;
|
||||
else
|
||||
temp->u.segment.limit_scaled = limit;
|
||||
|
||||
temp->valid = 1;
|
||||
}
|
||||
else { // system & gate segment descriptors
|
||||
switch (temp->type) {
|
||||
case BX_286_CALL_GATE:
|
||||
case BX_286_INTERRUPT_GATE:
|
||||
case BX_286_TRAP_GATE:
|
||||
// param count only used for call gate
|
||||
temp->u.gate.param_count = dword2 & 0x1f;
|
||||
temp->u.gate.dest_selector = dword1 >> 16;
|
||||
temp->u.gate.dest_offset = dword1 & 0xffff;
|
||||
temp->valid = 1;
|
||||
break;
|
||||
|
||||
case BX_386_CALL_GATE:
|
||||
case BX_386_INTERRUPT_GATE:
|
||||
case BX_386_TRAP_GATE:
|
||||
// param count only used for call gate
|
||||
temp->u.gate.param_count = dword2 & 0x1f;
|
||||
temp->u.gate.dest_selector = dword1 >> 16;
|
||||
temp->u.gate.dest_offset = (dword2 & 0xffff0000) |
|
||||
(dword1 & 0x0000ffff);
|
||||
temp->valid = 1;
|
||||
break;
|
||||
|
||||
case BX_TASK_GATE:
|
||||
temp->u.taskgate.tss_selector = dword1 >> 16;
|
||||
temp->valid = 1;
|
||||
break;
|
||||
|
||||
case BX_SYS_SEGMENT_LDT:
|
||||
case BX_SYS_SEGMENT_AVAIL_286_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_286_TSS:
|
||||
case BX_SYS_SEGMENT_AVAIL_386_TSS:
|
||||
case BX_SYS_SEGMENT_BUSY_386_TSS:
|
||||
limit = (dword1 & 0xffff) | (dword2 & 0x000F0000);
|
||||
temp->u.segment.base = (dword1 >> 16) |
|
||||
((dword2 & 0xff) << 16) | (dword2 & 0xff000000);
|
||||
temp->u.segment.g = (dword2 & 0x00800000) > 0;
|
||||
temp->u.segment.d_b = (dword2 & 0x00400000) > 0;
|
||||
temp->u.segment.avl = (dword2 & 0x00100000) > 0;
|
||||
if (temp->u.segment.g)
|
||||
temp->u.segment.limit_scaled = (limit << 12) | 0xfff;
|
||||
else
|
||||
temp->u.segment.limit_scaled = limit;
|
||||
temp->valid = 1;
|
||||
break;
|
||||
|
||||
default: // reserved
|
||||
temp->valid = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2)
|
||||
BX_CPU_C::touch_segment(bx_selector_t *selector, bx_descriptor_t *descriptor)
|
||||
{
|
||||
if (! IS_SEGMENT_ACCESSED(descriptor->type)) {
|
||||
Bit8u AR_byte = get_ar_byte(descriptor);
|
||||
AR_byte |= 1;
|
||||
descriptor->type |= 1;
|
||||
|
||||
if (selector->ti == 0) { /* GDT */
|
||||
access_write_linear(BX_CPU_THIS_PTR gdtr.base + selector->index*8 + 5, 1, 0, &AR_byte);
|
||||
}
|
||||
else { /* LDT */
|
||||
access_write_linear(BX_CPU_THIS_PTR ldtr.cache.u.segment.base + selector->index*8 + 5, 1, 0, &AR_byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::load_ss(bx_selector_t *selector, bx_descriptor_t *descriptor, Bit8u cpl)
|
||||
{
|
||||
// Add cpl to the selector value.
|
||||
selector->value = (BX_SELECTOR_RPL_MASK & selector->value) | cpl;
|
||||
|
||||
if ((selector->value & BX_SELECTOR_RPL_MASK) != 0)
|
||||
touch_segment(selector, descriptor);
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = *selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = *descriptor;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = cpl;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 1;
|
||||
}
|
||||
|
||||
void BX_CPU_C::fetch_raw_descriptor(const bx_selector_t *selector,
|
||||
Bit32u *dword1, Bit32u *dword2, unsigned exception_no)
|
||||
{
|
||||
Bit32u index = selector->index;
|
||||
bx_address offset;
|
||||
Bit64u raw_descriptor;
|
||||
|
||||
if (selector->ti == 0) { /* GDT */
|
||||
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit) {
|
||||
BX_ERROR(("fetch_raw_descriptor: GDT: index (%x) %x > limit (%x)",
|
||||
index*8 + 7, index, BX_CPU_THIS_PTR gdtr.limit));
|
||||
exception(exception_no, selector->value & 0xfffc);
|
||||
}
|
||||
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
||||
}
|
||||
else { /* LDT */
|
||||
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
||||
BX_ERROR(("fetch_raw_descriptor: LDTR.valid=0"));
|
||||
exception(exception_no, selector->value & 0xfffc);
|
||||
}
|
||||
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("fetch_raw_descriptor: LDT: index (%x) %x > limit (%x)",
|
||||
index*8 + 7, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
|
||||
exception(exception_no, selector->value & 0xfffc);
|
||||
}
|
||||
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
||||
}
|
||||
|
||||
raw_descriptor = system_read_qword(offset);
|
||||
|
||||
*dword1 = GET32L(raw_descriptor);
|
||||
*dword2 = GET32H(raw_descriptor);
|
||||
}
|
||||
|
||||
bx_bool BX_CPP_AttrRegparmN(3)
|
||||
BX_CPU_C::fetch_raw_descriptor2(const bx_selector_t *selector, Bit32u *dword1, Bit32u *dword2)
|
||||
{
|
||||
Bit32u index = selector->index;
|
||||
bx_address offset;
|
||||
Bit64u raw_descriptor;
|
||||
|
||||
if (selector->ti == 0) { /* GDT */
|
||||
if ((index*8 + 7) > BX_CPU_THIS_PTR gdtr.limit)
|
||||
return 0;
|
||||
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
||||
}
|
||||
else { /* LDT */
|
||||
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
||||
BX_ERROR(("fetch_raw_descriptor2: LDTR.valid=0"));
|
||||
return 0;
|
||||
}
|
||||
if ((index*8 + 7) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled)
|
||||
return 0;
|
||||
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
||||
}
|
||||
|
||||
raw_descriptor = system_read_qword(offset);
|
||||
|
||||
*dword1 = GET32L(raw_descriptor);
|
||||
*dword2 = GET32H(raw_descriptor);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
void BX_CPU_C::fetch_raw_descriptor_64(const bx_selector_t *selector,
|
||||
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3, unsigned exception_no)
|
||||
{
|
||||
Bit32u index = selector->index;
|
||||
bx_address offset;
|
||||
Bit64u raw_descriptor1, raw_descriptor2;
|
||||
|
||||
if (selector->ti == 0) { /* GDT */
|
||||
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
|
||||
BX_ERROR(("fetch_raw_descriptor64: GDT: index (%x) %x > limit (%x)",
|
||||
index*8 + 15, index, BX_CPU_THIS_PTR gdtr.limit));
|
||||
exception(exception_no, selector->value & 0xfffc);
|
||||
}
|
||||
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
||||
}
|
||||
else { /* LDT */
|
||||
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
||||
BX_ERROR(("fetch_raw_descriptor64: LDTR.valid=0"));
|
||||
exception(exception_no, selector->value & 0xfffc);
|
||||
}
|
||||
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("fetch_raw_descriptor64: LDT: index (%x) %x > limit (%x)",
|
||||
index*8 + 15, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
|
||||
exception(exception_no, selector->value & 0xfffc);
|
||||
}
|
||||
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
||||
}
|
||||
|
||||
raw_descriptor1 = system_read_qword(offset);
|
||||
raw_descriptor2 = system_read_qword(offset + 8);
|
||||
|
||||
if (raw_descriptor2 & BX_CONST64(0x00001F0000000000)) {
|
||||
BX_ERROR(("fetch_raw_descriptor64: extended attributes DWORD4 TYPE != 0"));
|
||||
exception(BX_GP_EXCEPTION, selector->value & 0xfffc);
|
||||
}
|
||||
|
||||
*dword1 = GET32L(raw_descriptor1);
|
||||
*dword2 = GET32H(raw_descriptor1);
|
||||
*dword3 = GET32L(raw_descriptor2);
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::fetch_raw_descriptor2_64(const bx_selector_t *selector,
|
||||
Bit32u *dword1, Bit32u *dword2, Bit32u *dword3)
|
||||
{
|
||||
Bit32u index = selector->index;
|
||||
bx_address offset;
|
||||
Bit64u raw_descriptor1, raw_descriptor2;
|
||||
|
||||
if (selector->ti == 0) { /* GDT */
|
||||
if ((index*8 + 15) > BX_CPU_THIS_PTR gdtr.limit) {
|
||||
BX_ERROR(("fetch_raw_descriptor2_64: GDT: index (%x) %x > limit (%x)",
|
||||
index*8 + 15, index, BX_CPU_THIS_PTR gdtr.limit));
|
||||
return 0;
|
||||
}
|
||||
offset = BX_CPU_THIS_PTR gdtr.base + index*8;
|
||||
}
|
||||
else { /* LDT */
|
||||
if (BX_CPU_THIS_PTR ldtr.cache.valid==0) {
|
||||
BX_ERROR(("fetch_raw_descriptor2_64: LDTR.valid=0"));
|
||||
return 0;
|
||||
}
|
||||
if ((index*8 + 15) > BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("fetch_raw_descriptor2_64: LDT: index (%x) %x > limit (%x)",
|
||||
index*8 + 15, index, BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled));
|
||||
return 0;
|
||||
}
|
||||
offset = BX_CPU_THIS_PTR ldtr.cache.u.segment.base + index*8;
|
||||
}
|
||||
|
||||
raw_descriptor1 = system_read_qword(offset);
|
||||
raw_descriptor2 = system_read_qword(offset + 8);
|
||||
|
||||
if (raw_descriptor2 & BX_CONST64(0x00001F0000000000)) {
|
||||
BX_ERROR(("fetch_raw_descriptor2_64: extended attributes DWORD4 TYPE != 0"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
*dword1 = GET32L(raw_descriptor1);
|
||||
*dword2 = GET32H(raw_descriptor1);
|
||||
*dword3 = GET32L(raw_descriptor2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
641
simulators/bochs/cpu/shift16.cc
Normal file
641
simulators/bochs/cpu/shift16.cc
Normal file
@ -0,0 +1,641 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, result_16;
|
||||
Bit32u temp_32, result_32;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
/* op1:op2 << count. result stored in op1 */
|
||||
if (i->b1() == 0xa4) // 0x1a4
|
||||
count = i->Ib();
|
||||
else // 0x1a5
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; // use only 5 LSB's
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
temp_32 = ((Bit32u)(op1_16) << 16) | (op2_16); // double formed by op1:op2
|
||||
result_32 = temp_32 << count;
|
||||
|
||||
// hack to act like x86 SHLD when count > 16
|
||||
if (count > 16) {
|
||||
// when count > 16 actually shifting op1:op2:op2 << count,
|
||||
// it is the same as shifting op2:op2 by count-16
|
||||
result_32 |= (op1_16 << (count - 16));
|
||||
}
|
||||
|
||||
result_16 = (Bit16u)(result_32 >> 16);
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
|
||||
cf = (temp_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_16 >> 15); // of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, result_16;
|
||||
Bit32u temp_32, result_32;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
/* op1:op2 << count. result stored in op1 */
|
||||
if (i->b1() == 0xa4) // 0x1a4
|
||||
count = i->Ib();
|
||||
else // 0x1a5
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; // use only 5 LSB's
|
||||
|
||||
if (!count) return;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
temp_32 = ((Bit32u)(op1_16) << 16) | (op2_16); // double formed by op1:op2
|
||||
result_32 = temp_32 << count;
|
||||
|
||||
// hack to act like x86 SHLD when count > 16
|
||||
if (count > 16) {
|
||||
// when count > 16 actually shifting op1:op2:op2 << count,
|
||||
// it is the same as shifting op2:op2 by count-16
|
||||
result_32 |= (op1_16 << (count - 16));
|
||||
}
|
||||
|
||||
result_16 = (Bit16u)(result_32 >> 16);
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
|
||||
cf = (temp_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_16 >> 15); // of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EwGwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, result_16;
|
||||
Bit32u temp_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xac) // 0x1ac
|
||||
count = i->Ib();
|
||||
else // 0x1ad
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
temp_32 = (op2_16 << 16) | op1_16; // double formed by op2:op1
|
||||
result_32 = temp_32 >> count;
|
||||
|
||||
// hack to act like x86 SHRD when count > 16
|
||||
if (count > 16) {
|
||||
// when count > 16 actually shifting op2:op2:op1 >> count,
|
||||
// it is the same as shifting op2:op2 by count-16
|
||||
result_32 |= (op1_16 << (32 - count));
|
||||
}
|
||||
|
||||
result_16 = (Bit16u) result_32;
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
|
||||
cf = (op1_16 >> (count - 1)) & 0x1;
|
||||
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result14 ^ result15
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EwGwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u op1_16, op2_16, result_16;
|
||||
Bit32u temp_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xac) // 0x1ac
|
||||
count = i->Ib();
|
||||
else // 0x1ad
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
if (!count) return;
|
||||
|
||||
op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
op2_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
temp_32 = (op2_16 << 16) | op1_16; // double formed by op2:op1
|
||||
result_32 = temp_32 >> count;
|
||||
|
||||
// hack to act like x86 SHRD when count > 16
|
||||
if (count > 16) {
|
||||
// when count > 16 actually shifting op2:op2:op1 >> count,
|
||||
// it is the same as shifting op2:op2 by count-16
|
||||
result_32 |= (op1_16 << (32 - count));
|
||||
}
|
||||
|
||||
result_16 = (Bit16u) result_32;
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
|
||||
cf = (op1_16 >> (count - 1)) & 0x1;
|
||||
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result14 ^ result15
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EwM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit0, bit15;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if ((count & 0x0f) == 0) {
|
||||
if (count & 0x10) {
|
||||
bit0 = (op1_16 & 0x1);
|
||||
bit15 = (op1_16 >> 15);
|
||||
// of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x0f; // only use bottom 4 bits
|
||||
|
||||
Bit16u result_16 = (op1_16 << count) | (op1_16 >> (16 - count));
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
bit0 = (result_16 & 0x1);
|
||||
bit15 = (result_16 >> 15);
|
||||
// of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EwR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit0, bit15;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if ((count & 0x0f) == 0) {
|
||||
if (count & 0x10) {
|
||||
bit0 = (op1_16 & 0x1);
|
||||
bit15 = (op1_16 >> 15);
|
||||
// of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x0f; // only use bottom 4 bits
|
||||
|
||||
Bit16u result_16 = (op1_16 << count) | (op1_16 >> (16 - count));
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
bit0 = (result_16 & 0x1);
|
||||
bit15 = (result_16 >> 15);
|
||||
// of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit15, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EwM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit14, bit15;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if ((count & 0x0f) == 0) {
|
||||
if (count & 0x10) {
|
||||
bit14 = (op1_16 >> 14) & 1;
|
||||
bit15 = (op1_16 >> 15) & 1;
|
||||
// of = result14 ^ result15
|
||||
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x0f; // use only 4 LSB's
|
||||
|
||||
Bit16u result_16 = (op1_16 >> count) | (op1_16 << (16 - count));
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
bit14 = (result_16 >> 14) & 1;
|
||||
bit15 = (result_16 >> 15) & 1;
|
||||
// of = result14 ^ result15
|
||||
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EwR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit14, bit15;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if ((count & 0x0f) == 0) {
|
||||
if (count & 0x10) {
|
||||
bit14 = (op1_16 >> 14) & 1;
|
||||
bit15 = (op1_16 >> 15) & 1;
|
||||
// of = result14 ^ result15
|
||||
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x0f; // use only 4 LSB's
|
||||
|
||||
Bit16u result_16 = (op1_16 >> count) | (op1_16 << (16 - count));
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
bit14 = (result_16 >> 14) & 1;
|
||||
bit15 = (result_16 >> 15) & 1;
|
||||
// of = result14 ^ result15
|
||||
SET_FLAGS_OxxxxC(bit14 ^ bit15, bit15);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u result_16;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count = (count & 0x1f) % 17;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
if (count==1) {
|
||||
result_16 = (op1_16 << 1) | getB_CF();
|
||||
}
|
||||
else if (count==16) {
|
||||
result_16 = (getB_CF() << 15) | (op1_16 >> 1);
|
||||
}
|
||||
else { // 2..15
|
||||
result_16 = (op1_16 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_16 >> (17 - count));
|
||||
}
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
cf = (op1_16 >> (16 - count)) & 0x1;
|
||||
of = cf ^ (result_16 >> 15); // of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u result_16;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count = (count & 0x1f) % 17;
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if (count==1) {
|
||||
result_16 = (op1_16 << 1) | getB_CF();
|
||||
}
|
||||
else if (count==16) {
|
||||
result_16 = (getB_CF() << 15) | (op1_16 >> 1);
|
||||
}
|
||||
else { // 2..15
|
||||
result_16 = (op1_16 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_16 >> (17 - count));
|
||||
}
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
cf = (op1_16 >> (16 - count)) & 0x1;
|
||||
of = cf ^ (result_16 >> 15); // of = cf ^ result15
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EwM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count = (count & 0x1f) % 17;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (! count) return;
|
||||
|
||||
Bit16u result_16 = (op1_16 >> count) | (getB_CF() << (16 - count)) |
|
||||
(op1_16 << (17 - count));
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
cf = (op1_16 >> (count - 1)) & 0x1;
|
||||
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result15 ^ result14
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EwR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count = (count & 0x1f) % 17;
|
||||
|
||||
if (! count) return;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
Bit16u result_16 = (op1_16 >> count) | (getB_CF() << (16 - count)) |
|
||||
(op1_16 << (17 - count));
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
cf = (op1_16 >> (count - 1)) & 0x1;
|
||||
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1; // of = result15 ^ result14
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EwM(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u result_16;
|
||||
unsigned count;
|
||||
unsigned of = 0, cf = 0;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
if (count <= 16) {
|
||||
result_16 = (op1_16 << count);
|
||||
cf = (op1_16 >> (16 - count)) & 0x1;
|
||||
of = cf ^ (result_16 >> 15); // of = cf ^ result15
|
||||
}
|
||||
else {
|
||||
result_16 = 0;
|
||||
}
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EwR(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u result_16;
|
||||
unsigned count;
|
||||
unsigned of = 0, cf = 0;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
|
||||
if (count <= 16) {
|
||||
result_16 = (op1_16 << count);
|
||||
cf = (op1_16 >> (16 - count)) & 0x1;
|
||||
of = cf ^ (result_16 >> 15); // of = cf ^ result15
|
||||
}
|
||||
else {
|
||||
result_16 = 0;
|
||||
}
|
||||
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EwM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit16u result_16 = (op1_16 >> count);
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
|
||||
cf = (op1_16 >> (count - 1)) & 0x1;
|
||||
// note, that of == result15 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EwR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
Bit16u result_16 = (op1_16 >> count);
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
cf = (op1_16 >> (count - 1)) & 0x1;
|
||||
// note, that of == result15 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
of = ((Bit16u)((result_16 << 1) ^ result_16) >> 15) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EwM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit16u op1_16 = read_RMW_virtual_word(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit16u result_16 = ((Bit16s) op1_16) >> count;
|
||||
|
||||
cf = (((Bit16s) op1_16) >> (count - 1)) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
/* signed overflow cannot happen in SAR instruction */
|
||||
SET_FLAGS_OxxxxC(0, cf);
|
||||
|
||||
write_RMW_virtual_word(result_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EwR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f; /* use only 5 LSB's */
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit16u op1_16 = BX_READ_16BIT_REG(i->rm());
|
||||
Bit16u result_16 = ((Bit16s) op1_16) >> count;
|
||||
BX_WRITE_16BIT_REG(i->rm(), result_16);
|
||||
|
||||
cf = (((Bit16s) op1_16) >> (count - 1)) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_16(result_16);
|
||||
/* signed overflow cannot happen in SAR instruction */
|
||||
SET_FLAGS_OxxxxC(0, cf);
|
||||
}
|
||||
576
simulators/bochs/cpu/shift32.cc
Normal file
576
simulators/bochs/cpu/shift32.cc
Normal file
@ -0,0 +1,576 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, result_32;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xa4) // 0x1a4
|
||||
count = i->Ib();
|
||||
else // 0x1a5
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; // use only 5 LSB's
|
||||
if (!count) return;
|
||||
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
result_32 = (op1_32 << count) | (op2_32 >> (32 - count));
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
|
||||
cf = (op1_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_32 >> 31); // of = cf ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, result_32;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xa4) // 0x1a4
|
||||
count = i->Ib();
|
||||
else // 0x1a5
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; // use only 5 LSB's
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
result_32 = (op1_32 << count) | (op2_32 >> (32 - count));
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
|
||||
cf = (op1_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_32 >> 31); // of = cf ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EdGdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xac) // 0x1ac
|
||||
count = i->Ib();
|
||||
else // 0x1ad
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; // use only 5 LSB's
|
||||
if (!count) return;
|
||||
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
result_32 = (op2_32 << (32 - count)) | (op1_32 >> count);
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
|
||||
cf = (op1_32 >> (count - 1)) & 0x1;
|
||||
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EdGdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, op2_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xac) // 0x1ac
|
||||
count = i->Ib();
|
||||
else // 0x1ad
|
||||
count = CL;
|
||||
|
||||
count &= 0x1f; // use only 5 LSB's
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
op2_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
result_32 = (op2_32 << (32 - count)) | (op1_32 >> count);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
|
||||
cf = (op1_32 >> (count - 1)) & 0x1;
|
||||
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (! count) return;
|
||||
|
||||
result_32 = (op1_32 << count) | (op1_32 >> (32 - count));
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
unsigned bit0 = (result_32 & 0x1);
|
||||
unsigned bit31 = (result_32 >> 31);
|
||||
// of = cf ^ result31
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit31, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned bit0, bit31;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
result_32 = (op1_32 << count) | (op1_32 >> (32 - count));
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
bit0 = (result_32 & 0x1);
|
||||
bit31 = (result_32 >> 31);
|
||||
// of = cf ^ result31
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit31, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned bit31, bit30;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (! count) return;
|
||||
|
||||
result_32 = (op1_32 >> count) | (op1_32 << (32 - count));
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
bit31 = (result_32 >> 31) & 1;
|
||||
bit30 = (result_32 >> 30) & 1;
|
||||
// of = result30 ^ result31
|
||||
SET_FLAGS_OxxxxC(bit30 ^ bit31, bit31);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned bit31, bit30;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
result_32 = (op1_32 >> count) | (op1_32 << (32 - count));
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
bit31 = (result_32 >> 31) & 1;
|
||||
bit30 = (result_32 >> 30) & 1;
|
||||
// of = result30 ^ result31
|
||||
SET_FLAGS_OxxxxC(bit30 ^ bit31, bit31);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) return;
|
||||
|
||||
if (count==1) {
|
||||
result_32 = (op1_32 << 1) | getB_CF();
|
||||
}
|
||||
else {
|
||||
result_32 = (op1_32 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_32 >> (33 - count));
|
||||
}
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
cf = (op1_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_32 >> 31); // of = cf ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
if (count==1) {
|
||||
result_32 = (op1_32 << 1) | getB_CF();
|
||||
}
|
||||
else {
|
||||
result_32 = (op1_32 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_32 >> (33 - count));
|
||||
}
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
cf = (op1_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_32 >> 31); // of = cf ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) return;
|
||||
|
||||
if (count==1) {
|
||||
result_32 = (op1_32 >> 1) | (getB_CF() << 31);
|
||||
}
|
||||
else {
|
||||
result_32 = (op1_32 >> count) | (getB_CF() << (32 - count)) |
|
||||
(op1_32 << (33 - count));
|
||||
}
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
cf = (op1_32 >> (count - 1)) & 0x1;
|
||||
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
if (count==1) {
|
||||
result_32 = (op1_32 >> 1) | (getB_CF() << 31);
|
||||
}
|
||||
else {
|
||||
result_32 = (op1_32 >> count) | (getB_CF() << (32 - count)) |
|
||||
(op1_32 << (33 - count));
|
||||
}
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
cf = (op1_32 >> (count - 1)) & 0x1;
|
||||
of = ((result_32 << 1) ^ result_32) >> 31; // of = result30 ^ result31
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) return;
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
result_32 = (op1_32 << count);
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
cf = (op1_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_32 >> 31);
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
result_32 = (op1_32 << count);
|
||||
cf = (op1_32 >> (32 - count)) & 0x1;
|
||||
of = cf ^ (result_32 >> 31);
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) return;
|
||||
|
||||
result_32 = (op1_32 >> count);
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
cf = (op1_32 >> (count - 1)) & 0x1;
|
||||
// note, that of == result31 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
of = ((result_32 << 1) ^ result_32) >> 31;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
result_32 = (op1_32 >> count);
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
cf = (op1_32 >> (count - 1)) & 0x1;
|
||||
// note, that of == result31 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
of = ((result_32 << 1) ^ result_32) >> 31;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_32 = read_RMW_virtual_dword(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) return;
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
result_32 = ((Bit32s) op1_32) >> count;
|
||||
|
||||
write_RMW_virtual_dword(result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
set_CF((op1_32 >> (count - 1)) & 1);
|
||||
clear_OF(); /* signed overflow cannot happen in SAR instruction */
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EdR(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u op1_32, result_32;
|
||||
unsigned count;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
if (!count) {
|
||||
BX_CLEAR_64BIT_HIGH(i->rm()); // always clear upper part of the register
|
||||
return;
|
||||
}
|
||||
|
||||
op1_32 = BX_READ_32BIT_REG(i->rm());
|
||||
|
||||
/* count < 32, since only lower 5 bits used */
|
||||
result_32 = ((Bit32s) op1_32) >> count;
|
||||
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), result_32);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_32(result_32);
|
||||
set_CF((op1_32 >> (count - 1)) & 1);
|
||||
clear_OF(); /* signed overflow cannot happen in SAR instruction */
|
||||
}
|
||||
552
simulators/bochs/cpu/shift64.cc
Normal file
552
simulators/bochs/cpu/shift64.cc
Normal file
@ -0,0 +1,552 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xa4) // 0x1a4
|
||||
count = i->Ib();
|
||||
else // 0x1a5
|
||||
count = CL;
|
||||
|
||||
count &= 0x3f; // use only 6 LSB's
|
||||
if (!count) return;
|
||||
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
result_64 = (op1_64 << count) | (op2_64 >> (64 - count));
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
|
||||
cf = (op1_64 >> (64 - count)) & 0x1;
|
||||
of = cf ^ (result_64 >> 63); // of = cf ^ result63
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHLD_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xa4) // 0x1a4
|
||||
count = i->Ib();
|
||||
else // 0x1a5
|
||||
count = CL;
|
||||
|
||||
count &= 0x3f; // use only 6 LSB's
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
result_64 = (op1_64 << count) | (op2_64 >> (64 - count));
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
|
||||
cf = (op1_64 >> (64 - count)) & 0x1;
|
||||
of = cf ^ (result_64 >> 63); // of = cf ^ result63
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EqGqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xac) // 0x1ac
|
||||
count = i->Ib();
|
||||
else // 0x1ad
|
||||
count = CL;
|
||||
|
||||
count &= 0x3f; // use only 6 LSB's
|
||||
if (!count) return;
|
||||
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
result_64 = (op2_64 << (64 - count)) | (op1_64 >> count);
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
|
||||
cf = (op1_64 >> (count - 1)) & 0x1;
|
||||
of = ((result_64 << 1) ^ result_64) >> 63; // of = result62 ^ result63
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHRD_EqGqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, op2_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xac) // 0x1ac
|
||||
count = i->Ib();
|
||||
else // 0x1ad
|
||||
count = CL;
|
||||
|
||||
count &= 0x3f; // use only 6 LSB's
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
op2_64 = BX_READ_64BIT_REG(i->nnn());
|
||||
|
||||
result_64 = (op2_64 << (64 - count)) | (op1_64 >> count);
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
|
||||
cf = (op1_64 >> (count - 1)) & 0x1;
|
||||
of = ((result_64 << 1) ^ result_64) >> 63; // of = result62 ^ result63
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned bit0, bit63;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (! count) return;
|
||||
|
||||
result_64 = (op1_64 << count) | (op1_64 >> (64 - count));
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
bit0 = (result_64 & 0x1);
|
||||
bit63 = (result_64 >> 63);
|
||||
// of = cf ^ result63
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit63, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned bit0, bit63;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (! count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
result_64 = (op1_64 << count) | (op1_64 >> (64 - count));
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
bit0 = (result_64 & 0x1);
|
||||
bit63 = (result_64 >> 63);
|
||||
// of = cf ^ result63
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit63, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned bit62, bit63;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (! count) return;
|
||||
|
||||
result_64 = (op1_64 >> count) | (op1_64 << (64 - count));
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
bit63 = (result_64 >> 63) & 1;
|
||||
bit62 = (result_64 >> 62) & 1;
|
||||
// of = result62 ^ result63
|
||||
SET_FLAGS_OxxxxC(bit62 ^ bit63, bit63);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned bit62, bit63;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (! count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
result_64 = (op1_64 >> count) | (op1_64 << (64 - count));
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
bit63 = (result_64 >> 63) & 1;
|
||||
bit62 = (result_64 >> 62) & 1;
|
||||
// of = result62 ^ result63
|
||||
SET_FLAGS_OxxxxC(bit62 ^ bit63, bit63);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
if (count==1) {
|
||||
result_64 = (op1_64 << 1) | getB_CF();
|
||||
}
|
||||
else {
|
||||
result_64 = (op1_64 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_64 >> (65 - count));
|
||||
}
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
cf = (op1_64 >> (64 - count)) & 0x1;
|
||||
of = cf ^ (result_64 >> 63); // of = cf ^ result63
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
if (count==1) {
|
||||
result_64 = (op1_64 << 1) | getB_CF();
|
||||
}
|
||||
else {
|
||||
result_64 = (op1_64 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_64 >> (65 - count));
|
||||
}
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
cf = (op1_64 >> (64 - count)) & 0x1;
|
||||
of = cf ^ (result_64 >> 63); // of = cf ^ result63
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
if (count==1) {
|
||||
result_64 = (op1_64 >> 1) | (((Bit64u) getB_CF()) << 63);
|
||||
}
|
||||
else {
|
||||
result_64 = (op1_64 >> count) | (getB_CF() << (64 - count)) |
|
||||
(op1_64 << (65 - count));
|
||||
}
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
cf = (op1_64 >> (count - 1)) & 0x1;
|
||||
of = ((result_64 << 1) ^ result_64) >> 63;
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
if (count==1) {
|
||||
result_64 = (op1_64 >> 1) | (((Bit64u) getB_CF()) << 63);
|
||||
}
|
||||
else {
|
||||
result_64 = (op1_64 >> count) | (getB_CF() << (64 - count)) |
|
||||
(op1_64 << (65 - count));
|
||||
}
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
cf = (op1_64 >> (count - 1)) & 0x1;
|
||||
of = ((result_64 << 1) ^ result_64) >> 63;
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
/* count < 64, since only lower 6 bits used */
|
||||
result_64 = (op1_64 << count);
|
||||
cf = (op1_64 >> (64 - count)) & 0x1;
|
||||
of = cf ^ (result_64 >> 63);
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
/* count < 64, since only lower 6 bits used */
|
||||
result_64 = (op1_64 << count);
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
cf = (op1_64 >> (64 - count)) & 0x1;
|
||||
of = cf ^ (result_64 >> 63);
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
result_64 = (op1_64 >> count);
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
cf = (op1_64 >> (count - 1)) & 0x1;
|
||||
// note, that of == result63 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
of = ((result_64 << 1) ^ result_64) >> 63;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
result_64 = (op1_64 >> count);
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
cf = (op1_64 >> (count - 1)) & 0x1;
|
||||
// note, that of == result63 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
of = ((result_64 << 1) ^ result_64) >> 63;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EqM(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
/* pointer, segment address pair */
|
||||
op1_64 = read_RMW_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
/* count < 64, since only lower 6 bits used */
|
||||
result_64 = ((Bit64s) op1_64) >> count;
|
||||
|
||||
write_RMW_virtual_qword(result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
set_CF((op1_64 >> (count - 1)) & 1);
|
||||
clear_OF(); /* signed overflow cannot happen in SAR instruction */
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EqR(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u op1_64, result_64;
|
||||
unsigned count;
|
||||
|
||||
if (i->b1() == 0xd3)
|
||||
count = CL;
|
||||
else // 0xc1 or 0xd1
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x3f;
|
||||
if (!count) return;
|
||||
|
||||
op1_64 = BX_READ_64BIT_REG(i->rm());
|
||||
|
||||
/* count < 64, since only lower 6 bits used */
|
||||
result_64 = ((Bit64s) op1_64) >> count;
|
||||
|
||||
BX_WRITE_64BIT_REG(i->rm(), result_64);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_64(result_64);
|
||||
set_CF((op1_64 >> (count - 1)) & 1);
|
||||
clear_OF(); /* signed overflow cannot happen in SAR instruction */
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
469
simulators/bochs/cpu/shift8.cc
Normal file
469
simulators/bochs/cpu/shift8.cc
Normal file
@ -0,0 +1,469 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EbR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit0, bit7;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
if ((count & 0x07) == 0) {
|
||||
if (count & 0x18) {
|
||||
bit0 = (op1_8 & 1);
|
||||
bit7 = (op1_8 >> 7);
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x7; // use only lowest 3 bits
|
||||
|
||||
Bit8u result_8 = (op1_8 << count) | (op1_8 >> (8 - count));
|
||||
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
/* set eflags:
|
||||
* ROL count affects the following flags: C, O
|
||||
*/
|
||||
bit0 = (result_8 & 1);
|
||||
bit7 = (result_8 >> 7);
|
||||
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROL_EbM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit0, bit7;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
if ((count & 0x07) == 0) {
|
||||
if (count & 0x18) {
|
||||
bit0 = (op1_8 & 1);
|
||||
bit7 = (op1_8 >> 7);
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x7; // use only lowest 3 bits
|
||||
|
||||
Bit8u result_8 = (op1_8 << count) | (op1_8 >> (8 - count));
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
/* set eflags:
|
||||
* ROL count affects the following flags: C, O
|
||||
*/
|
||||
bit0 = (result_8 & 1);
|
||||
bit7 = (result_8 >> 7);
|
||||
|
||||
SET_FLAGS_OxxxxC(bit0 ^ bit7, bit0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EbR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit6, bit7;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
if ((count & 0x07) == 0) {
|
||||
if (count & 0x18) {
|
||||
bit6 = (op1_8 >> 6) & 1;
|
||||
bit7 = (op1_8 >> 7) & 1;
|
||||
|
||||
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x7; /* use only bottom 3 bits */
|
||||
|
||||
Bit8u result_8 = (op1_8 >> count) | (op1_8 << (8 - count));
|
||||
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
/* set eflags:
|
||||
* ROR count affects the following flags: C, O
|
||||
*/
|
||||
bit6 = (result_8 >> 6) & 1;
|
||||
bit7 = (result_8 >> 7) & 1;
|
||||
|
||||
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ROR_EbM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned bit6, bit7;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
if ((count & 0x07) == 0) {
|
||||
if (count & 0x18) {
|
||||
bit6 = (op1_8 >> 6) & 1;
|
||||
bit7 = (op1_8 >> 7) & 1;
|
||||
|
||||
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
count &= 0x7; /* use only bottom 3 bits */
|
||||
|
||||
Bit8u result_8 = (op1_8 >> count) | (op1_8 << (8 - count));
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
/* set eflags:
|
||||
* ROR count affects the following flags: C, O
|
||||
*/
|
||||
bit6 = (result_8 >> 6) & 1;
|
||||
bit7 = (result_8 >> 7) & 1;
|
||||
|
||||
SET_FLAGS_OxxxxC(bit6 ^ bit7, bit7);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u result_8;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count = (count & 0x1f) % 9;
|
||||
|
||||
if (! count) return;
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
if (count==1) {
|
||||
result_8 = (op1_8 << 1) | getB_CF();
|
||||
}
|
||||
else {
|
||||
result_8 = (op1_8 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_8 >> (9 - count));
|
||||
}
|
||||
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
cf = (op1_8 >> (8 - count)) & 0x01;
|
||||
of = cf ^ (result_8 >> 7); // of = cf ^ result7
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCL_EbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u result_8;
|
||||
unsigned count;
|
||||
unsigned of, cf;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
count = (count & 0x1f) % 9;
|
||||
|
||||
if (! count) return;
|
||||
|
||||
if (count==1) {
|
||||
result_8 = (op1_8 << 1) | getB_CF();
|
||||
}
|
||||
else {
|
||||
result_8 = (op1_8 << count) | (getB_CF() << (count - 1)) |
|
||||
(op1_8 >> (9 - count));
|
||||
}
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
cf = (op1_8 >> (8 - count)) & 0x01;
|
||||
of = cf ^ (result_8 >> 7); // of = cf ^ result7
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EbR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count = (count & 0x1f) % 9;
|
||||
|
||||
if (! count) return;
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
Bit8u result_8 = (op1_8 >> count) | (getB_CF() << (8 - count)) |
|
||||
(op1_8 << (9 - count));
|
||||
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
cf = (op1_8 >> (count - 1)) & 0x1;
|
||||
of = (((result_8 << 1) ^ result_8) >> 7) & 0x1; // of = result6 ^ result7
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCR_EbM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
unsigned cf, of;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
count = (count & 0x1f) % 9;
|
||||
|
||||
if (! count) return;
|
||||
|
||||
Bit8u result_8 = (op1_8 >> count) | (getB_CF() << (8 - count)) |
|
||||
(op1_8 << (9 - count));
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
cf = (op1_8 >> (count - 1)) & 0x1;
|
||||
of = (((result_8 << 1) ^ result_8) >> 7) & 0x1; // of = result6 ^ result7
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EbR(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u result_8;
|
||||
unsigned count;
|
||||
unsigned of = 0, cf = 0;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
|
||||
if (count <= 8) {
|
||||
result_8 = (op1_8 << count);
|
||||
cf = (op1_8 >> (8 - count)) & 0x1;
|
||||
of = cf ^ (result_8 >> 7);
|
||||
}
|
||||
else {
|
||||
result_8 = 0;
|
||||
}
|
||||
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHL_EbM(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u result_8;
|
||||
unsigned count;
|
||||
unsigned of = 0, cf = 0;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
if (count <= 8) {
|
||||
result_8 = (op1_8 << count);
|
||||
cf = (op1_8 >> (8 - count)) & 0x1;
|
||||
of = cf ^ (result_8 >> 7);
|
||||
}
|
||||
else {
|
||||
result_8 = 0;
|
||||
}
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EbR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
Bit8u result_8 = (op1_8 >> count);
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
unsigned cf = (op1_8 >> (count - 1)) & 0x1;
|
||||
// note, that of == result7 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
unsigned of = (((result_8 << 1) ^ result_8) >> 7) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SHR_EbM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit8u result_8 = (op1_8 >> count);
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
unsigned cf = (op1_8 >> (count - 1)) & 0x1;
|
||||
// note, that of == result7 if count == 1 and
|
||||
// of == 0 if count >= 2
|
||||
unsigned of = (((result_8 << 1) ^ result_8) >> 7) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
|
||||
SET_FLAGS_OxxxxC(of, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EbR(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit8u op1_8 = BX_READ_8BIT_REGx(i->rm(), i->extend8bitL());
|
||||
Bit8u result_8 = ((Bit8s) op1_8) >> count;
|
||||
BX_WRITE_8BIT_REGx(i->rm(), i->extend8bitL(), result_8);
|
||||
|
||||
unsigned cf = (((Bit8s) op1_8) >> (count - 1)) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
|
||||
/* signed overflow cannot happen in SAR instruction */
|
||||
SET_FLAGS_OxxxxC(0, cf);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::SAR_EbM(bxInstruction_c *i)
|
||||
{
|
||||
unsigned count;
|
||||
|
||||
if (i->b1() == 0xd2)
|
||||
count = CL;
|
||||
else // 0xc0 or 0xd0
|
||||
count = i->Ib();
|
||||
|
||||
count &= 0x1f;
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
/* pointer, segment address pair */
|
||||
Bit8u op1_8 = read_RMW_virtual_byte(i->seg(), eaddr);
|
||||
|
||||
if (!count) return;
|
||||
|
||||
Bit8u result_8 = ((Bit8s) op1_8) >> count;
|
||||
|
||||
write_RMW_virtual_byte(result_8);
|
||||
|
||||
unsigned cf = (((Bit8s) op1_8) >> (count - 1)) & 0x1;
|
||||
|
||||
SET_FLAGS_OSZAPC_LOGIC_8(result_8);
|
||||
/* signed overflow cannot happen in SAR instruction */
|
||||
SET_FLAGS_OxxxxC(0, cf);
|
||||
}
|
||||
874
simulators/bochs/cpu/smm.cc
Executable file
874
simulators/bochs/cpu/smm.cc
Executable file
@ -0,0 +1,874 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2006-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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#include "smm.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RIP EIP
|
||||
#endif
|
||||
|
||||
//
|
||||
// Some of the CPU field must be saved and restored in order to continue the
|
||||
// simulation correctly after the RSM instruction:
|
||||
//
|
||||
// ---------------------------------------------------------------
|
||||
//
|
||||
// 1. General purpose registers: EAX-EDI, R8-R15
|
||||
// 2. EIP, RFLAGS
|
||||
// 3. Segment registers CS, DS, SS, ES, FS, GS
|
||||
// fields: valid - not required, initialized according to selector value
|
||||
// p - must be saved/restored
|
||||
// dpl - must be saved/restored
|
||||
// segment - must be 1 for seg registers, not required to save
|
||||
// type - must be saved/restored
|
||||
// base - must be saved/restored
|
||||
// limit - must be saved/restored
|
||||
// g - must be saved/restored
|
||||
// d_b - must be saved/restored
|
||||
// l - must be saved/restored
|
||||
// avl - must be saved/restored
|
||||
// 4. GDTR, IDTR
|
||||
// fields: base, limit
|
||||
// 5. LDTR, TR
|
||||
// fields: base, limit, anything else ?
|
||||
// 6. Debug Registers DR0-DR7, only DR6 and DR7 are saved
|
||||
// 7. Control Registers: CR0, CR1 is always 0, CR2 is NOT saved, CR3, CR4, EFER
|
||||
// 8. SMBASE
|
||||
// 9. MSR/FPU/XMM/APIC are NOT saved accoring to Intel docs
|
||||
//
|
||||
|
||||
#define SMM_SAVE_STATE_MAP_SIZE 128
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RSM(bxInstruction_c *i)
|
||||
{
|
||||
/* If we are not in System Management Mode, then #UD should be generated */
|
||||
if (! BX_CPU_THIS_PTR smm_mode()) {
|
||||
BX_INFO(("RSM not in System Management Mode !"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
if (BX_CPU_THIS_PTR in_vmx) {
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
||||
BX_ERROR(("VMEXIT: RSM in VMX non-root operation"));
|
||||
VMexit(i, VMX_VMEXIT_RSM, 0);
|
||||
}
|
||||
else {
|
||||
BX_ERROR(("RSM in VMX root operation !"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
BX_INFO(("RSM: Resuming from System Management Mode"));
|
||||
|
||||
BX_CPU_THIS_PTR disable_NMI = 0;
|
||||
|
||||
Bit32u saved_state[SMM_SAVE_STATE_MAP_SIZE], n;
|
||||
// reset reserved bits
|
||||
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) saved_state[n] = 0;
|
||||
|
||||
bx_phy_address base = BX_CPU_THIS_PTR smbase + 0x10000;
|
||||
// could be optimized with reading of only non-reserved bytes
|
||||
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) {
|
||||
base -= 4;
|
||||
access_read_physical(base, 4, &saved_state[n]);
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, base, 4, BX_SMRAM_ACCESS | BX_READ, (Bit8u*)(&saved_state[n]));
|
||||
}
|
||||
BX_CPU_THIS_PTR in_smm = 0;
|
||||
|
||||
// restore the CPU state from SMRAM
|
||||
if (! smram_restore_state(saved_state)) {
|
||||
BX_PANIC(("RSM: Incorrect state when restoring CPU state - shutdown !"));
|
||||
shutdown();
|
||||
}
|
||||
|
||||
// debug(RIP);
|
||||
}
|
||||
|
||||
void BX_CPU_C::enter_system_management_mode(void)
|
||||
{
|
||||
invalidate_prefetch_q();
|
||||
|
||||
BX_INFO(("Enter to System Management Mode"));
|
||||
|
||||
// debug(BX_CPU_THIS_PTR prev_rip);
|
||||
|
||||
//
|
||||
// Processors that support VMX operation perform SMI delivery as follows:
|
||||
//
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
// Enter SMM
|
||||
// save the following internal to the processor:
|
||||
// * CR4.VMXE
|
||||
// * an indication of whether the logical processor was in VMX operation (root or non-root)
|
||||
// IF the logical processor is in VMX operation
|
||||
// THEN
|
||||
// leave VMX operation;
|
||||
// save VMX-critical state defined below;
|
||||
// preserve current VMCS pointer as noted below;
|
||||
// FI;
|
||||
// CR4.VMXE = 0;
|
||||
|
||||
BX_CPU_THIS_PTR cr4.set_VMXE(0);
|
||||
BX_CPU_THIS_PTR in_smm_vmx = BX_CPU_THIS_PTR in_vmx;
|
||||
BX_CPU_THIS_PTR in_smm_vmx_guest = BX_CPU_THIS_PTR in_vmx_guest;
|
||||
BX_CPU_THIS_PTR in_vmx = 0;
|
||||
BX_CPU_THIS_PTR in_vmx_guest = 0;
|
||||
|
||||
BX_INFO(("enter_system_management_mode: temporary disable VMX while in SMM mode"));
|
||||
|
||||
// perform ordinary SMI delivery:
|
||||
// * save processor state in SMRAM;
|
||||
// * set processor state to standard SMM values
|
||||
#endif
|
||||
|
||||
BX_CPU_THIS_PTR in_smm = 1;
|
||||
BX_CPU_THIS_PTR disable_NMI = 1;
|
||||
|
||||
Bit32u saved_state[SMM_SAVE_STATE_MAP_SIZE], n;
|
||||
// reset reserved bits
|
||||
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) saved_state[n] = 0;
|
||||
// prepare CPU state to be saved in the SMRAM
|
||||
smram_save_state(saved_state);
|
||||
|
||||
bx_phy_address base = BX_CPU_THIS_PTR smbase + 0x10000;
|
||||
// could be optimized with reading of only non-reserved bytes
|
||||
for(n=0;n<SMM_SAVE_STATE_MAP_SIZE;n++) {
|
||||
base -= 4;
|
||||
access_write_physical(base, 4, &saved_state[n]);
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, base, 4, BX_SMRAM_ACCESS | BX_WRITE, (Bit8u*)(&saved_state[n]));
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR setEFlags(0x2); // Bit1 is always set
|
||||
BX_CPU_THIS_PTR prev_rip = RIP = 0x00008000;
|
||||
BX_CPU_THIS_PTR dr7 = 0x00000400;
|
||||
|
||||
// CR0 - PE, EM, TS, and PG flags set to 0; others unmodified
|
||||
BX_CPU_THIS_PTR cr0.set_PE(0); // real mode (bit 0)
|
||||
BX_CPU_THIS_PTR cr0.set_EM(0); // emulate math coprocessor (bit 2)
|
||||
BX_CPU_THIS_PTR cr0.set_TS(0); // no task switch (bit 3)
|
||||
BX_CPU_THIS_PTR cr0.set_PG(0); // paging disabled (bit 31)
|
||||
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
BX_CPU_THIS_PTR cr4.set32(0);
|
||||
#endif
|
||||
|
||||
// paging mode was changed - flush TLB
|
||||
TLB_flush(); // Flush Global entries also
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPU_THIS_PTR efer.set32(0);
|
||||
#endif
|
||||
|
||||
parse_selector(BX_CPU_THIS_PTR smbase >> 4,
|
||||
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector);
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = 1;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = 1; /* data/code segment */
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = BX_CPU_THIS_PTR smbase;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xffffffff;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; /* page granular */
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 0; /* 16bit default size */
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.l = 0; /* 16bit default size */
|
||||
#endif
|
||||
|
||||
handleCpuModeChange();
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck();
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
handleSseModeChange();
|
||||
#endif
|
||||
|
||||
/* DS (Data Segment) and descriptor cache */
|
||||
parse_selector(0x0000,
|
||||
&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector);
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.p = 1;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.dpl = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment = 1; /* data/code segment */
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base = 0x00000000;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit_scaled = 0xffffffff;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.avl = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.g = 1; /* byte granular */
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.d_b = 0; /* 16bit default size */
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.l = 0; /* 16bit default size */
|
||||
#endif
|
||||
|
||||
// use DS segment as template for the others
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS] = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS];
|
||||
}
|
||||
|
||||
#define SMRAM_TRANSLATE(addr) (((0x8000 - (addr)) >> 2) - 1)
|
||||
|
||||
// SMRAM SMM_SAVE_STATE_MAP_SIZE is 128 elements, find the element for each field
|
||||
static unsigned smram_map[SMRAM_FIELD_LAST];
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPU_C::init_SMRAM(void)
|
||||
{
|
||||
static bx_bool smram_map_ready = 0;
|
||||
|
||||
if (smram_map_ready) return;
|
||||
smram_map_ready = 1;
|
||||
|
||||
smram_map[SMRAM_FIELD_SMBASE_OFFSET] = SMRAM_TRANSLATE(0x7f00);
|
||||
smram_map[SMRAM_FIELD_SMM_REVISION_ID] = SMRAM_TRANSLATE(0x7efc);
|
||||
smram_map[SMRAM_FIELD_RAX_HI32] = SMRAM_TRANSLATE(0x7ffc);
|
||||
smram_map[SMRAM_FIELD_EAX] = SMRAM_TRANSLATE(0x7ff8);
|
||||
smram_map[SMRAM_FIELD_RCX_HI32] = SMRAM_TRANSLATE(0x7ff4);
|
||||
smram_map[SMRAM_FIELD_ECX] = SMRAM_TRANSLATE(0x7ff0);
|
||||
smram_map[SMRAM_FIELD_RDX_HI32] = SMRAM_TRANSLATE(0x7fec);
|
||||
smram_map[SMRAM_FIELD_EDX] = SMRAM_TRANSLATE(0x7fe8);
|
||||
smram_map[SMRAM_FIELD_RBX_HI32] = SMRAM_TRANSLATE(0x7fe4);
|
||||
smram_map[SMRAM_FIELD_EBX] = SMRAM_TRANSLATE(0x7fe0);
|
||||
smram_map[SMRAM_FIELD_RSP_HI32] = SMRAM_TRANSLATE(0x7fdc);
|
||||
smram_map[SMRAM_FIELD_ESP] = SMRAM_TRANSLATE(0x7fd8);
|
||||
smram_map[SMRAM_FIELD_RBP_HI32] = SMRAM_TRANSLATE(0x7fd4);
|
||||
smram_map[SMRAM_FIELD_EBP] = SMRAM_TRANSLATE(0x7fd0);
|
||||
smram_map[SMRAM_FIELD_RSI_HI32] = SMRAM_TRANSLATE(0x7fcc);
|
||||
smram_map[SMRAM_FIELD_ESI] = SMRAM_TRANSLATE(0x7fc8);
|
||||
smram_map[SMRAM_FIELD_RDI_HI32] = SMRAM_TRANSLATE(0x7fc4);
|
||||
smram_map[SMRAM_FIELD_EDI] = SMRAM_TRANSLATE(0x7fc0);
|
||||
smram_map[SMRAM_FIELD_R8_HI32] = SMRAM_TRANSLATE(0x7fbc);
|
||||
smram_map[SMRAM_FIELD_R8] = SMRAM_TRANSLATE(0x7fb8);
|
||||
smram_map[SMRAM_FIELD_R9_HI32] = SMRAM_TRANSLATE(0x7fb4);
|
||||
smram_map[SMRAM_FIELD_R9] = SMRAM_TRANSLATE(0x7fb0);
|
||||
smram_map[SMRAM_FIELD_R10_HI32] = SMRAM_TRANSLATE(0x7fac);
|
||||
smram_map[SMRAM_FIELD_R10] = SMRAM_TRANSLATE(0x7fa8);
|
||||
smram_map[SMRAM_FIELD_R11_HI32] = SMRAM_TRANSLATE(0x7fa4);
|
||||
smram_map[SMRAM_FIELD_R11] = SMRAM_TRANSLATE(0x7fa0);
|
||||
smram_map[SMRAM_FIELD_R12_HI32] = SMRAM_TRANSLATE(0x7f9c);
|
||||
smram_map[SMRAM_FIELD_R12] = SMRAM_TRANSLATE(0x7f98);
|
||||
smram_map[SMRAM_FIELD_R13_HI32] = SMRAM_TRANSLATE(0x7f94);
|
||||
smram_map[SMRAM_FIELD_R13] = SMRAM_TRANSLATE(0x7f90);
|
||||
smram_map[SMRAM_FIELD_R14_HI32] = SMRAM_TRANSLATE(0x7f8c);
|
||||
smram_map[SMRAM_FIELD_R14] = SMRAM_TRANSLATE(0x7f88);
|
||||
smram_map[SMRAM_FIELD_R15_HI32] = SMRAM_TRANSLATE(0x7f84);
|
||||
smram_map[SMRAM_FIELD_R15] = SMRAM_TRANSLATE(0x7f80);
|
||||
smram_map[SMRAM_FIELD_RIP_HI32] = SMRAM_TRANSLATE(0x7f7c);
|
||||
smram_map[SMRAM_FIELD_EIP] = SMRAM_TRANSLATE(0x7f78);
|
||||
smram_map[SMRAM_FIELD_RFLAGS_HI32] = SMRAM_TRANSLATE(0x7f74); // always zero
|
||||
smram_map[SMRAM_FIELD_EFLAGS] = SMRAM_TRANSLATE(0x7f70);
|
||||
smram_map[SMRAM_FIELD_DR6_HI32] = SMRAM_TRANSLATE(0x7f6c); // always zero
|
||||
smram_map[SMRAM_FIELD_DR6] = SMRAM_TRANSLATE(0x7f68);
|
||||
smram_map[SMRAM_FIELD_DR7_HI32] = SMRAM_TRANSLATE(0x7f64); // always zero
|
||||
smram_map[SMRAM_FIELD_DR7] = SMRAM_TRANSLATE(0x7f60);
|
||||
smram_map[SMRAM_FIELD_CR0_HI32] = SMRAM_TRANSLATE(0x7f5c); // always zero
|
||||
smram_map[SMRAM_FIELD_CR0] = SMRAM_TRANSLATE(0x7f58);
|
||||
smram_map[SMRAM_FIELD_CR3_HI32] = SMRAM_TRANSLATE(0x7f54); // zero when physical address size 32-bit
|
||||
smram_map[SMRAM_FIELD_CR3] = SMRAM_TRANSLATE(0x7f50);
|
||||
smram_map[SMRAM_FIELD_CR4_HI32] = SMRAM_TRANSLATE(0x7f4c); // always zero
|
||||
smram_map[SMRAM_FIELD_CR4] = SMRAM_TRANSLATE(0x7f48);
|
||||
smram_map[SMRAM_FIELD_EFER_HI32] = SMRAM_TRANSLATE(0x7ed4); // always zero
|
||||
smram_map[SMRAM_FIELD_EFER] = SMRAM_TRANSLATE(0x7ed0);
|
||||
smram_map[SMRAM_FIELD_IO_INSTRUCTION_RESTART] = SMRAM_TRANSLATE(0x7ec8);
|
||||
smram_map[SMRAM_FIELD_AUTOHALT_RESTART] = SMRAM_TRANSLATE(0x7ec8);
|
||||
smram_map[SMRAM_FIELD_NMI_MASK] = SMRAM_TRANSLATE(0x7ec8);
|
||||
smram_map[SMRAM_FIELD_TR_BASE_HI32] = SMRAM_TRANSLATE(0x7e9c);
|
||||
smram_map[SMRAM_FIELD_TR_BASE] = SMRAM_TRANSLATE(0x7e98);
|
||||
smram_map[SMRAM_FIELD_TR_LIMIT] = SMRAM_TRANSLATE(0x7e94);
|
||||
smram_map[SMRAM_FIELD_TR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e90);
|
||||
smram_map[SMRAM_FIELD_IDTR_BASE_HI32] = SMRAM_TRANSLATE(0x7e8c);
|
||||
smram_map[SMRAM_FIELD_IDTR_BASE] = SMRAM_TRANSLATE(0x7e88);
|
||||
smram_map[SMRAM_FIELD_IDTR_LIMIT] = SMRAM_TRANSLATE(0x7e84);
|
||||
smram_map[SMRAM_FIELD_LDTR_BASE_HI32] = SMRAM_TRANSLATE(0x7e7c);
|
||||
smram_map[SMRAM_FIELD_LDTR_BASE] = SMRAM_TRANSLATE(0x7e78);
|
||||
smram_map[SMRAM_FIELD_LDTR_LIMIT] = SMRAM_TRANSLATE(0x7e74);
|
||||
smram_map[SMRAM_FIELD_LDTR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e70);
|
||||
smram_map[SMRAM_FIELD_GDTR_BASE_HI32] = SMRAM_TRANSLATE(0x7e6c);
|
||||
smram_map[SMRAM_FIELD_GDTR_BASE] = SMRAM_TRANSLATE(0x7e68);
|
||||
smram_map[SMRAM_FIELD_GDTR_LIMIT] = SMRAM_TRANSLATE(0x7e64);
|
||||
smram_map[SMRAM_FIELD_ES_BASE_HI32] = SMRAM_TRANSLATE(0x7e0c);
|
||||
smram_map[SMRAM_FIELD_ES_BASE] = SMRAM_TRANSLATE(0x7e08);
|
||||
smram_map[SMRAM_FIELD_ES_LIMIT] = SMRAM_TRANSLATE(0x7e04);
|
||||
smram_map[SMRAM_FIELD_ES_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e00);
|
||||
smram_map[SMRAM_FIELD_CS_BASE_HI32] = SMRAM_TRANSLATE(0x7e1c);
|
||||
smram_map[SMRAM_FIELD_CS_BASE] = SMRAM_TRANSLATE(0x7e18);
|
||||
smram_map[SMRAM_FIELD_CS_LIMIT] = SMRAM_TRANSLATE(0x7e14);
|
||||
smram_map[SMRAM_FIELD_CS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e10);
|
||||
smram_map[SMRAM_FIELD_SS_BASE_HI32] = SMRAM_TRANSLATE(0x7e2c);
|
||||
smram_map[SMRAM_FIELD_SS_BASE] = SMRAM_TRANSLATE(0x7e28);
|
||||
smram_map[SMRAM_FIELD_SS_LIMIT] = SMRAM_TRANSLATE(0x7e24);
|
||||
smram_map[SMRAM_FIELD_SS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e20);
|
||||
smram_map[SMRAM_FIELD_DS_BASE_HI32] = SMRAM_TRANSLATE(0x7e3c);
|
||||
smram_map[SMRAM_FIELD_DS_BASE] = SMRAM_TRANSLATE(0x7e38);
|
||||
smram_map[SMRAM_FIELD_DS_LIMIT] = SMRAM_TRANSLATE(0x7e34);
|
||||
smram_map[SMRAM_FIELD_DS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e30);
|
||||
smram_map[SMRAM_FIELD_FS_BASE_HI32] = SMRAM_TRANSLATE(0x7e4c);
|
||||
smram_map[SMRAM_FIELD_FS_BASE] = SMRAM_TRANSLATE(0x7e48);
|
||||
smram_map[SMRAM_FIELD_FS_LIMIT] = SMRAM_TRANSLATE(0x7e44);
|
||||
smram_map[SMRAM_FIELD_FS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e40);
|
||||
smram_map[SMRAM_FIELD_GS_BASE_HI32] = SMRAM_TRANSLATE(0x7e5c);
|
||||
smram_map[SMRAM_FIELD_GS_BASE] = SMRAM_TRANSLATE(0x7e58);
|
||||
smram_map[SMRAM_FIELD_GS_LIMIT] = SMRAM_TRANSLATE(0x7e54);
|
||||
smram_map[SMRAM_FIELD_GS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7e50);
|
||||
|
||||
for (unsigned n=0; n<SMRAM_FIELD_LAST;n++) {
|
||||
if (smram_map[n] >= SMM_SAVE_STATE_MAP_SIZE) {
|
||||
BX_PANIC(("smram map[%d] = %d", n, smram_map[n]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// source for Intel P6 SMM save state map used: www.sandpile.org
|
||||
|
||||
void BX_CPU_C::init_SMRAM(void)
|
||||
{
|
||||
smram_map[SMRAM_FIELD_SMBASE_OFFSET] = SMRAM_TRANSLATE(0x7ef8);
|
||||
smram_map[SMRAM_FIELD_SMM_REVISION_ID] = SMRAM_TRANSLATE(0x7efc);
|
||||
smram_map[SMRAM_FIELD_EAX] = SMRAM_TRANSLATE(0x7fd0);
|
||||
smram_map[SMRAM_FIELD_ECX] = SMRAM_TRANSLATE(0x7fd4);
|
||||
smram_map[SMRAM_FIELD_EDX] = SMRAM_TRANSLATE(0x7fd8);
|
||||
smram_map[SMRAM_FIELD_EBX] = SMRAM_TRANSLATE(0x7fdc);
|
||||
smram_map[SMRAM_FIELD_ESP] = SMRAM_TRANSLATE(0x7fe0);
|
||||
smram_map[SMRAM_FIELD_EBP] = SMRAM_TRANSLATE(0x7fe4);
|
||||
smram_map[SMRAM_FIELD_ESI] = SMRAM_TRANSLATE(0x7fe8);
|
||||
smram_map[SMRAM_FIELD_EDI] = SMRAM_TRANSLATE(0x7fec);
|
||||
smram_map[SMRAM_FIELD_EIP] = SMRAM_TRANSLATE(0x7ff0);
|
||||
smram_map[SMRAM_FIELD_EFLAGS] = SMRAM_TRANSLATE(0x7ff4);
|
||||
smram_map[SMRAM_FIELD_DR6] = SMRAM_TRANSLATE(0x7fcc);
|
||||
smram_map[SMRAM_FIELD_DR7] = SMRAM_TRANSLATE(0x7fc8);
|
||||
smram_map[SMRAM_FIELD_CR0] = SMRAM_TRANSLATE(0x7ffc);
|
||||
smram_map[SMRAM_FIELD_CR3] = SMRAM_TRANSLATE(0x7ff8);
|
||||
smram_map[SMRAM_FIELD_CR4] = SMRAM_TRANSLATE(0x7f14);
|
||||
smram_map[SMRAM_FIELD_IO_INSTRUCTION_RESTART] = SMRAM_TRANSLATE(0x7f00);
|
||||
smram_map[SMRAM_FIELD_AUTOHALT_RESTART] = SMRAM_TRANSLATE(0x7f00);
|
||||
smram_map[SMRAM_FIELD_NMI_MASK] = SMRAM_TRANSLATE(0x7f00);
|
||||
smram_map[SMRAM_FIELD_TR_SELECTOR] = SMRAM_TRANSLATE(0x7fc4);
|
||||
smram_map[SMRAM_FIELD_TR_BASE] = SMRAM_TRANSLATE(0x7f64);
|
||||
smram_map[SMRAM_FIELD_TR_LIMIT] = SMRAM_TRANSLATE(0x7f60);
|
||||
smram_map[SMRAM_FIELD_TR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f5c);
|
||||
smram_map[SMRAM_FIELD_LDTR_SELECTOR] = SMRAM_TRANSLATE(0x7fc0);
|
||||
smram_map[SMRAM_FIELD_LDTR_BASE] = SMRAM_TRANSLATE(0x7f80);
|
||||
smram_map[SMRAM_FIELD_LDTR_LIMIT] = SMRAM_TRANSLATE(0x7f7c);
|
||||
smram_map[SMRAM_FIELD_LDTR_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f78);
|
||||
smram_map[SMRAM_FIELD_IDTR_BASE] = SMRAM_TRANSLATE(0x7f58);
|
||||
smram_map[SMRAM_FIELD_IDTR_LIMIT] = SMRAM_TRANSLATE(0x7f54);
|
||||
smram_map[SMRAM_FIELD_GDTR_BASE] = SMRAM_TRANSLATE(0x7f74);
|
||||
smram_map[SMRAM_FIELD_GDTR_LIMIT] = SMRAM_TRANSLATE(0x7f70);
|
||||
smram_map[SMRAM_FIELD_ES_SELECTOR] = SMRAM_TRANSLATE(0x7fa8);
|
||||
smram_map[SMRAM_FIELD_ES_BASE] = SMRAM_TRANSLATE(0x7f8c);
|
||||
smram_map[SMRAM_FIELD_ES_LIMIT] = SMRAM_TRANSLATE(0x7f88);
|
||||
smram_map[SMRAM_FIELD_ES_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f84);
|
||||
smram_map[SMRAM_FIELD_CS_SELECTOR] = SMRAM_TRANSLATE(0x7fac);
|
||||
smram_map[SMRAM_FIELD_CS_BASE] = SMRAM_TRANSLATE(0x7f98);
|
||||
smram_map[SMRAM_FIELD_CS_LIMIT] = SMRAM_TRANSLATE(0x7f94);
|
||||
smram_map[SMRAM_FIELD_CS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f90);
|
||||
smram_map[SMRAM_FIELD_SS_SELECTOR] = SMRAM_TRANSLATE(0x7fb0);
|
||||
smram_map[SMRAM_FIELD_SS_BASE] = SMRAM_TRANSLATE(0x7fa4);
|
||||
smram_map[SMRAM_FIELD_SS_LIMIT] = SMRAM_TRANSLATE(0x7fa0);
|
||||
smram_map[SMRAM_FIELD_SS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f9c);
|
||||
smram_map[SMRAM_FIELD_DS_SELECTOR] = SMRAM_TRANSLATE(0x7fb4);
|
||||
smram_map[SMRAM_FIELD_DS_BASE] = SMRAM_TRANSLATE(0x7f34);
|
||||
smram_map[SMRAM_FIELD_DS_LIMIT] = SMRAM_TRANSLATE(0x7f30);
|
||||
smram_map[SMRAM_FIELD_DS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f2c);
|
||||
smram_map[SMRAM_FIELD_FS_SELECTOR] = SMRAM_TRANSLATE(0x7fb8);
|
||||
smram_map[SMRAM_FIELD_FS_BASE] = SMRAM_TRANSLATE(0x7f40);
|
||||
smram_map[SMRAM_FIELD_FS_LIMIT] = SMRAM_TRANSLATE(0x7f3c);
|
||||
smram_map[SMRAM_FIELD_FS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f38);
|
||||
smram_map[SMRAM_FIELD_GS_SELECTOR] = SMRAM_TRANSLATE(0x7fbc);
|
||||
smram_map[SMRAM_FIELD_GS_BASE] = SMRAM_TRANSLATE(0x7f4c);
|
||||
smram_map[SMRAM_FIELD_GS_LIMIT] = SMRAM_TRANSLATE(0x7f48);
|
||||
smram_map[SMRAM_FIELD_GS_SELECTOR_AR] = SMRAM_TRANSLATE(0x7f44);
|
||||
|
||||
for (unsigned n=0; n<SMRAM_FIELD_LAST;n++) {
|
||||
if (smram_map[n] >= SMM_SAVE_STATE_MAP_SIZE) {
|
||||
BX_PANIC(("smram map[%d] = %d", n, smram_map[n]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define SMRAM_FIELD(state, field) (state[smram_map[field]])
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
BX_CPP_INLINE Bit64u SMRAM_FIELD64(const Bit32u *saved_state, unsigned hi, unsigned lo)
|
||||
{
|
||||
Bit64u tmp = ((Bit64u) SMRAM_FIELD(saved_state, hi)) << 32;
|
||||
tmp |= (Bit64u) SMRAM_FIELD(saved_state, lo);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
void BX_CPU_C::smram_save_state(Bit32u *saved_state)
|
||||
{
|
||||
// --- General Purpose Registers --- //
|
||||
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
|
||||
Bit64u val_64 = BX_READ_64BIT_REG(n);
|
||||
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_RAX_HI32 + 2*n) = GET32H(val_64);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EAX + 2*n) = GET32L(val_64);
|
||||
}
|
||||
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_RIP_HI32) = GET32H(RIP);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EIP) = EIP;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS) = read_eflags();
|
||||
|
||||
// --- Debug and Control Registers --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6) = BX_CPU_THIS_PTR dr6;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7) = BX_CPU_THIS_PTR dr7;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0) = BX_CPU_THIS_PTR cr0.get32();
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3_HI32) = GET32H(BX_CPU_THIS_PTR cr3);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3) = GET32L(BX_CPU_THIS_PTR cr3);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4) = BX_CPU_THIS_PTR cr4.get32();
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EFER) = BX_CPU_THIS_PTR efer.get32();
|
||||
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET) = BX_CPU_THIS_PTR smbase;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMM_REVISION_ID) = SMM_REVISION_ID;
|
||||
|
||||
// --- Task Register --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR tr.cache.u.segment.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE) = GET32L(BX_CPU_THIS_PTR tr.cache.u.segment.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT) = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
|
||||
Bit32u tr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR tr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR tr.cache.valid << 8);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) = BX_CPU_THIS_PTR tr.selector.value | (tr_ar << 16);
|
||||
|
||||
// --- LDTR --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR ldtr.cache.u.segment.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE) = GET32L(BX_CPU_THIS_PTR ldtr.cache.u.segment.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT) = BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled;
|
||||
Bit32u ldtr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR ldtr.cache.valid << 8);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) = BX_CPU_THIS_PTR ldtr.selector.value | (ldtr_ar << 16);
|
||||
|
||||
// --- IDTR --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR idtr.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE) = GET32L(BX_CPU_THIS_PTR idtr.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT) = BX_CPU_THIS_PTR idtr.limit;
|
||||
|
||||
// --- GDTR --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE_HI32) = GET32H(BX_CPU_THIS_PTR gdtr.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE) = GET32L(BX_CPU_THIS_PTR gdtr.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT) = BX_CPU_THIS_PTR gdtr.limit;
|
||||
|
||||
for (int segreg = 0; segreg < 6; segreg++) {
|
||||
bx_segment_reg_t *seg = &(BX_CPU_THIS_PTR sregs[segreg]);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE_HI32 + 4*segreg) = GET32H(seg->cache.u.segment.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE + 4*segreg) = GET32L(seg->cache.u.segment.base);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg) = seg->cache.u.segment.limit_scaled;
|
||||
Bit32u seg_ar = ((get_descriptor_h(&seg->cache) >> 8) & 0xf0ff) | (seg->cache.valid << 8);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) = seg->selector.value | (seg_ar << 16);
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::smram_restore_state(const Bit32u *saved_state)
|
||||
{
|
||||
Bit32u temp_cr0 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0);
|
||||
Bit32u temp_eflags = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS);
|
||||
Bit32u temp_efer = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFER);
|
||||
Bit32u temp_cr4 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4);
|
||||
|
||||
// Processors that support VMX operation perform RSM as follows:
|
||||
#if BX_SUPPORT_VMX
|
||||
// IF VMXE=1 in CR4 image in SMRAM
|
||||
// THEN
|
||||
// fail and enter shutdown state;
|
||||
|
||||
if (temp_cr4 & BX_CR4_VMXE_MASK) {
|
||||
BX_PANIC(("SMM restore: CR4.VMXE is set in restore image !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// restore state normally from SMRAM;
|
||||
// CR4.VMXE = value stored internally;
|
||||
// IF internal storage indicates that the logical processor had been in VMX operation (root or non-root)
|
||||
// THEN
|
||||
// enter VMX operation (root or non-root);
|
||||
// restore VMX-critical state
|
||||
// set CR0.PE, CR0.NE, and CR0.PG to 1;
|
||||
// IF RFLAGS.VM = 0
|
||||
// THEN
|
||||
// CS.RPL = SS.DPL;
|
||||
// SS.RPL = SS.DPL;
|
||||
// FI;
|
||||
// If necessary, restore current VMCS pointer;
|
||||
// Leave SMM; Deassert SMMEM on subsequent bus transactions;
|
||||
// IF logical processor will be in VMX operation after RSM
|
||||
// THEN
|
||||
// block A20M and leave A20M mode;
|
||||
// FI;
|
||||
|
||||
if (BX_CPU_THIS_PTR in_smm_vmx) {
|
||||
BX_CPU_THIS_PTR in_vmx = 1;
|
||||
BX_CPU_THIS_PTR in_vmx_guest = BX_CPU_THIS_PTR in_smm_vmx_guest;
|
||||
BX_INFO(("SMM Restore: enable VMX %s mode", BX_CPU_THIS_PTR in_vmx_guest ? "guest" : "host"));
|
||||
temp_cr4 |= BX_CR4_VMXE_MASK; /* set VMXE */
|
||||
temp_cr0 |= (1<<31) /* PG */ | (1 << 5) /* NE */ | 0x1 /* PE */;
|
||||
// block and disable A20M;
|
||||
}
|
||||
#endif
|
||||
|
||||
bx_bool pe = (temp_cr0 & 0x1);
|
||||
bx_bool pg = (temp_cr0 >> 31) & 0x1;
|
||||
|
||||
// check CR0 conditions for entering to shutdown state
|
||||
if (!check_CR0(temp_cr0)) {
|
||||
BX_PANIC(("SMM restore: CR0 consistency check failed !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!check_CR4(temp_cr4)) {
|
||||
BX_PANIC(("SMM restore: CR4 consistency check failed !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
// shutdown if write to reserved CR4 bits
|
||||
if (!SetCR4(temp_cr4)) {
|
||||
BX_PANIC(("SMM restore: incorrect CR4 state !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (temp_efer & ~BX_EFER_SUPPORTED_BITS) {
|
||||
BX_PANIC(("SMM restore: Attemp to set EFER reserved bits: 0x%08x !", temp_efer));
|
||||
return 0;
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR efer.set32(temp_efer & BX_EFER_SUPPORTED_BITS);
|
||||
|
||||
if (BX_CPU_THIS_PTR efer.get_LMA()) {
|
||||
if (temp_eflags & EFlagsVMMask) {
|
||||
BX_PANIC(("SMM restore: If EFER.LMA = 1 => RFLAGS.VM=0 !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!BX_CPU_THIS_PTR cr4.get_PAE() || !pg || !pe || !BX_CPU_THIS_PTR efer.get_LME()) {
|
||||
BX_PANIC(("SMM restore: If EFER.LMA = 1 <=> CR4.PAE, CR0.PG, CR0.PE, EFER.LME=1 !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (BX_CPU_THIS_PTR cr4.get_PCIDE()) {
|
||||
BX_PANIC(("SMM restore: CR4.PCIDE must be clear when not in long mode !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR cr4.get_PAE() && pg && pe && BX_CPU_THIS_PTR efer.get_LME()) {
|
||||
if (! BX_CPU_THIS_PTR efer.get_LMA()) {
|
||||
BX_PANIC(("SMM restore: If EFER.LMA = 1 <=> CR4.PAE, CR0.PG, CR0.PE, EFER.LME=1 !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// hack CR0 to be able to back to long mode correctly
|
||||
BX_CPU_THIS_PTR cr0.set_PE(0); // real mode (bit 0)
|
||||
BX_CPU_THIS_PTR cr0.set_PG(0); // paging disabled (bit 31)
|
||||
if (! SetCR0(temp_cr0)) {
|
||||
BX_PANIC(("SMM restore: failed to restore CR0 !"));
|
||||
return 0;
|
||||
}
|
||||
setEFlags(temp_eflags);
|
||||
|
||||
bx_phy_address temp_cr3 = (bx_phy_address) SMRAM_FIELD64(saved_state, SMRAM_FIELD_CR3_HI32, SMRAM_FIELD_CR3);
|
||||
if (!SetCR3(temp_cr3)) {
|
||||
BX_PANIC(("SMM restore: failed to restore CR3 !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE() && !long_mode()) {
|
||||
if (! CheckPDPTR(temp_cr3)) {
|
||||
BX_ERROR(("SMM restore: PDPTR check failed !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
|
||||
Bit64u val_64 = SMRAM_FIELD64(saved_state,
|
||||
SMRAM_FIELD_RAX_HI32 + 2*n, SMRAM_FIELD_EAX + 2*n);
|
||||
|
||||
BX_WRITE_64BIT_REG(n, val_64);
|
||||
}
|
||||
|
||||
RIP = SMRAM_FIELD64(saved_state, SMRAM_FIELD_RIP_HI32, SMRAM_FIELD_EIP);
|
||||
|
||||
BX_CPU_THIS_PTR dr6 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6);
|
||||
BX_CPU_THIS_PTR dr7 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7);
|
||||
|
||||
BX_CPU_THIS_PTR gdtr.base = SMRAM_FIELD64(saved_state, SMRAM_FIELD_GDTR_BASE_HI32, SMRAM_FIELD_GDTR_BASE);
|
||||
BX_CPU_THIS_PTR gdtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT);
|
||||
BX_CPU_THIS_PTR idtr.base = SMRAM_FIELD64(saved_state, SMRAM_FIELD_IDTR_BASE_HI32, SMRAM_FIELD_IDTR_BASE);
|
||||
BX_CPU_THIS_PTR idtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT);
|
||||
|
||||
for (int segreg = 0; segreg < 6; segreg++) {
|
||||
Bit16u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) >> 16;
|
||||
if (set_segment_ar_data(&BX_CPU_THIS_PTR sregs[segreg],
|
||||
(ar_data >> 8) & 1,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) & 0xf0ff,
|
||||
SMRAM_FIELD64(saved_state, SMRAM_FIELD_ES_BASE_HI32 + 4*segreg, SMRAM_FIELD_ES_BASE + 4*segreg),
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg), ar_data))
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR sregs[segreg].cache.segment) {
|
||||
BX_PANIC(("SMM restore: restored valid non segment %d !", segreg));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleCpuModeChange();
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
handleSseModeChange();
|
||||
#endif
|
||||
|
||||
Bit16u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) >> 16;
|
||||
if (set_segment_ar_data(&BX_CPU_THIS_PTR ldtr,
|
||||
(ar_data >> 8) & 1,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) & 0xf0ff,
|
||||
SMRAM_FIELD64(saved_state, SMRAM_FIELD_LDTR_BASE_HI32, SMRAM_FIELD_LDTR_BASE),
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT), ar_data))
|
||||
{
|
||||
if (BX_CPU_THIS_PTR ldtr.cache.type != BX_SYS_SEGMENT_LDT) {
|
||||
BX_PANIC(("SMM restore: LDTR is not LDT descriptor type !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) >> 16;
|
||||
if (set_segment_ar_data(&BX_CPU_THIS_PTR tr,
|
||||
(ar_data >> 8) & 1,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) & 0xf0ff,
|
||||
SMRAM_FIELD64(saved_state, SMRAM_FIELD_TR_BASE_HI32, SMRAM_FIELD_TR_BASE),
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT), ar_data))
|
||||
{
|
||||
if (BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_286_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_286_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_386_TSS)
|
||||
{
|
||||
BX_PANIC(("SMM restore: TR is not TSS descriptor type !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION)
|
||||
BX_CPU_THIS_PTR smbase = SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else /* BX_SUPPORT_X86_64 == 0 */
|
||||
|
||||
void BX_CPU_C::smram_save_state(Bit32u *saved_state)
|
||||
{
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMM_REVISION_ID) = SMM_REVISION_ID;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET) = BX_CPU_THIS_PTR smbase;
|
||||
|
||||
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
|
||||
Bit32u val_32 = BX_READ_32BIT_REG(n);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EAX + n) = val_32;
|
||||
}
|
||||
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EIP) = EIP;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS) = read_eflags();
|
||||
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0) = BX_CPU_THIS_PTR cr0.get32();
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3) = BX_CPU_THIS_PTR cr3;
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4) = BX_CPU_THIS_PTR cr4.get32();
|
||||
#endif
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6) = BX_CPU_THIS_PTR dr6;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7) = BX_CPU_THIS_PTR dr7;
|
||||
|
||||
// --- Task Register --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR) = BX_CPU_THIS_PTR tr.selector.value;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE) = BX_CPU_THIS_PTR tr.cache.u.segment.base;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT) = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
|
||||
Bit32u tr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR tr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR tr.cache.valid << 8);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) = BX_CPU_THIS_PTR tr.selector.value | (tr_ar << 16);
|
||||
|
||||
// --- LDTR --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR) = BX_CPU_THIS_PTR ldtr.selector.value;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE) = BX_CPU_THIS_PTR ldtr.cache.u.segment.base;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT) = BX_CPU_THIS_PTR ldtr.cache.u.segment.limit_scaled;
|
||||
Bit32u ldtr_ar = ((get_descriptor_h(&BX_CPU_THIS_PTR ldtr.cache) >> 8) & 0xf0ff) | (BX_CPU_THIS_PTR ldtr.cache.valid << 8);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) = BX_CPU_THIS_PTR ldtr.selector.value | (ldtr_ar << 16);
|
||||
|
||||
// --- IDTR --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE) = BX_CPU_THIS_PTR idtr.base;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT) = BX_CPU_THIS_PTR idtr.limit;
|
||||
|
||||
// --- GDTR --- //
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE) = BX_CPU_THIS_PTR gdtr.base;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT) = BX_CPU_THIS_PTR gdtr.limit;
|
||||
|
||||
for (int segreg = 0; segreg < 6; segreg++) {
|
||||
bx_segment_reg_t *seg = &(BX_CPU_THIS_PTR sregs[segreg]);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR + 4*segreg) = seg->selector.value;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE + 4*segreg) = seg->cache.u.segment.base;
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg) = seg->cache.u.segment.limit_scaled;
|
||||
Bit32u seg_ar = ((get_descriptor_h(&seg->cache) >> 8) & 0xf0ff) | (seg->cache.valid << 8);
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) = seg->selector.value | (seg_ar << 16);
|
||||
}
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::smram_restore_state(const Bit32u *saved_state)
|
||||
{
|
||||
// check conditions for entering to shutdown state
|
||||
Bit32u temp_cr0 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR0);
|
||||
if (!check_CR0(temp_cr0)) {
|
||||
BX_PANIC(("SMM restore: CR0 consistency check failed !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
Bit32u temp_cr4 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR4);
|
||||
if (! check_CR4(temp_cr4)) {
|
||||
BX_PANIC(("SMM restore: CR4 consistency check failed !"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!SetCR0(temp_cr0)) {
|
||||
BX_PANIC(("SMM restore: failed to restore CR0 !"));
|
||||
return 0;
|
||||
}
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
if (!SetCR4(temp_cr4)) {
|
||||
BX_PANIC(("SMM restore: incorrect CR4 state !"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Bit32u temp_cr3 = SMRAM_FIELD(saved_state, SMRAM_FIELD_CR3);
|
||||
if (!SetCR3(temp_cr3)) {
|
||||
BX_PANIC(("SMM restore: failed to restore CR3 !"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE()) {
|
||||
if (! CheckPDPTR(temp_cr3)) {
|
||||
BX_ERROR(("SMM restore: PDPTR check failed !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Bit32u temp_eflags = SMRAM_FIELD(saved_state, SMRAM_FIELD_EFLAGS);
|
||||
setEFlags(temp_eflags);
|
||||
|
||||
for (int n=0; n<BX_GENERAL_REGISTERS; n++) {
|
||||
Bit32u val_32 = SMRAM_FIELD(saved_state, SMRAM_FIELD_EAX + n);
|
||||
BX_WRITE_32BIT_REGZ(n, val_32);
|
||||
}
|
||||
|
||||
EIP = SMRAM_FIELD(saved_state, SMRAM_FIELD_EIP);
|
||||
|
||||
BX_CPU_THIS_PTR dr6 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR6);
|
||||
BX_CPU_THIS_PTR dr7 = SMRAM_FIELD(saved_state, SMRAM_FIELD_DR7);
|
||||
|
||||
BX_CPU_THIS_PTR gdtr.base = SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_BASE);
|
||||
BX_CPU_THIS_PTR gdtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_GDTR_LIMIT);
|
||||
|
||||
BX_CPU_THIS_PTR idtr.base = SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_BASE);
|
||||
BX_CPU_THIS_PTR idtr.limit = SMRAM_FIELD(saved_state, SMRAM_FIELD_IDTR_LIMIT);
|
||||
|
||||
for (int segreg = 0; segreg < 6; segreg++) {
|
||||
Bit32u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) >> 16;
|
||||
if (set_segment_ar_data(&BX_CPU_THIS_PTR sregs[segreg],
|
||||
(ar_data >> 8) & 1,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_SELECTOR_AR + 4*segreg) & 0xf0ff,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_BASE + 4*segreg),
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_ES_LIMIT + 4*segreg), ar_data))
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR sregs[segreg].cache.segment) {
|
||||
BX_PANIC(("SMM restore: restored valid non segment %d !", segreg));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Bit32u ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) >> 16;
|
||||
if (set_segment_ar_data(&BX_CPU_THIS_PTR ldtr,
|
||||
(ar_data >> 8) & 1,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_SELECTOR_AR) & 0xf0ff,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_BASE),
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_LDTR_LIMIT), ar_data))
|
||||
{
|
||||
if (BX_CPU_THIS_PTR ldtr.cache.type != BX_SYS_SEGMENT_LDT) {
|
||||
BX_PANIC(("SMM restore: LDTR is not LDT descriptor type !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
ar_data = SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) >> 16;
|
||||
if (set_segment_ar_data(&BX_CPU_THIS_PTR tr,
|
||||
(ar_data >> 8) & 1,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_SELECTOR_AR) & 0xf0ff,
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_BASE),
|
||||
SMRAM_FIELD(saved_state, SMRAM_FIELD_TR_LIMIT), ar_data))
|
||||
{
|
||||
if (BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_286_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_286_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_AVAIL_386_TSS &&
|
||||
BX_CPU_THIS_PTR tr.cache.type != BX_SYS_SEGMENT_BUSY_386_TSS)
|
||||
{
|
||||
BX_PANIC(("SMM restore: TR is not TSS descriptor type !"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (SMM_REVISION_ID & SMM_SMBASE_RELOCATION) {
|
||||
BX_CPU_THIS_PTR smbase = SMRAM_FIELD(saved_state, SMRAM_FIELD_SMBASE_OFFSET);
|
||||
#if BX_CPU_LEVEL < 6
|
||||
if (BX_CPU_THIS_PTR smbase & 0x7fff) {
|
||||
BX_PANIC(("SMM restore: SMBASE must be aligned to 32K !"));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif /* BX_SUPPORT_X86_64 */
|
||||
|
||||
#endif /* BX_CPU_LEVEL >= 3 */
|
||||
203
simulators/bochs/cpu/smm.h
Executable file
203
simulators/bochs/cpu/smm.h
Executable file
@ -0,0 +1,203 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2006-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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_SMM_H
|
||||
#define BX_SMM_H
|
||||
|
||||
/* SMM feature masks */
|
||||
#define SMM_IO_INSTRUCTION_RESTART (0x00010000)
|
||||
#define SMM_SMBASE_RELOCATION (0x00020000)
|
||||
|
||||
#define SMM_SAVE_STATE_MAP_SIZE 128
|
||||
|
||||
//
|
||||
// - For x86-64 configuration using AMD Athlon 64 512-byte SMM save state map
|
||||
// revision ID according to QEMU/Bochs BIOS
|
||||
//
|
||||
// - For x86-32 configuration using Intel P6 512-byte SMM save state map
|
||||
//
|
||||
|
||||
#define SMM_REVISION_ID \
|
||||
((BX_SUPPORT_X86_64 ? 0x00000064 : 0) | SMM_SMBASE_RELOCATION)
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
enum SMMRAM_Fields {
|
||||
SMRAM_FIELD_SMBASE_OFFSET = 0,
|
||||
SMRAM_FIELD_SMM_REVISION_ID,
|
||||
SMRAM_FIELD_RAX_HI32,
|
||||
SMRAM_FIELD_EAX,
|
||||
SMRAM_FIELD_RCX_HI32,
|
||||
SMRAM_FIELD_ECX,
|
||||
SMRAM_FIELD_RDX_HI32,
|
||||
SMRAM_FIELD_EDX,
|
||||
SMRAM_FIELD_RBX_HI32,
|
||||
SMRAM_FIELD_EBX,
|
||||
SMRAM_FIELD_RSP_HI32,
|
||||
SMRAM_FIELD_ESP,
|
||||
SMRAM_FIELD_RBP_HI32,
|
||||
SMRAM_FIELD_EBP,
|
||||
SMRAM_FIELD_RSI_HI32,
|
||||
SMRAM_FIELD_ESI,
|
||||
SMRAM_FIELD_RDI_HI32,
|
||||
SMRAM_FIELD_EDI,
|
||||
SMRAM_FIELD_R8_HI32,
|
||||
SMRAM_FIELD_R8,
|
||||
SMRAM_FIELD_R9_HI32,
|
||||
SMRAM_FIELD_R9,
|
||||
SMRAM_FIELD_R10_HI32,
|
||||
SMRAM_FIELD_R10,
|
||||
SMRAM_FIELD_R11_HI32,
|
||||
SMRAM_FIELD_R11,
|
||||
SMRAM_FIELD_R12_HI32,
|
||||
SMRAM_FIELD_R12,
|
||||
SMRAM_FIELD_R13_HI32,
|
||||
SMRAM_FIELD_R13,
|
||||
SMRAM_FIELD_R14_HI32,
|
||||
SMRAM_FIELD_R14,
|
||||
SMRAM_FIELD_R15_HI32,
|
||||
SMRAM_FIELD_R15,
|
||||
SMRAM_FIELD_RIP_HI32,
|
||||
SMRAM_FIELD_EIP,
|
||||
SMRAM_FIELD_RFLAGS_HI32, // always zero
|
||||
SMRAM_FIELD_EFLAGS,
|
||||
SMRAM_FIELD_DR6_HI32, // always zero
|
||||
SMRAM_FIELD_DR6,
|
||||
SMRAM_FIELD_DR7_HI32, // always zero
|
||||
SMRAM_FIELD_DR7,
|
||||
SMRAM_FIELD_CR0_HI32, // always zero
|
||||
SMRAM_FIELD_CR0,
|
||||
SMRAM_FIELD_CR3_HI32, // zero when physical address size 32-bit
|
||||
SMRAM_FIELD_CR3,
|
||||
SMRAM_FIELD_CR4_HI32, // always zero
|
||||
SMRAM_FIELD_CR4,
|
||||
SMRAM_FIELD_EFER_HI32, // always zero
|
||||
SMRAM_FIELD_EFER,
|
||||
SMRAM_FIELD_IO_INSTRUCTION_RESTART,
|
||||
SMRAM_FIELD_AUTOHALT_RESTART,
|
||||
SMRAM_FIELD_NMI_MASK,
|
||||
SMRAM_FIELD_TR_BASE_HI32,
|
||||
SMRAM_FIELD_TR_BASE,
|
||||
SMRAM_FIELD_TR_LIMIT,
|
||||
SMRAM_FIELD_TR_SELECTOR_AR,
|
||||
SMRAM_FIELD_LDTR_BASE_HI32,
|
||||
SMRAM_FIELD_LDTR_BASE,
|
||||
SMRAM_FIELD_LDTR_LIMIT,
|
||||
SMRAM_FIELD_LDTR_SELECTOR_AR,
|
||||
SMRAM_FIELD_IDTR_BASE_HI32,
|
||||
SMRAM_FIELD_IDTR_BASE,
|
||||
SMRAM_FIELD_IDTR_LIMIT,
|
||||
SMRAM_FIELD_GDTR_BASE_HI32,
|
||||
SMRAM_FIELD_GDTR_BASE,
|
||||
SMRAM_FIELD_GDTR_LIMIT,
|
||||
SMRAM_FIELD_ES_BASE_HI32,
|
||||
SMRAM_FIELD_ES_BASE,
|
||||
SMRAM_FIELD_ES_LIMIT,
|
||||
SMRAM_FIELD_ES_SELECTOR_AR,
|
||||
SMRAM_FIELD_CS_BASE_HI32,
|
||||
SMRAM_FIELD_CS_BASE,
|
||||
SMRAM_FIELD_CS_LIMIT,
|
||||
SMRAM_FIELD_CS_SELECTOR_AR,
|
||||
SMRAM_FIELD_SS_BASE_HI32,
|
||||
SMRAM_FIELD_SS_BASE,
|
||||
SMRAM_FIELD_SS_LIMIT,
|
||||
SMRAM_FIELD_SS_SELECTOR_AR,
|
||||
SMRAM_FIELD_DS_BASE_HI32,
|
||||
SMRAM_FIELD_DS_BASE,
|
||||
SMRAM_FIELD_DS_LIMIT,
|
||||
SMRAM_FIELD_DS_SELECTOR_AR,
|
||||
SMRAM_FIELD_FS_BASE_HI32,
|
||||
SMRAM_FIELD_FS_BASE,
|
||||
SMRAM_FIELD_FS_LIMIT,
|
||||
SMRAM_FIELD_FS_SELECTOR_AR,
|
||||
SMRAM_FIELD_GS_BASE_HI32,
|
||||
SMRAM_FIELD_GS_BASE,
|
||||
SMRAM_FIELD_GS_LIMIT,
|
||||
SMRAM_FIELD_GS_SELECTOR_AR,
|
||||
SMRAM_FIELD_LAST
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
enum SMMRAM_Fields {
|
||||
SMRAM_FIELD_SMBASE_OFFSET = 0,
|
||||
SMRAM_FIELD_SMM_REVISION_ID,
|
||||
SMRAM_FIELD_EAX,
|
||||
SMRAM_FIELD_ECX,
|
||||
SMRAM_FIELD_EDX,
|
||||
SMRAM_FIELD_EBX,
|
||||
SMRAM_FIELD_ESP,
|
||||
SMRAM_FIELD_EBP,
|
||||
SMRAM_FIELD_ESI,
|
||||
SMRAM_FIELD_EDI,
|
||||
SMRAM_FIELD_EIP,
|
||||
SMRAM_FIELD_EFLAGS,
|
||||
SMRAM_FIELD_DR6,
|
||||
SMRAM_FIELD_DR7,
|
||||
SMRAM_FIELD_CR0,
|
||||
SMRAM_FIELD_CR3,
|
||||
SMRAM_FIELD_CR4,
|
||||
SMRAM_FIELD_IO_INSTRUCTION_RESTART,
|
||||
SMRAM_FIELD_AUTOHALT_RESTART,
|
||||
SMRAM_FIELD_NMI_MASK,
|
||||
SMRAM_FIELD_TR_SELECTOR,
|
||||
SMRAM_FIELD_TR_BASE,
|
||||
SMRAM_FIELD_TR_LIMIT,
|
||||
SMRAM_FIELD_TR_SELECTOR_AR,
|
||||
SMRAM_FIELD_LDTR_SELECTOR,
|
||||
SMRAM_FIELD_LDTR_BASE,
|
||||
SMRAM_FIELD_LDTR_LIMIT,
|
||||
SMRAM_FIELD_LDTR_SELECTOR_AR,
|
||||
SMRAM_FIELD_IDTR_BASE,
|
||||
SMRAM_FIELD_IDTR_LIMIT,
|
||||
SMRAM_FIELD_GDTR_BASE,
|
||||
SMRAM_FIELD_GDTR_LIMIT,
|
||||
SMRAM_FIELD_ES_SELECTOR,
|
||||
SMRAM_FIELD_ES_BASE,
|
||||
SMRAM_FIELD_ES_LIMIT,
|
||||
SMRAM_FIELD_ES_SELECTOR_AR,
|
||||
SMRAM_FIELD_CS_SELECTOR,
|
||||
SMRAM_FIELD_CS_BASE,
|
||||
SMRAM_FIELD_CS_LIMIT,
|
||||
SMRAM_FIELD_CS_SELECTOR_AR,
|
||||
SMRAM_FIELD_SS_SELECTOR,
|
||||
SMRAM_FIELD_SS_BASE,
|
||||
SMRAM_FIELD_SS_LIMIT,
|
||||
SMRAM_FIELD_SS_SELECTOR_AR,
|
||||
SMRAM_FIELD_DS_SELECTOR,
|
||||
SMRAM_FIELD_DS_BASE,
|
||||
SMRAM_FIELD_DS_LIMIT,
|
||||
SMRAM_FIELD_DS_SELECTOR_AR,
|
||||
SMRAM_FIELD_FS_SELECTOR,
|
||||
SMRAM_FIELD_FS_BASE,
|
||||
SMRAM_FIELD_FS_LIMIT,
|
||||
SMRAM_FIELD_FS_SELECTOR_AR,
|
||||
SMRAM_FIELD_GS_SELECTOR,
|
||||
SMRAM_FIELD_GS_BASE,
|
||||
SMRAM_FIELD_GS_LIMIT,
|
||||
SMRAM_FIELD_GS_SELECTOR_AR,
|
||||
SMRAM_FIELD_LAST
|
||||
};
|
||||
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
|
||||
#endif
|
||||
162
simulators/bochs/cpu/soft_int.cc
Normal file
162
simulators/bochs/cpu/soft_int.cc
Normal file
@ -0,0 +1,162 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RSP ESP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GwMa(bxInstruction_c *i)
|
||||
{
|
||||
Bit16s op1_16 = BX_READ_16BIT_REG(i->nnn());
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16s bound_min = (Bit16s) read_virtual_word_32(i->seg(), eaddr);
|
||||
Bit16s bound_max = (Bit16s) read_virtual_word_32(i->seg(), (eaddr+2) & i->asize_mask());
|
||||
|
||||
if (op1_16 < bound_min || op1_16 > bound_max) {
|
||||
BX_INFO(("BOUND_GdMa: fails bounds test"));
|
||||
exception(BX_BR_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::BOUND_GdMa(bxInstruction_c *i)
|
||||
{
|
||||
Bit32s op1_32 = BX_READ_32BIT_REG(i->nnn());
|
||||
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32s bound_min = (Bit32s) read_virtual_dword_32(i->seg(), eaddr);
|
||||
Bit32s bound_max = (Bit32s) read_virtual_dword_32(i->seg(), (eaddr+4) & i->asize_mask());
|
||||
|
||||
if (op1_32 < bound_min || op1_32 > bound_max) {
|
||||
BX_INFO(("BOUND_GdMa: fails bounds test"));
|
||||
exception(BX_BR_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// This is an undocumented instrucion (opcode 0xf1) which
|
||||
// is useful for an ICE system
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT1(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_Event(i, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 1, 0, 0);
|
||||
#endif
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_softint;
|
||||
#endif
|
||||
|
||||
BX_CPU_THIS_PTR EXT = 1;
|
||||
|
||||
// interrupt is not RSP safe
|
||||
interrupt(1, BX_PRIVILEGED_SOFTWARE_INTERRUPT, 0, 0);
|
||||
|
||||
BX_CPU_THIS_PTR EXT = 0;
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
||||
EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT3(bxInstruction_c *i)
|
||||
{
|
||||
// INT 3 is not IOPL sensitive
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 3, 0, 0);
|
||||
#endif
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_softint;
|
||||
#endif
|
||||
|
||||
// interrupt is not RSP safe
|
||||
interrupt(3, BX_SOFTWARE_EXCEPTION, 0, 0);
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
||||
EIP);
|
||||
}
|
||||
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INT_Ib(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_softint;
|
||||
#endif
|
||||
|
||||
Bit8u vector = i->Ib();
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_Event(i, BX_SOFTWARE_INTERRUPT, vector, 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_EXIT_STATUS
|
||||
if ((vector == 0x21) && (AH == 0x4c)) {
|
||||
BX_INFO(("INT 21/4C called AL=0x%02x, BX=0x%04x", (unsigned) AL, (unsigned) BX));
|
||||
}
|
||||
#endif
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
if (v8086_mode()) {
|
||||
// redirect interrupt through virtual-mode idt
|
||||
if (v86_redirect_interrupt(vector)) goto done;
|
||||
}
|
||||
|
||||
interrupt(vector, BX_SOFTWARE_INTERRUPT, 0, 0);
|
||||
|
||||
done:
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
||||
EIP);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::INTO(bxInstruction_c *i)
|
||||
{
|
||||
if (get_OF()) {
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_Event(i, BX_SOFTWARE_EXCEPTION, 4, 0, 0);
|
||||
#endif
|
||||
|
||||
#if BX_DEBUGGER
|
||||
BX_CPU_THIS_PTR show_flag |= Flag_softint;
|
||||
#endif
|
||||
|
||||
// interrupt is not RSP safe
|
||||
interrupt(4, BX_SOFTWARE_EXCEPTION, 0, 0);
|
||||
|
||||
BX_INSTR_FAR_BRANCH(BX_CPU_ID, BX_INSTR_IS_INT,
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
|
||||
EIP);
|
||||
}
|
||||
}
|
||||
2438
simulators/bochs/cpu/sse.cc
Normal file
2438
simulators/bochs/cpu/sse.cc
Normal file
File diff suppressed because it is too large
Load Diff
1074
simulators/bochs/cpu/sse_move.cc
Normal file
1074
simulators/bochs/cpu/sse_move.cc
Normal file
File diff suppressed because it is too large
Load Diff
2272
simulators/bochs/cpu/sse_pfp.cc
Normal file
2272
simulators/bochs/cpu/sse_pfp.cc
Normal file
File diff suppressed because it is too large
Load Diff
727
simulators/bochs/cpu/sse_rcp.cc
Executable file
727
simulators/bochs/cpu/sse_rcp.cc
Executable file
@ -0,0 +1,727 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2003-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
|
||||
#include "fpu/softfloat-specialize.h"
|
||||
|
||||
BX_CPP_INLINE float32 convert_to_QNaN(float32 op)
|
||||
{
|
||||
return op | 0x00400000;
|
||||
}
|
||||
|
||||
static Bit16u rcp_table[2048] = {
|
||||
0x7ff0, 0x7fd0, 0x7fb0, 0x7f90, 0x7f70, 0x7f50, 0x7f30, 0x7f10,
|
||||
0x7ef0, 0x7ed0, 0x7eb0, 0x7e90, 0x7e70, 0x7e50, 0x7e30, 0x7e10,
|
||||
0x7df8, 0x7dd8, 0x7db8, 0x7d98, 0x7d78, 0x7d58, 0x7d38, 0x7d18,
|
||||
0x7cf8, 0x7cd8, 0x7cb8, 0x7c98, 0x7c80, 0x7c60, 0x7c40, 0x7c20,
|
||||
0x7c00, 0x7be0, 0x7bc0, 0x7ba0, 0x7b88, 0x7b68, 0x7b48, 0x7b28,
|
||||
0x7b08, 0x7ae8, 0x7ac8, 0x7ab0, 0x7a90, 0x7a70, 0x7a50, 0x7a30,
|
||||
0x7a10, 0x79f8, 0x79d8, 0x79b8, 0x7998, 0x7978, 0x7960, 0x7940,
|
||||
0x7920, 0x7900, 0x78e0, 0x78c8, 0x78a8, 0x7888, 0x7868, 0x7850,
|
||||
0x7830, 0x7810, 0x77f0, 0x77d8, 0x77b8, 0x7798, 0x7778, 0x7760,
|
||||
0x7740, 0x7720, 0x7700, 0x76e8, 0x76c8, 0x76a8, 0x7690, 0x7670,
|
||||
0x7650, 0x7630, 0x7618, 0x75f8, 0x75d8, 0x75c0, 0x75a0, 0x7580,
|
||||
0x7568, 0x7548, 0x7528, 0x7510, 0x74f0, 0x74d0, 0x74b8, 0x7498,
|
||||
0x7478, 0x7460, 0x7440, 0x7420, 0x7408, 0x73e8, 0x73d0, 0x73b0,
|
||||
0x7390, 0x7378, 0x7358, 0x7338, 0x7320, 0x7300, 0x72e8, 0x72c8,
|
||||
0x72a8, 0x7290, 0x7270, 0x7258, 0x7238, 0x7220, 0x7200, 0x71e0,
|
||||
0x71c8, 0x71a8, 0x7190, 0x7170, 0x7158, 0x7138, 0x7118, 0x7100,
|
||||
0x70e0, 0x70c8, 0x70a8, 0x7090, 0x7070, 0x7058, 0x7038, 0x7020,
|
||||
0x7000, 0x6fe8, 0x6fc8, 0x6fb0, 0x6f90, 0x6f78, 0x6f58, 0x6f40,
|
||||
0x6f20, 0x6f08, 0x6ee8, 0x6ed0, 0x6eb0, 0x6e98, 0x6e78, 0x6e60,
|
||||
0x6e40, 0x6e28, 0x6e08, 0x6df0, 0x6dd0, 0x6db8, 0x6da0, 0x6d80,
|
||||
0x6d68, 0x6d48, 0x6d30, 0x6d10, 0x6cf8, 0x6cd8, 0x6cc0, 0x6ca8,
|
||||
0x6c88, 0x6c70, 0x6c50, 0x6c38, 0x6c20, 0x6c00, 0x6be8, 0x6bc8,
|
||||
0x6bb0, 0x6b98, 0x6b78, 0x6b60, 0x6b40, 0x6b28, 0x6b10, 0x6af0,
|
||||
0x6ad8, 0x6ac0, 0x6aa0, 0x6a88, 0x6a70, 0x6a50, 0x6a38, 0x6a20,
|
||||
0x6a00, 0x69e8, 0x69c8, 0x69b0, 0x6998, 0x6978, 0x6960, 0x6948,
|
||||
0x6930, 0x6910, 0x68f8, 0x68e0, 0x68c0, 0x68a8, 0x6890, 0x6870,
|
||||
0x6858, 0x6840, 0x6820, 0x6808, 0x67f0, 0x67d8, 0x67b8, 0x67a0,
|
||||
0x6788, 0x6770, 0x6750, 0x6738, 0x6720, 0x6700, 0x66e8, 0x66d0,
|
||||
0x66b8, 0x6698, 0x6680, 0x6668, 0x6650, 0x6638, 0x6618, 0x6600,
|
||||
0x65e8, 0x65d0, 0x65b0, 0x6598, 0x6580, 0x6568, 0x6550, 0x6530,
|
||||
0x6518, 0x6500, 0x64e8, 0x64c8, 0x64b0, 0x6498, 0x6480, 0x6468,
|
||||
0x6450, 0x6430, 0x6418, 0x6400, 0x63e8, 0x63d0, 0x63b8, 0x6398,
|
||||
0x6380, 0x6368, 0x6350, 0x6338, 0x6320, 0x6300, 0x62e8, 0x62d0,
|
||||
0x62b8, 0x62a0, 0x6288, 0x6270, 0x6250, 0x6238, 0x6220, 0x6208,
|
||||
0x61f0, 0x61d8, 0x61c0, 0x61a8, 0x6190, 0x6170, 0x6158, 0x6140,
|
||||
0x6128, 0x6110, 0x60f8, 0x60e0, 0x60c8, 0x60b0, 0x6098, 0x6080,
|
||||
0x6060, 0x6048, 0x6030, 0x6018, 0x6000, 0x5fe8, 0x5fd0, 0x5fb8,
|
||||
0x5fa0, 0x5f88, 0x5f70, 0x5f58, 0x5f40, 0x5f28, 0x5f10, 0x5ef8,
|
||||
0x5ee0, 0x5ec8, 0x5eb0, 0x5e98, 0x5e80, 0x5e68, 0x5e50, 0x5e30,
|
||||
0x5e18, 0x5e00, 0x5de8, 0x5dd0, 0x5db8, 0x5da0, 0x5d88, 0x5d70,
|
||||
0x5d58, 0x5d40, 0x5d30, 0x5d18, 0x5d00, 0x5ce8, 0x5cd0, 0x5cb8,
|
||||
0x5ca0, 0x5c88, 0x5c70, 0x5c58, 0x5c40, 0x5c28, 0x5c10, 0x5bf8,
|
||||
0x5be0, 0x5bc8, 0x5bb0, 0x5b98, 0x5b80, 0x5b68, 0x5b50, 0x5b38,
|
||||
0x5b20, 0x5b08, 0x5af8, 0x5ae0, 0x5ac8, 0x5ab0, 0x5a98, 0x5a80,
|
||||
0x5a68, 0x5a50, 0x5a38, 0x5a20, 0x5a08, 0x59f8, 0x59e0, 0x59c8,
|
||||
0x59b0, 0x5998, 0x5980, 0x5968, 0x5950, 0x5938, 0x5928, 0x5910,
|
||||
0x58f8, 0x58e0, 0x58c8, 0x58b0, 0x5898, 0x5880, 0x5870, 0x5858,
|
||||
0x5840, 0x5828, 0x5810, 0x57f8, 0x57e0, 0x57d0, 0x57b8, 0x57a0,
|
||||
0x5788, 0x5770, 0x5758, 0x5748, 0x5730, 0x5718, 0x5700, 0x56e8,
|
||||
0x56d0, 0x56c0, 0x56a8, 0x5690, 0x5678, 0x5660, 0x5650, 0x5638,
|
||||
0x5620, 0x5608, 0x55f0, 0x55e0, 0x55c8, 0x55b0, 0x5598, 0x5588,
|
||||
0x5570, 0x5558, 0x5540, 0x5528, 0x5518, 0x5500, 0x54e8, 0x54d0,
|
||||
0x54c0, 0x54a8, 0x5490, 0x5478, 0x5468, 0x5450, 0x5438, 0x5420,
|
||||
0x5410, 0x53f8, 0x53e0, 0x53c8, 0x53b8, 0x53a0, 0x5388, 0x5370,
|
||||
0x5360, 0x5348, 0x5330, 0x5318, 0x5308, 0x52f0, 0x52d8, 0x52c8,
|
||||
0x52b0, 0x5298, 0x5280, 0x5270, 0x5258, 0x5240, 0x5230, 0x5218,
|
||||
0x5200, 0x51f0, 0x51d8, 0x51c0, 0x51b0, 0x5198, 0x5180, 0x5170,
|
||||
0x5158, 0x5140, 0x5128, 0x5118, 0x5100, 0x50e8, 0x50d8, 0x50c0,
|
||||
0x50a8, 0x5098, 0x5080, 0x5070, 0x5058, 0x5040, 0x5030, 0x5018,
|
||||
0x5000, 0x4ff0, 0x4fd8, 0x4fc0, 0x4fb0, 0x4f98, 0x4f80, 0x4f70,
|
||||
0x4f58, 0x4f48, 0x4f30, 0x4f18, 0x4f08, 0x4ef0, 0x4ee0, 0x4ec8,
|
||||
0x4eb0, 0x4ea0, 0x4e88, 0x4e78, 0x4e60, 0x4e48, 0x4e38, 0x4e20,
|
||||
0x4e10, 0x4df8, 0x4de0, 0x4dd0, 0x4db8, 0x4da8, 0x4d90, 0x4d78,
|
||||
0x4d68, 0x4d50, 0x4d40, 0x4d28, 0x4d18, 0x4d00, 0x4ce8, 0x4cd8,
|
||||
0x4cc0, 0x4cb0, 0x4c98, 0x4c88, 0x4c70, 0x4c60, 0x4c48, 0x4c30,
|
||||
0x4c20, 0x4c08, 0x4bf8, 0x4be0, 0x4bd0, 0x4bb8, 0x4ba8, 0x4b90,
|
||||
0x4b80, 0x4b68, 0x4b58, 0x4b40, 0x4b30, 0x4b18, 0x4b08, 0x4af0,
|
||||
0x4ad8, 0x4ac8, 0x4ab0, 0x4aa0, 0x4a88, 0x4a78, 0x4a60, 0x4a50,
|
||||
0x4a38, 0x4a28, 0x4a10, 0x4a00, 0x49e8, 0x49d8, 0x49c8, 0x49b0,
|
||||
0x49a0, 0x4988, 0x4978, 0x4960, 0x4950, 0x4938, 0x4928, 0x4910,
|
||||
0x4900, 0x48e8, 0x48d8, 0x48c0, 0x48b0, 0x4898, 0x4888, 0x4878,
|
||||
0x4860, 0x4850, 0x4838, 0x4828, 0x4810, 0x4800, 0x47e8, 0x47d8,
|
||||
0x47c8, 0x47b0, 0x47a0, 0x4788, 0x4778, 0x4760, 0x4750, 0x4740,
|
||||
0x4728, 0x4718, 0x4700, 0x46f0, 0x46d8, 0x46c8, 0x46b8, 0x46a0,
|
||||
0x4690, 0x4678, 0x4668, 0x4658, 0x4640, 0x4630, 0x4618, 0x4608,
|
||||
0x45f8, 0x45e0, 0x45d0, 0x45b8, 0x45a8, 0x4598, 0x4580, 0x4570,
|
||||
0x4560, 0x4548, 0x4538, 0x4520, 0x4510, 0x4500, 0x44e8, 0x44d8,
|
||||
0x44c8, 0x44b0, 0x44a0, 0x4488, 0x4478, 0x4468, 0x4450, 0x4440,
|
||||
0x4430, 0x4418, 0x4408, 0x43f8, 0x43e0, 0x43d0, 0x43c0, 0x43a8,
|
||||
0x4398, 0x4388, 0x4370, 0x4360, 0x4350, 0x4338, 0x4328, 0x4318,
|
||||
0x4300, 0x42f0, 0x42e0, 0x42c8, 0x42b8, 0x42a8, 0x4290, 0x4280,
|
||||
0x4270, 0x4260, 0x4248, 0x4238, 0x4228, 0x4210, 0x4200, 0x41f0,
|
||||
0x41d8, 0x41c8, 0x41b8, 0x41a8, 0x4190, 0x4180, 0x4170, 0x4158,
|
||||
0x4148, 0x4138, 0x4128, 0x4110, 0x4100, 0x40f0, 0x40d8, 0x40c8,
|
||||
0x40b8, 0x40a8, 0x4090, 0x4080, 0x4070, 0x4060, 0x4048, 0x4038,
|
||||
0x4028, 0x4018, 0x4000, 0x3ff0, 0x3fe0, 0x3fd0, 0x3fb8, 0x3fa8,
|
||||
0x3f98, 0x3f88, 0x3f70, 0x3f60, 0x3f50, 0x3f40, 0x3f28, 0x3f18,
|
||||
0x3f08, 0x3ef8, 0x3ee8, 0x3ed0, 0x3ec0, 0x3eb0, 0x3ea0, 0x3e88,
|
||||
0x3e78, 0x3e68, 0x3e58, 0x3e48, 0x3e30, 0x3e20, 0x3e10, 0x3e00,
|
||||
0x3df0, 0x3dd8, 0x3dc8, 0x3db8, 0x3da8, 0x3d98, 0x3d80, 0x3d70,
|
||||
0x3d60, 0x3d50, 0x3d40, 0x3d28, 0x3d18, 0x3d08, 0x3cf8, 0x3ce8,
|
||||
0x3cd8, 0x3cc0, 0x3cb0, 0x3ca0, 0x3c90, 0x3c80, 0x3c70, 0x3c58,
|
||||
0x3c48, 0x3c38, 0x3c28, 0x3c18, 0x3c08, 0x3bf0, 0x3be0, 0x3bd0,
|
||||
0x3bc0, 0x3bb0, 0x3ba0, 0x3b90, 0x3b78, 0x3b68, 0x3b58, 0x3b48,
|
||||
0x3b38, 0x3b28, 0x3b18, 0x3b00, 0x3af0, 0x3ae0, 0x3ad0, 0x3ac0,
|
||||
0x3ab0, 0x3aa0, 0x3a88, 0x3a78, 0x3a68, 0x3a58, 0x3a48, 0x3a38,
|
||||
0x3a28, 0x3a18, 0x3a08, 0x39f0, 0x39e0, 0x39d0, 0x39c0, 0x39b0,
|
||||
0x39a0, 0x3990, 0x3980, 0x3970, 0x3958, 0x3948, 0x3938, 0x3928,
|
||||
0x3918, 0x3908, 0x38f8, 0x38e8, 0x38d8, 0x38c8, 0x38b8, 0x38a8,
|
||||
0x3890, 0x3880, 0x3870, 0x3860, 0x3850, 0x3840, 0x3830, 0x3820,
|
||||
0x3810, 0x3800, 0x37f0, 0x37e0, 0x37d0, 0x37c0, 0x37a8, 0x3798,
|
||||
0x3788, 0x3778, 0x3768, 0x3758, 0x3748, 0x3738, 0x3728, 0x3718,
|
||||
0x3708, 0x36f8, 0x36e8, 0x36d8, 0x36c8, 0x36b8, 0x36a8, 0x3698,
|
||||
0x3688, 0x3678, 0x3668, 0x3658, 0x3648, 0x3630, 0x3620, 0x3610,
|
||||
0x3600, 0x35f0, 0x35e0, 0x35d0, 0x35c0, 0x35b0, 0x35a0, 0x3590,
|
||||
0x3580, 0x3570, 0x3560, 0x3550, 0x3540, 0x3530, 0x3520, 0x3510,
|
||||
0x3500, 0x34f0, 0x34e0, 0x34d0, 0x34c0, 0x34b0, 0x34a0, 0x3490,
|
||||
0x3480, 0x3470, 0x3460, 0x3450, 0x3440, 0x3430, 0x3420, 0x3410,
|
||||
0x3400, 0x33f0, 0x33e0, 0x33d0, 0x33c8, 0x33b8, 0x33a8, 0x3398,
|
||||
0x3388, 0x3378, 0x3368, 0x3358, 0x3348, 0x3338, 0x3328, 0x3318,
|
||||
0x3308, 0x32f8, 0x32e8, 0x32d8, 0x32c8, 0x32b8, 0x32a8, 0x3298,
|
||||
0x3288, 0x3278, 0x3268, 0x3260, 0x3250, 0x3240, 0x3230, 0x3220,
|
||||
0x3210, 0x3200, 0x31f0, 0x31e0, 0x31d0, 0x31c0, 0x31b0, 0x31a0,
|
||||
0x3190, 0x3180, 0x3178, 0x3168, 0x3158, 0x3148, 0x3138, 0x3128,
|
||||
0x3118, 0x3108, 0x30f8, 0x30e8, 0x30d8, 0x30c8, 0x30c0, 0x30b0,
|
||||
0x30a0, 0x3090, 0x3080, 0x3070, 0x3060, 0x3050, 0x3040, 0x3030,
|
||||
0x3028, 0x3018, 0x3008, 0x2ff8, 0x2fe8, 0x2fd8, 0x2fc8, 0x2fb8,
|
||||
0x2fa8, 0x2fa0, 0x2f90, 0x2f80, 0x2f70, 0x2f60, 0x2f50, 0x2f40,
|
||||
0x2f30, 0x2f28, 0x2f18, 0x2f08, 0x2ef8, 0x2ee8, 0x2ed8, 0x2ec8,
|
||||
0x2eb8, 0x2eb0, 0x2ea0, 0x2e90, 0x2e80, 0x2e70, 0x2e60, 0x2e50,
|
||||
0x2e48, 0x2e38, 0x2e28, 0x2e18, 0x2e08, 0x2df8, 0x2df0, 0x2de0,
|
||||
0x2dd0, 0x2dc0, 0x2db0, 0x2da0, 0x2d90, 0x2d88, 0x2d78, 0x2d68,
|
||||
0x2d58, 0x2d48, 0x2d38, 0x2d30, 0x2d20, 0x2d10, 0x2d00, 0x2cf0,
|
||||
0x2ce0, 0x2cd8, 0x2cc8, 0x2cb8, 0x2ca8, 0x2c98, 0x2c90, 0x2c80,
|
||||
0x2c70, 0x2c60, 0x2c50, 0x2c40, 0x2c38, 0x2c28, 0x2c18, 0x2c08,
|
||||
0x2bf8, 0x2bf0, 0x2be0, 0x2bd0, 0x2bc0, 0x2bb0, 0x2ba8, 0x2b98,
|
||||
0x2b88, 0x2b78, 0x2b68, 0x2b60, 0x2b50, 0x2b40, 0x2b30, 0x2b20,
|
||||
0x2b18, 0x2b08, 0x2af8, 0x2ae8, 0x2ae0, 0x2ad0, 0x2ac0, 0x2ab0,
|
||||
0x2aa0, 0x2a98, 0x2a88, 0x2a78, 0x2a68, 0x2a60, 0x2a50, 0x2a40,
|
||||
0x2a30, 0x2a20, 0x2a18, 0x2a08, 0x29f8, 0x29e8, 0x29e0, 0x29d0,
|
||||
0x29c0, 0x29b0, 0x29a8, 0x2998, 0x2988, 0x2978, 0x2970, 0x2960,
|
||||
0x2950, 0x2940, 0x2938, 0x2928, 0x2918, 0x2908, 0x2900, 0x28f0,
|
||||
0x28e0, 0x28d0, 0x28c8, 0x28b8, 0x28a8, 0x2898, 0x2890, 0x2880,
|
||||
0x2870, 0x2868, 0x2858, 0x2848, 0x2838, 0x2830, 0x2820, 0x2810,
|
||||
0x2800, 0x27f8, 0x27e8, 0x27d8, 0x27d0, 0x27c0, 0x27b0, 0x27a0,
|
||||
0x2798, 0x2788, 0x2778, 0x2770, 0x2760, 0x2750, 0x2740, 0x2738,
|
||||
0x2728, 0x2718, 0x2710, 0x2700, 0x26f0, 0x26e8, 0x26d8, 0x26c8,
|
||||
0x26b8, 0x26b0, 0x26a0, 0x2690, 0x2688, 0x2678, 0x2668, 0x2660,
|
||||
0x2650, 0x2640, 0x2638, 0x2628, 0x2618, 0x2608, 0x2600, 0x25f0,
|
||||
0x25e0, 0x25d8, 0x25c8, 0x25b8, 0x25b0, 0x25a0, 0x2590, 0x2588,
|
||||
0x2578, 0x2568, 0x2560, 0x2550, 0x2540, 0x2538, 0x2528, 0x2518,
|
||||
0x2510, 0x2500, 0x24f0, 0x24e8, 0x24d8, 0x24c8, 0x24c0, 0x24b0,
|
||||
0x24a0, 0x2498, 0x2488, 0x2478, 0x2470, 0x2460, 0x2450, 0x2448,
|
||||
0x2438, 0x2430, 0x2420, 0x2410, 0x2408, 0x23f8, 0x23e8, 0x23e0,
|
||||
0x23d0, 0x23c0, 0x23b8, 0x23a8, 0x23a0, 0x2390, 0x2380, 0x2378,
|
||||
0x2368, 0x2358, 0x2350, 0x2340, 0x2330, 0x2328, 0x2318, 0x2310,
|
||||
0x2300, 0x22f0, 0x22e8, 0x22d8, 0x22d0, 0x22c0, 0x22b0, 0x22a8,
|
||||
0x2298, 0x2288, 0x2280, 0x2270, 0x2268, 0x2258, 0x2248, 0x2240,
|
||||
0x2230, 0x2228, 0x2218, 0x2208, 0x2200, 0x21f0, 0x21e8, 0x21d8,
|
||||
0x21c8, 0x21c0, 0x21b0, 0x21a8, 0x2198, 0x2188, 0x2180, 0x2170,
|
||||
0x2168, 0x2158, 0x2148, 0x2140, 0x2130, 0x2128, 0x2118, 0x2108,
|
||||
0x2100, 0x20f0, 0x20e8, 0x20d8, 0x20d0, 0x20c0, 0x20b0, 0x20a8,
|
||||
0x2098, 0x2090, 0x2080, 0x2078, 0x2068, 0x2058, 0x2050, 0x2040,
|
||||
0x2038, 0x2028, 0x2020, 0x2010, 0x2000, 0x1ff8, 0x1fe8, 0x1fe0,
|
||||
0x1fd0, 0x1fc8, 0x1fb8, 0x1fb0, 0x1fa0, 0x1f90, 0x1f88, 0x1f78,
|
||||
0x1f70, 0x1f60, 0x1f58, 0x1f48, 0x1f40, 0x1f30, 0x1f20, 0x1f18,
|
||||
0x1f08, 0x1f00, 0x1ef0, 0x1ee8, 0x1ed8, 0x1ed0, 0x1ec0, 0x1eb8,
|
||||
0x1ea8, 0x1ea0, 0x1e90, 0x1e80, 0x1e78, 0x1e68, 0x1e60, 0x1e50,
|
||||
0x1e48, 0x1e38, 0x1e30, 0x1e20, 0x1e18, 0x1e08, 0x1e00, 0x1df0,
|
||||
0x1de8, 0x1dd8, 0x1dd0, 0x1dc0, 0x1db8, 0x1da8, 0x1da0, 0x1d90,
|
||||
0x1d80, 0x1d78, 0x1d68, 0x1d60, 0x1d50, 0x1d48, 0x1d38, 0x1d30,
|
||||
0x1d20, 0x1d18, 0x1d08, 0x1d00, 0x1cf0, 0x1ce8, 0x1cd8, 0x1cd0,
|
||||
0x1cc0, 0x1cb8, 0x1ca8, 0x1ca0, 0x1c90, 0x1c88, 0x1c78, 0x1c70,
|
||||
0x1c60, 0x1c58, 0x1c48, 0x1c40, 0x1c30, 0x1c28, 0x1c18, 0x1c10,
|
||||
0x1c00, 0x1bf8, 0x1bf0, 0x1be0, 0x1bd8, 0x1bc8, 0x1bc0, 0x1bb0,
|
||||
0x1ba8, 0x1b98, 0x1b90, 0x1b80, 0x1b78, 0x1b68, 0x1b60, 0x1b50,
|
||||
0x1b48, 0x1b38, 0x1b30, 0x1b20, 0x1b18, 0x1b08, 0x1b00, 0x1af8,
|
||||
0x1ae8, 0x1ae0, 0x1ad0, 0x1ac8, 0x1ab8, 0x1ab0, 0x1aa0, 0x1a98,
|
||||
0x1a88, 0x1a80, 0x1a70, 0x1a68, 0x1a60, 0x1a50, 0x1a48, 0x1a38,
|
||||
0x1a30, 0x1a20, 0x1a18, 0x1a08, 0x1a00, 0x19f8, 0x19e8, 0x19e0,
|
||||
0x19d0, 0x19c8, 0x19b8, 0x19b0, 0x19a0, 0x1998, 0x1990, 0x1980,
|
||||
0x1978, 0x1968, 0x1960, 0x1950, 0x1948, 0x1938, 0x1930, 0x1928,
|
||||
0x1918, 0x1910, 0x1900, 0x18f8, 0x18e8, 0x18e0, 0x18d8, 0x18c8,
|
||||
0x18c0, 0x18b0, 0x18a8, 0x1898, 0x1890, 0x1888, 0x1878, 0x1870,
|
||||
0x1860, 0x1858, 0x1850, 0x1840, 0x1838, 0x1828, 0x1820, 0x1810,
|
||||
0x1808, 0x1800, 0x17f0, 0x17e8, 0x17d8, 0x17d0, 0x17c8, 0x17b8,
|
||||
0x17b0, 0x17a0, 0x1798, 0x1790, 0x1780, 0x1778, 0x1768, 0x1760,
|
||||
0x1758, 0x1748, 0x1740, 0x1730, 0x1728, 0x1720, 0x1710, 0x1708,
|
||||
0x16f8, 0x16f0, 0x16e8, 0x16d8, 0x16d0, 0x16c8, 0x16b8, 0x16b0,
|
||||
0x16a0, 0x1698, 0x1690, 0x1680, 0x1678, 0x1668, 0x1660, 0x1658,
|
||||
0x1648, 0x1640, 0x1638, 0x1628, 0x1620, 0x1610, 0x1608, 0x1600,
|
||||
0x15f0, 0x15e8, 0x15e0, 0x15d0, 0x15c8, 0x15b8, 0x15b0, 0x15a8,
|
||||
0x1598, 0x1590, 0x1588, 0x1578, 0x1570, 0x1568, 0x1558, 0x1550,
|
||||
0x1540, 0x1538, 0x1530, 0x1520, 0x1518, 0x1510, 0x1500, 0x14f8,
|
||||
0x14f0, 0x14e0, 0x14d8, 0x14d0, 0x14c0, 0x14b8, 0x14a8, 0x14a0,
|
||||
0x1498, 0x1488, 0x1480, 0x1478, 0x1468, 0x1460, 0x1458, 0x1448,
|
||||
0x1440, 0x1438, 0x1428, 0x1420, 0x1418, 0x1408, 0x1400, 0x13f8,
|
||||
0x13e8, 0x13e0, 0x13d8, 0x13c8, 0x13c0, 0x13b8, 0x13a8, 0x13a0,
|
||||
0x1398, 0x1388, 0x1380, 0x1378, 0x1368, 0x1360, 0x1358, 0x1348,
|
||||
0x1340, 0x1338, 0x1328, 0x1320, 0x1318, 0x1308, 0x1300, 0x12f8,
|
||||
0x12e8, 0x12e0, 0x12d8, 0x12d0, 0x12c0, 0x12b8, 0x12b0, 0x12a0,
|
||||
0x1298, 0x1290, 0x1280, 0x1278, 0x1270, 0x1260, 0x1258, 0x1250,
|
||||
0x1240, 0x1238, 0x1230, 0x1228, 0x1218, 0x1210, 0x1208, 0x11f8,
|
||||
0x11f0, 0x11e8, 0x11d8, 0x11d0, 0x11c8, 0x11c0, 0x11b0, 0x11a8,
|
||||
0x11a0, 0x1190, 0x1188, 0x1180, 0x1178, 0x1168, 0x1160, 0x1158,
|
||||
0x1148, 0x1140, 0x1138, 0x1128, 0x1120, 0x1118, 0x1110, 0x1100,
|
||||
0x10f8, 0x10f0, 0x10e8, 0x10d8, 0x10d0, 0x10c8, 0x10b8, 0x10b0,
|
||||
0x10a8, 0x10a0, 0x1090, 0x1088, 0x1080, 0x1070, 0x1068, 0x1060,
|
||||
0x1058, 0x1048, 0x1040, 0x1038, 0x1030, 0x1020, 0x1018, 0x1010,
|
||||
0x1000, 0x0ff8, 0x0ff0, 0x0fe8, 0x0fd8, 0x0fd0, 0x0fc8, 0x0fc0,
|
||||
0x0fb0, 0x0fa8, 0x0fa0, 0x0f98, 0x0f88, 0x0f80, 0x0f78, 0x0f70,
|
||||
0x0f60, 0x0f58, 0x0f50, 0x0f48, 0x0f38, 0x0f30, 0x0f28, 0x0f20,
|
||||
0x0f10, 0x0f08, 0x0f00, 0x0ef8, 0x0ee8, 0x0ee0, 0x0ed8, 0x0ed0,
|
||||
0x0ec0, 0x0eb8, 0x0eb0, 0x0ea8, 0x0e98, 0x0e90, 0x0e88, 0x0e80,
|
||||
0x0e70, 0x0e68, 0x0e60, 0x0e58, 0x0e48, 0x0e40, 0x0e38, 0x0e30,
|
||||
0x0e28, 0x0e18, 0x0e10, 0x0e08, 0x0e00, 0x0df0, 0x0de8, 0x0de0,
|
||||
0x0dd8, 0x0dc8, 0x0dc0, 0x0db8, 0x0db0, 0x0da8, 0x0d98, 0x0d90,
|
||||
0x0d88, 0x0d80, 0x0d70, 0x0d68, 0x0d60, 0x0d58, 0x0d50, 0x0d40,
|
||||
0x0d38, 0x0d30, 0x0d28, 0x0d18, 0x0d10, 0x0d08, 0x0d00, 0x0cf8,
|
||||
0x0ce8, 0x0ce0, 0x0cd8, 0x0cd0, 0x0cc8, 0x0cb8, 0x0cb0, 0x0ca8,
|
||||
0x0ca0, 0x0c98, 0x0c88, 0x0c80, 0x0c78, 0x0c70, 0x0c60, 0x0c58,
|
||||
0x0c50, 0x0c48, 0x0c40, 0x0c30, 0x0c28, 0x0c20, 0x0c18, 0x0c10,
|
||||
0x0c00, 0x0bf8, 0x0bf0, 0x0be8, 0x0be0, 0x0bd8, 0x0bc8, 0x0bc0,
|
||||
0x0bb8, 0x0bb0, 0x0ba8, 0x0b98, 0x0b90, 0x0b88, 0x0b80, 0x0b78,
|
||||
0x0b68, 0x0b60, 0x0b58, 0x0b50, 0x0b48, 0x0b40, 0x0b30, 0x0b28,
|
||||
0x0b20, 0x0b18, 0x0b10, 0x0b00, 0x0af8, 0x0af0, 0x0ae8, 0x0ae0,
|
||||
0x0ad8, 0x0ac8, 0x0ac0, 0x0ab8, 0x0ab0, 0x0aa8, 0x0a98, 0x0a90,
|
||||
0x0a88, 0x0a80, 0x0a78, 0x0a70, 0x0a60, 0x0a58, 0x0a50, 0x0a48,
|
||||
0x0a40, 0x0a38, 0x0a28, 0x0a20, 0x0a18, 0x0a10, 0x0a08, 0x0a00,
|
||||
0x09f0, 0x09e8, 0x09e0, 0x09d8, 0x09d0, 0x09c8, 0x09c0, 0x09b0,
|
||||
0x09a8, 0x09a0, 0x0998, 0x0990, 0x0988, 0x0978, 0x0970, 0x0968,
|
||||
0x0960, 0x0958, 0x0950, 0x0948, 0x0938, 0x0930, 0x0928, 0x0920,
|
||||
0x0918, 0x0910, 0x0900, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x08d8,
|
||||
0x08d0, 0x08c0, 0x08b8, 0x08b0, 0x08a8, 0x08a0, 0x0898, 0x0890,
|
||||
0x0880, 0x0878, 0x0870, 0x0868, 0x0860, 0x0858, 0x0850, 0x0848,
|
||||
0x0838, 0x0830, 0x0828, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800,
|
||||
0x07f0, 0x07e8, 0x07e0, 0x07d8, 0x07d0, 0x07c8, 0x07c0, 0x07b0,
|
||||
0x07a8, 0x07a0, 0x0798, 0x0790, 0x0788, 0x0780, 0x0778, 0x0770,
|
||||
0x0760, 0x0758, 0x0750, 0x0748, 0x0740, 0x0738, 0x0730, 0x0728,
|
||||
0x0718, 0x0710, 0x0708, 0x0700, 0x06f8, 0x06f0, 0x06e8, 0x06e0,
|
||||
0x06d8, 0x06c8, 0x06c0, 0x06b8, 0x06b0, 0x06a8, 0x06a0, 0x0698,
|
||||
0x0690, 0x0688, 0x0680, 0x0670, 0x0668, 0x0660, 0x0658, 0x0650,
|
||||
0x0648, 0x0640, 0x0638, 0x0630, 0x0620, 0x0618, 0x0610, 0x0608,
|
||||
0x0600, 0x05f8, 0x05f0, 0x05e8, 0x05e0, 0x05d8, 0x05d0, 0x05c0,
|
||||
0x05b8, 0x05b0, 0x05a8, 0x05a0, 0x0598, 0x0590, 0x0588, 0x0580,
|
||||
0x0578, 0x0570, 0x0560, 0x0558, 0x0550, 0x0548, 0x0540, 0x0538,
|
||||
0x0530, 0x0528, 0x0520, 0x0518, 0x0510, 0x0508, 0x04f8, 0x04f0,
|
||||
0x04e8, 0x04e0, 0x04d8, 0x04d0, 0x04c8, 0x04c0, 0x04b8, 0x04b0,
|
||||
0x04a8, 0x04a0, 0x0498, 0x0488, 0x0480, 0x0478, 0x0470, 0x0468,
|
||||
0x0460, 0x0458, 0x0450, 0x0448, 0x0440, 0x0438, 0x0430, 0x0428,
|
||||
0x0420, 0x0418, 0x0408, 0x0400, 0x03f8, 0x03f0, 0x03e8, 0x03e0,
|
||||
0x03d8, 0x03d0, 0x03c8, 0x03c0, 0x03b8, 0x03b0, 0x03a8, 0x03a0,
|
||||
0x0398, 0x0390, 0x0388, 0x0378, 0x0370, 0x0368, 0x0360, 0x0358,
|
||||
0x0350, 0x0348, 0x0340, 0x0338, 0x0330, 0x0328, 0x0320, 0x0318,
|
||||
0x0310, 0x0308, 0x0300, 0x02f8, 0x02f0, 0x02e8, 0x02d8, 0x02d0,
|
||||
0x02c8, 0x02c0, 0x02b8, 0x02b0, 0x02a8, 0x02a0, 0x0298, 0x0290,
|
||||
0x0288, 0x0280, 0x0278, 0x0270, 0x0268, 0x0260, 0x0258, 0x0250,
|
||||
0x0248, 0x0240, 0x0238, 0x0230, 0x0228, 0x0220, 0x0218, 0x0210,
|
||||
0x0200, 0x01f8, 0x01f0, 0x01e8, 0x01e0, 0x01d8, 0x01d0, 0x01c8,
|
||||
0x01c0, 0x01b8, 0x01b0, 0x01a8, 0x01a0, 0x0198, 0x0190, 0x0188,
|
||||
0x0180, 0x0178, 0x0170, 0x0168, 0x0160, 0x0158, 0x0150, 0x0148,
|
||||
0x0140, 0x0138, 0x0130, 0x0128, 0x0120, 0x0118, 0x0110, 0x0108,
|
||||
0x0100, 0x00f8, 0x00f0, 0x00e8, 0x00e0, 0x00d8, 0x00d0, 0x00c8,
|
||||
0x00c0, 0x00b8, 0x00b0, 0x00a8, 0x00a0, 0x0098, 0x0090, 0x0088,
|
||||
0x0080, 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048,
|
||||
0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008
|
||||
};
|
||||
|
||||
// approximate reciprocal of scalar single precision FP
|
||||
static float32 approximate_rcp(float32 op)
|
||||
{
|
||||
float_class_t op_class = float32_class(op);
|
||||
|
||||
int sign = float32_sign(op);
|
||||
|
||||
switch(op_class)
|
||||
{
|
||||
case float_zero:
|
||||
case float_denormal:
|
||||
return packFloat32(sign, 0xFF, 0);
|
||||
|
||||
case float_negative_inf:
|
||||
case float_positive_inf:
|
||||
return packFloat32(sign, 0x00, 0);
|
||||
|
||||
case float_NaN:
|
||||
return convert_to_QNaN(op);
|
||||
|
||||
case float_normalized:
|
||||
break;
|
||||
}
|
||||
|
||||
Bit32u fraction = float32_fraction(op);
|
||||
Bit16s exp = float32_exp(op);
|
||||
|
||||
/*
|
||||
* Calculate (1/1.yyyyyyyyyyy1), the result is always rounded to the
|
||||
* 12th bit after the decimal point by round-to-nearest, regardless
|
||||
* of the current rounding mode.
|
||||
*
|
||||
* Using precalculated 2048-entry table.
|
||||
*/
|
||||
|
||||
exp = 253 - exp;
|
||||
/* check for underflow */
|
||||
if (exp <= 0)
|
||||
return packFloat32(sign, 0x00, 0);
|
||||
|
||||
return packFloat32(sign, exp, (Bit32u)(rcp_table[fraction >> 12]) << 8);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Opcode: 0F 53
|
||||
* Approximate reciprocals of packed single precision FP values from XMM2/MEM.
|
||||
* Possible floating point exceptions: -
|
||||
*/
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCPPS_VpsWpsR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
op.xmm32u(0) = approximate_rcp(op.xmm32u(0));
|
||||
op.xmm32u(1) = approximate_rcp(op.xmm32u(1));
|
||||
op.xmm32u(2) = approximate_rcp(op.xmm32u(2));
|
||||
op.xmm32u(3) = approximate_rcp(op.xmm32u(3));
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Opcode: F3 0F 53
|
||||
* Approximate reciprocal of scalar single precision FP value from XMM2/MEM32.
|
||||
* Possible floating point exceptions: -
|
||||
*/
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RCPSS_VssWssR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
float32 op = BX_READ_XMM_REG_LO_DWORD(i->rm());
|
||||
op = approximate_rcp(op);
|
||||
BX_WRITE_XMM_REG_LO_DWORD(i->nnn(), op);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
|
||||
Bit16u rsqrt_table0[1024] =
|
||||
{
|
||||
0x34f8, 0x34e0, 0x34d0, 0x34b8, 0x34a0, 0x3488, 0x3470, 0x3460,
|
||||
0x3448, 0x3430, 0x3418, 0x3400, 0x33f0, 0x33d8, 0x33c0, 0x33a8,
|
||||
0x3398, 0x3380, 0x3368, 0x3350, 0x3338, 0x3328, 0x3310, 0x32f8,
|
||||
0x32e8, 0x32d0, 0x32b8, 0x32a0, 0x3290, 0x3278, 0x3260, 0x3250,
|
||||
0x3238, 0x3220, 0x3208, 0x31f8, 0x31e0, 0x31c8, 0x31b8, 0x31a0,
|
||||
0x3188, 0x3178, 0x3160, 0x3148, 0x3138, 0x3120, 0x3108, 0x30f8,
|
||||
0x30e0, 0x30c8, 0x30b8, 0x30a0, 0x3090, 0x3078, 0x3060, 0x3050,
|
||||
0x3038, 0x3028, 0x3010, 0x2ff8, 0x2fe8, 0x2fd0, 0x2fc0, 0x2fa8,
|
||||
0x2f90, 0x2f80, 0x2f68, 0x2f58, 0x2f40, 0x2f30, 0x2f18, 0x2f00,
|
||||
0x2ef0, 0x2ed8, 0x2ec8, 0x2eb0, 0x2ea0, 0x2e88, 0x2e78, 0x2e60,
|
||||
0x2e50, 0x2e38, 0x2e20, 0x2e10, 0x2df8, 0x2de8, 0x2dd0, 0x2dc0,
|
||||
0x2da8, 0x2d98, 0x2d80, 0x2d70, 0x2d58, 0x2d48, 0x2d38, 0x2d20,
|
||||
0x2d10, 0x2cf8, 0x2ce8, 0x2cd0, 0x2cc0, 0x2ca8, 0x2c98, 0x2c80,
|
||||
0x2c70, 0x2c58, 0x2c48, 0x2c38, 0x2c20, 0x2c10, 0x2bf8, 0x2be8,
|
||||
0x2bd0, 0x2bc0, 0x2bb0, 0x2b98, 0x2b88, 0x2b70, 0x2b60, 0x2b50,
|
||||
0x2b38, 0x2b28, 0x2b10, 0x2b00, 0x2af0, 0x2ad8, 0x2ac8, 0x2ab8,
|
||||
0x2aa0, 0x2a90, 0x2a78, 0x2a68, 0x2a58, 0x2a40, 0x2a30, 0x2a20,
|
||||
0x2a08, 0x29f8, 0x29e8, 0x29d0, 0x29c0, 0x29b0, 0x2998, 0x2988,
|
||||
0x2978, 0x2960, 0x2950, 0x2940, 0x2928, 0x2918, 0x2908, 0x28f0,
|
||||
0x28e0, 0x28d0, 0x28c0, 0x28a8, 0x2898, 0x2888, 0x2870, 0x2860,
|
||||
0x2850, 0x2840, 0x2828, 0x2818, 0x2808, 0x27f8, 0x27e0, 0x27d0,
|
||||
0x27c0, 0x27b0, 0x2798, 0x2788, 0x2778, 0x2768, 0x2750, 0x2740,
|
||||
0x2730, 0x2720, 0x2708, 0x26f8, 0x26e8, 0x26d8, 0x26c8, 0x26b0,
|
||||
0x26a0, 0x2690, 0x2680, 0x2670, 0x2658, 0x2648, 0x2638, 0x2628,
|
||||
0x2618, 0x2600, 0x25f0, 0x25e0, 0x25d0, 0x25c0, 0x25b0, 0x2598,
|
||||
0x2588, 0x2578, 0x2568, 0x2558, 0x2548, 0x2530, 0x2520, 0x2510,
|
||||
0x2500, 0x24f0, 0x24e0, 0x24d0, 0x24b8, 0x24a8, 0x2498, 0x2488,
|
||||
0x2478, 0x2468, 0x2458, 0x2448, 0x2430, 0x2420, 0x2410, 0x2400,
|
||||
0x23f0, 0x23e0, 0x23d0, 0x23c0, 0x23b0, 0x23a0, 0x2388, 0x2378,
|
||||
0x2368, 0x2358, 0x2348, 0x2338, 0x2328, 0x2318, 0x2308, 0x22f8,
|
||||
0x22e8, 0x22d8, 0x22c8, 0x22b8, 0x22a8, 0x2290, 0x2280, 0x2270,
|
||||
0x2260, 0x2250, 0x2240, 0x2230, 0x2220, 0x2210, 0x2200, 0x21f0,
|
||||
0x21e0, 0x21d0, 0x21c0, 0x21b0, 0x21a0, 0x2190, 0x2180, 0x2170,
|
||||
0x2160, 0x2150, 0x2140, 0x2130, 0x2120, 0x2110, 0x2100, 0x20f0,
|
||||
0x20e0, 0x20d0, 0x20c0, 0x20b0, 0x20a0, 0x2090, 0x2080, 0x2070,
|
||||
0x2060, 0x2050, 0x2040, 0x2030, 0x2020, 0x2010, 0x2000, 0x1ff0,
|
||||
0x1fe8, 0x1fd8, 0x1fc8, 0x1fb8, 0x1fa8, 0x1f98, 0x1f88, 0x1f78,
|
||||
0x1f68, 0x1f58, 0x1f48, 0x1f38, 0x1f28, 0x1f18, 0x1f08, 0x1f00,
|
||||
0x1ef0, 0x1ee0, 0x1ed0, 0x1ec0, 0x1eb0, 0x1ea0, 0x1e90, 0x1e80,
|
||||
0x1e70, 0x1e60, 0x1e58, 0x1e48, 0x1e38, 0x1e28, 0x1e18, 0x1e08,
|
||||
0x1df8, 0x1de8, 0x1de0, 0x1dd0, 0x1dc0, 0x1db0, 0x1da0, 0x1d90,
|
||||
0x1d80, 0x1d70, 0x1d68, 0x1d58, 0x1d48, 0x1d38, 0x1d28, 0x1d18,
|
||||
0x1d08, 0x1d00, 0x1cf0, 0x1ce0, 0x1cd0, 0x1cc0, 0x1cb0, 0x1ca8,
|
||||
0x1c98, 0x1c88, 0x1c78, 0x1c68, 0x1c58, 0x1c50, 0x1c40, 0x1c30,
|
||||
0x1c20, 0x1c10, 0x1c08, 0x1bf8, 0x1be8, 0x1bd8, 0x1bc8, 0x1bc0,
|
||||
0x1bb0, 0x1ba0, 0x1b90, 0x1b80, 0x1b78, 0x1b68, 0x1b58, 0x1b48,
|
||||
0x1b38, 0x1b30, 0x1b20, 0x1b10, 0x1b00, 0x1af0, 0x1ae8, 0x1ad8,
|
||||
0x1ac8, 0x1ab8, 0x1ab0, 0x1aa0, 0x1a90, 0x1a80, 0x1a78, 0x1a68,
|
||||
0x1a58, 0x1a48, 0x1a40, 0x1a30, 0x1a20, 0x1a10, 0x1a08, 0x19f8,
|
||||
0x19e8, 0x19d8, 0x19d0, 0x19c0, 0x19b0, 0x19a0, 0x1998, 0x1988,
|
||||
0x1978, 0x1970, 0x1960, 0x1950, 0x1940, 0x1938, 0x1928, 0x1918,
|
||||
0x1910, 0x1900, 0x18f0, 0x18e0, 0x18d8, 0x18c8, 0x18b8, 0x18b0,
|
||||
0x18a0, 0x1890, 0x1888, 0x1878, 0x1868, 0x1858, 0x1850, 0x1840,
|
||||
0x1830, 0x1828, 0x1818, 0x1808, 0x1800, 0x17f0, 0x17e0, 0x17d8,
|
||||
0x17c8, 0x17b8, 0x17b0, 0x17a0, 0x1790, 0x1788, 0x1778, 0x1768,
|
||||
0x1760, 0x1750, 0x1740, 0x1738, 0x1728, 0x1718, 0x1710, 0x1700,
|
||||
0x16f8, 0x16e8, 0x16d8, 0x16d0, 0x16c0, 0x16b0, 0x16a8, 0x1698,
|
||||
0x1688, 0x1680, 0x1670, 0x1668, 0x1658, 0x1648, 0x1640, 0x1630,
|
||||
0x1628, 0x1618, 0x1608, 0x1600, 0x15f0, 0x15e0, 0x15d8, 0x15c8,
|
||||
0x15c0, 0x15b0, 0x15a0, 0x1598, 0x1588, 0x1580, 0x1570, 0x1560,
|
||||
0x1558, 0x1548, 0x1540, 0x1530, 0x1528, 0x1518, 0x1508, 0x1500,
|
||||
0x14f0, 0x14e8, 0x14d8, 0x14d0, 0x14c0, 0x14b0, 0x14a8, 0x1498,
|
||||
0x1490, 0x1480, 0x1478, 0x1468, 0x1458, 0x1450, 0x1440, 0x1438,
|
||||
0x1428, 0x1420, 0x1410, 0x1408, 0x13f8, 0x13f0, 0x13e0, 0x13d0,
|
||||
0x13c8, 0x13b8, 0x13b0, 0x13a0, 0x1398, 0x1388, 0x1380, 0x1370,
|
||||
0x1368, 0x1358, 0x1350, 0x1340, 0x1338, 0x1328, 0x1318, 0x1310,
|
||||
0x1300, 0x12f8, 0x12e8, 0x12e0, 0x12d0, 0x12c8, 0x12b8, 0x12b0,
|
||||
0x12a0, 0x1298, 0x1288, 0x1280, 0x1270, 0x1268, 0x1258, 0x1250,
|
||||
0x1240, 0x1238, 0x1228, 0x1220, 0x1210, 0x1208, 0x11f8, 0x11f0,
|
||||
0x11e8, 0x11d8, 0x11d0, 0x11c0, 0x11b8, 0x11a8, 0x11a0, 0x1190,
|
||||
0x1188, 0x1178, 0x1170, 0x1160, 0x1158, 0x1148, 0x1140, 0x1130,
|
||||
0x1128, 0x1120, 0x1110, 0x1108, 0x10f8, 0x10f0, 0x10e0, 0x10d8,
|
||||
0x10c8, 0x10c0, 0x10b0, 0x10a8, 0x10a0, 0x1090, 0x1088, 0x1078,
|
||||
0x1070, 0x1060, 0x1058, 0x1050, 0x1040, 0x1038, 0x1028, 0x1020,
|
||||
0x1010, 0x1008, 0x1000, 0x0ff0, 0x0fe8, 0x0fd8, 0x0fd0, 0x0fc0,
|
||||
0x0fb8, 0x0fb0, 0x0fa0, 0x0f98, 0x0f88, 0x0f80, 0x0f78, 0x0f68,
|
||||
0x0f60, 0x0f50, 0x0f48, 0x0f40, 0x0f30, 0x0f28, 0x0f18, 0x0f10,
|
||||
0x0f08, 0x0ef8, 0x0ef0, 0x0ee0, 0x0ed8, 0x0ed0, 0x0ec0, 0x0eb8,
|
||||
0x0ea8, 0x0ea0, 0x0e98, 0x0e88, 0x0e80, 0x0e78, 0x0e68, 0x0e60,
|
||||
0x0e50, 0x0e48, 0x0e40, 0x0e30, 0x0e28, 0x0e20, 0x0e10, 0x0e08,
|
||||
0x0df8, 0x0df0, 0x0de8, 0x0dd8, 0x0dd0, 0x0dc8, 0x0db8, 0x0db0,
|
||||
0x0da8, 0x0d98, 0x0d90, 0x0d80, 0x0d78, 0x0d70, 0x0d60, 0x0d58,
|
||||
0x0d50, 0x0d40, 0x0d38, 0x0d30, 0x0d20, 0x0d18, 0x0d10, 0x0d00,
|
||||
0x0cf8, 0x0cf0, 0x0ce0, 0x0cd8, 0x0cd0, 0x0cc0, 0x0cb8, 0x0cb0,
|
||||
0x0ca0, 0x0c98, 0x0c90, 0x0c80, 0x0c78, 0x0c70, 0x0c60, 0x0c58,
|
||||
0x0c50, 0x0c40, 0x0c38, 0x0c30, 0x0c28, 0x0c18, 0x0c10, 0x0c08,
|
||||
0x0bf8, 0x0bf0, 0x0be8, 0x0bd8, 0x0bd0, 0x0bc8, 0x0bb8, 0x0bb0,
|
||||
0x0ba8, 0x0ba0, 0x0b90, 0x0b88, 0x0b80, 0x0b70, 0x0b68, 0x0b60,
|
||||
0x0b58, 0x0b48, 0x0b40, 0x0b38, 0x0b28, 0x0b20, 0x0b18, 0x0b10,
|
||||
0x0b00, 0x0af8, 0x0af0, 0x0ae0, 0x0ad8, 0x0ad0, 0x0ac8, 0x0ab8,
|
||||
0x0ab0, 0x0aa8, 0x0a98, 0x0a90, 0x0a88, 0x0a80, 0x0a70, 0x0a68,
|
||||
0x0a60, 0x0a58, 0x0a48, 0x0a40, 0x0a38, 0x0a30, 0x0a20, 0x0a18,
|
||||
0x0a10, 0x0a08, 0x09f8, 0x09f0, 0x09e8, 0x09e0, 0x09d0, 0x09c8,
|
||||
0x09c0, 0x09b8, 0x09a8, 0x09a0, 0x0998, 0x0990, 0x0980, 0x0978,
|
||||
0x0970, 0x0968, 0x0958, 0x0950, 0x0948, 0x0940, 0x0930, 0x0928,
|
||||
0x0920, 0x0918, 0x0910, 0x0900, 0x08f8, 0x08f0, 0x08e8, 0x08d8,
|
||||
0x08d0, 0x08c8, 0x08c0, 0x08b8, 0x08a8, 0x08a0, 0x0898, 0x0890,
|
||||
0x0880, 0x0878, 0x0870, 0x0868, 0x0860, 0x0850, 0x0848, 0x0840,
|
||||
0x0838, 0x0830, 0x0820, 0x0818, 0x0810, 0x0808, 0x0800, 0x07f0,
|
||||
0x07e8, 0x07e0, 0x07d8, 0x07d0, 0x07c0, 0x07b8, 0x07b0, 0x07a8,
|
||||
0x07a0, 0x0790, 0x0788, 0x0780, 0x0778, 0x0770, 0x0768, 0x0758,
|
||||
0x0750, 0x0748, 0x0740, 0x0738, 0x0728, 0x0720, 0x0718, 0x0710,
|
||||
0x0708, 0x0700, 0x06f0, 0x06e8, 0x06e0, 0x06d8, 0x06d0, 0x06c8,
|
||||
0x06b8, 0x06b0, 0x06a8, 0x06a0, 0x0698, 0x0690, 0x0680, 0x0678,
|
||||
0x0670, 0x0668, 0x0660, 0x0658, 0x0648, 0x0640, 0x0638, 0x0630,
|
||||
0x0628, 0x0620, 0x0618, 0x0608, 0x0600, 0x05f8, 0x05f0, 0x05e8,
|
||||
0x05e0, 0x05d8, 0x05c8, 0x05c0, 0x05b8, 0x05b0, 0x05a8, 0x05a0,
|
||||
0x0598, 0x0588, 0x0580, 0x0578, 0x0570, 0x0568, 0x0560, 0x0558,
|
||||
0x0548, 0x0540, 0x0538, 0x0530, 0x0528, 0x0520, 0x0518, 0x0510,
|
||||
0x0500, 0x04f8, 0x04f0, 0x04e8, 0x04e0, 0x04d8, 0x04d0, 0x04c8,
|
||||
0x04c0, 0x04b0, 0x04a8, 0x04a0, 0x0498, 0x0490, 0x0488, 0x0480,
|
||||
0x0478, 0x0470, 0x0460, 0x0458, 0x0450, 0x0448, 0x0440, 0x0438,
|
||||
0x0430, 0x0428, 0x0420, 0x0410, 0x0408, 0x0400, 0x03f8, 0x03f0,
|
||||
0x03e8, 0x03e0, 0x03d8, 0x03d0, 0x03c8, 0x03c0, 0x03b0, 0x03a8,
|
||||
0x03a0, 0x0398, 0x0390, 0x0388, 0x0380, 0x0378, 0x0370, 0x0368,
|
||||
0x0360, 0x0358, 0x0348, 0x0340, 0x0338, 0x0330, 0x0328, 0x0320,
|
||||
0x0318, 0x0310, 0x0308, 0x0300, 0x02f8, 0x02f0, 0x02e8, 0x02d8,
|
||||
0x02d0, 0x02c8, 0x02c0, 0x02b8, 0x02b0, 0x02a8, 0x02a0, 0x0298,
|
||||
0x0290, 0x0288, 0x0280, 0x0278, 0x0270, 0x0268, 0x0260, 0x0250,
|
||||
0x0248, 0x0240, 0x0238, 0x0230, 0x0228, 0x0220, 0x0218, 0x0210,
|
||||
0x0208, 0x0200, 0x01f8, 0x01f0, 0x01e8, 0x01e0, 0x01d8, 0x01d0,
|
||||
0x01c8, 0x01c0, 0x01b8, 0x01b0, 0x01a0, 0x0198, 0x0190, 0x0188,
|
||||
0x0180, 0x0178, 0x0170, 0x0168, 0x0160, 0x0158, 0x0150, 0x0148,
|
||||
0x0140, 0x0138, 0x0130, 0x0128, 0x0120, 0x0118, 0x0110, 0x0108,
|
||||
0x0100, 0x00f8, 0x00f0, 0x00e8, 0x00e0, 0x00d8, 0x00d0, 0x00c8,
|
||||
0x00c0, 0x00b8, 0x00b0, 0x00a8, 0x00a0, 0x0098, 0x0090, 0x0088,
|
||||
0x0080, 0x0078, 0x0070, 0x0068, 0x0060, 0x0058, 0x0050, 0x0048,
|
||||
0x0040, 0x0038, 0x0030, 0x0028, 0x0020, 0x0018, 0x0010, 0x0008
|
||||
};
|
||||
|
||||
Bit16u rsqrt_table1[1024] =
|
||||
{
|
||||
0x7ff0, 0x7fd0, 0x7fb0, 0x7f90, 0x7f70, 0x7f50, 0x7f30, 0x7f10,
|
||||
0x7ef0, 0x7ed0, 0x7eb0, 0x7e90, 0x7e70, 0x7e58, 0x7e38, 0x7e18,
|
||||
0x7df8, 0x7dd8, 0x7db8, 0x7d98, 0x7d78, 0x7d58, 0x7d38, 0x7d20,
|
||||
0x7d00, 0x7ce0, 0x7cc0, 0x7ca0, 0x7c80, 0x7c60, 0x7c48, 0x7c28,
|
||||
0x7c08, 0x7be8, 0x7bc8, 0x7bb0, 0x7b90, 0x7b70, 0x7b50, 0x7b30,
|
||||
0x7b18, 0x7af8, 0x7ad8, 0x7ab8, 0x7aa0, 0x7a80, 0x7a60, 0x7a40,
|
||||
0x7a28, 0x7a08, 0x79e8, 0x79c8, 0x79b0, 0x7990, 0x7970, 0x7958,
|
||||
0x7938, 0x7918, 0x7900, 0x78e0, 0x78c0, 0x78a8, 0x7888, 0x7868,
|
||||
0x7850, 0x7830, 0x7810, 0x77f8, 0x77d8, 0x77b8, 0x77a0, 0x7780,
|
||||
0x7768, 0x7748, 0x7728, 0x7710, 0x76f0, 0x76d8, 0x76b8, 0x7698,
|
||||
0x7680, 0x7660, 0x7648, 0x7628, 0x7610, 0x75f0, 0x75d0, 0x75b8,
|
||||
0x7598, 0x7580, 0x7560, 0x7548, 0x7528, 0x7510, 0x74f0, 0x74d8,
|
||||
0x74b8, 0x74a0, 0x7480, 0x7468, 0x7448, 0x7430, 0x7410, 0x73f8,
|
||||
0x73d8, 0x73c0, 0x73a8, 0x7388, 0x7370, 0x7350, 0x7338, 0x7318,
|
||||
0x7300, 0x72e8, 0x72c8, 0x72b0, 0x7290, 0x7278, 0x7260, 0x7240,
|
||||
0x7228, 0x7208, 0x71f0, 0x71d8, 0x71b8, 0x71a0, 0x7188, 0x7168,
|
||||
0x7150, 0x7130, 0x7118, 0x7100, 0x70e0, 0x70c8, 0x70b0, 0x7090,
|
||||
0x7078, 0x7060, 0x7048, 0x7028, 0x7010, 0x6ff8, 0x6fd8, 0x6fc0,
|
||||
0x6fa8, 0x6f88, 0x6f70, 0x6f58, 0x6f40, 0x6f20, 0x6f08, 0x6ef0,
|
||||
0x6ed8, 0x6eb8, 0x6ea0, 0x6e88, 0x6e70, 0x6e50, 0x6e38, 0x6e20,
|
||||
0x6e08, 0x6df0, 0x6dd0, 0x6db8, 0x6da0, 0x6d88, 0x6d70, 0x6d50,
|
||||
0x6d38, 0x6d20, 0x6d08, 0x6cf0, 0x6cd8, 0x6cb8, 0x6ca0, 0x6c88,
|
||||
0x6c70, 0x6c58, 0x6c40, 0x6c20, 0x6c08, 0x6bf0, 0x6bd8, 0x6bc0,
|
||||
0x6ba8, 0x6b90, 0x6b78, 0x6b58, 0x6b40, 0x6b28, 0x6b10, 0x6af8,
|
||||
0x6ae0, 0x6ac8, 0x6ab0, 0x6a98, 0x6a80, 0x6a68, 0x6a48, 0x6a30,
|
||||
0x6a18, 0x6a00, 0x69e8, 0x69d0, 0x69b8, 0x69a0, 0x6988, 0x6970,
|
||||
0x6958, 0x6940, 0x6928, 0x6910, 0x68f8, 0x68e0, 0x68c8, 0x68b0,
|
||||
0x6898, 0x6880, 0x6868, 0x6850, 0x6838, 0x6820, 0x6808, 0x67f0,
|
||||
0x67d8, 0x67c0, 0x67a8, 0x6790, 0x6778, 0x6760, 0x6748, 0x6730,
|
||||
0x6718, 0x6700, 0x66e8, 0x66d8, 0x66c0, 0x66a8, 0x6690, 0x6678,
|
||||
0x6660, 0x6648, 0x6630, 0x6618, 0x6600, 0x65e8, 0x65d0, 0x65c0,
|
||||
0x65a8, 0x6590, 0x6578, 0x6560, 0x6548, 0x6530, 0x6518, 0x6508,
|
||||
0x64f0, 0x64d8, 0x64c0, 0x64a8, 0x6490, 0x6478, 0x6468, 0x6450,
|
||||
0x6438, 0x6420, 0x6408, 0x63f0, 0x63e0, 0x63c8, 0x63b0, 0x6398,
|
||||
0x6380, 0x6370, 0x6358, 0x6340, 0x6328, 0x6310, 0x6300, 0x62e8,
|
||||
0x62d0, 0x62b8, 0x62a0, 0x6290, 0x6278, 0x6260, 0x6248, 0x6238,
|
||||
0x6220, 0x6208, 0x61f0, 0x61e0, 0x61c8, 0x61b0, 0x6198, 0x6188,
|
||||
0x6170, 0x6158, 0x6140, 0x6130, 0x6118, 0x6100, 0x60f0, 0x60d8,
|
||||
0x60c0, 0x60a8, 0x6098, 0x6080, 0x6068, 0x6058, 0x6040, 0x6028,
|
||||
0x6018, 0x6000, 0x5fe8, 0x5fd8, 0x5fc0, 0x5fa8, 0x5f98, 0x5f80,
|
||||
0x5f68, 0x5f58, 0x5f40, 0x5f28, 0x5f18, 0x5f00, 0x5ee8, 0x5ed8,
|
||||
0x5ec0, 0x5ea8, 0x5e98, 0x5e80, 0x5e70, 0x5e58, 0x5e40, 0x5e30,
|
||||
0x5e18, 0x5e00, 0x5df0, 0x5dd8, 0x5dc8, 0x5db0, 0x5d98, 0x5d88,
|
||||
0x5d70, 0x5d60, 0x5d48, 0x5d38, 0x5d20, 0x5d08, 0x5cf8, 0x5ce0,
|
||||
0x5cd0, 0x5cb8, 0x5ca8, 0x5c90, 0x5c78, 0x5c68, 0x5c50, 0x5c40,
|
||||
0x5c28, 0x5c18, 0x5c00, 0x5bf0, 0x5bd8, 0x5bc8, 0x5bb0, 0x5b98,
|
||||
0x5b88, 0x5b70, 0x5b60, 0x5b48, 0x5b38, 0x5b20, 0x5b10, 0x5af8,
|
||||
0x5ae8, 0x5ad0, 0x5ac0, 0x5aa8, 0x5a98, 0x5a80, 0x5a70, 0x5a58,
|
||||
0x5a48, 0x5a30, 0x5a20, 0x5a08, 0x59f8, 0x59e8, 0x59d0, 0x59c0,
|
||||
0x59a8, 0x5998, 0x5980, 0x5970, 0x5958, 0x5948, 0x5930, 0x5920,
|
||||
0x5910, 0x58f8, 0x58e8, 0x58d0, 0x58c0, 0x58a8, 0x5898, 0x5888,
|
||||
0x5870, 0x5860, 0x5848, 0x5838, 0x5828, 0x5810, 0x5800, 0x57e8,
|
||||
0x57d8, 0x57c8, 0x57b0, 0x57a0, 0x5788, 0x5778, 0x5768, 0x5750,
|
||||
0x5740, 0x5728, 0x5718, 0x5708, 0x56f0, 0x56e0, 0x56d0, 0x56b8,
|
||||
0x56a8, 0x5698, 0x5680, 0x5670, 0x5658, 0x5648, 0x5638, 0x5620,
|
||||
0x5610, 0x5600, 0x55e8, 0x55d8, 0x55c8, 0x55b0, 0x55a0, 0x5590,
|
||||
0x5578, 0x5568, 0x5558, 0x5540, 0x5530, 0x5520, 0x5510, 0x54f8,
|
||||
0x54e8, 0x54d8, 0x54c0, 0x54b0, 0x54a0, 0x5488, 0x5478, 0x5468,
|
||||
0x5458, 0x5440, 0x5430, 0x5420, 0x5410, 0x53f8, 0x53e8, 0x53d8,
|
||||
0x53c0, 0x53b0, 0x53a0, 0x5390, 0x5378, 0x5368, 0x5358, 0x5348,
|
||||
0x5330, 0x5320, 0x5310, 0x5300, 0x52e8, 0x52d8, 0x52c8, 0x52b8,
|
||||
0x52a8, 0x5290, 0x5280, 0x5270, 0x5260, 0x5248, 0x5238, 0x5228,
|
||||
0x5218, 0x5208, 0x51f0, 0x51e0, 0x51d0, 0x51c0, 0x51b0, 0x5198,
|
||||
0x5188, 0x5178, 0x5168, 0x5158, 0x5140, 0x5130, 0x5120, 0x5110,
|
||||
0x5100, 0x50e8, 0x50d8, 0x50c8, 0x50b8, 0x50a8, 0x5098, 0x5080,
|
||||
0x5070, 0x5060, 0x5050, 0x5040, 0x5030, 0x5020, 0x5008, 0x4ff8,
|
||||
0x4fe8, 0x4fd8, 0x4fc8, 0x4fb8, 0x4fa8, 0x4f90, 0x4f80, 0x4f70,
|
||||
0x4f60, 0x4f50, 0x4f40, 0x4f30, 0x4f20, 0x4f08, 0x4ef8, 0x4ee8,
|
||||
0x4ed8, 0x4ec8, 0x4eb8, 0x4ea8, 0x4e98, 0x4e88, 0x4e70, 0x4e60,
|
||||
0x4e50, 0x4e40, 0x4e30, 0x4e20, 0x4e10, 0x4e00, 0x4df0, 0x4de0,
|
||||
0x4dd0, 0x4db8, 0x4da8, 0x4d98, 0x4d88, 0x4d78, 0x4d68, 0x4d58,
|
||||
0x4d48, 0x4d38, 0x4d28, 0x4d18, 0x4d08, 0x4cf8, 0x4ce8, 0x4cd8,
|
||||
0x4cc8, 0x4cb8, 0x4ca0, 0x4c90, 0x4c80, 0x4c70, 0x4c60, 0x4c50,
|
||||
0x4c40, 0x4c30, 0x4c20, 0x4c10, 0x4c00, 0x4bf0, 0x4be0, 0x4bd0,
|
||||
0x4bc0, 0x4bb0, 0x4ba0, 0x4b90, 0x4b80, 0x4b70, 0x4b60, 0x4b50,
|
||||
0x4b40, 0x4b30, 0x4b20, 0x4b10, 0x4b00, 0x4af0, 0x4ae0, 0x4ad0,
|
||||
0x4ac0, 0x4ab0, 0x4aa0, 0x4a90, 0x4a80, 0x4a70, 0x4a60, 0x4a50,
|
||||
0x4a40, 0x4a30, 0x4a20, 0x4a10, 0x4a00, 0x49f0, 0x49e0, 0x49d0,
|
||||
0x49c0, 0x49b8, 0x49a8, 0x4998, 0x4988, 0x4978, 0x4968, 0x4958,
|
||||
0x4948, 0x4938, 0x4928, 0x4918, 0x4908, 0x48f8, 0x48e8, 0x48d8,
|
||||
0x48c8, 0x48b8, 0x48b0, 0x48a0, 0x4890, 0x4880, 0x4870, 0x4860,
|
||||
0x4850, 0x4840, 0x4830, 0x4820, 0x4810, 0x4800, 0x47f8, 0x47e8,
|
||||
0x47d8, 0x47c8, 0x47b8, 0x47a8, 0x4798, 0x4788, 0x4778, 0x4768,
|
||||
0x4760, 0x4750, 0x4740, 0x4730, 0x4720, 0x4710, 0x4700, 0x46f0,
|
||||
0x46e0, 0x46d8, 0x46c8, 0x46b8, 0x46a8, 0x4698, 0x4688, 0x4678,
|
||||
0x4670, 0x4660, 0x4650, 0x4640, 0x4630, 0x4620, 0x4610, 0x4608,
|
||||
0x45f8, 0x45e8, 0x45d8, 0x45c8, 0x45b8, 0x45a8, 0x45a0, 0x4590,
|
||||
0x4580, 0x4570, 0x4560, 0x4550, 0x4548, 0x4538, 0x4528, 0x4518,
|
||||
0x4508, 0x44f8, 0x44f0, 0x44e0, 0x44d0, 0x44c0, 0x44b0, 0x44a8,
|
||||
0x4498, 0x4488, 0x4478, 0x4468, 0x4460, 0x4450, 0x4440, 0x4430,
|
||||
0x4420, 0x4418, 0x4408, 0x43f8, 0x43e8, 0x43d8, 0x43d0, 0x43c0,
|
||||
0x43b0, 0x43a0, 0x4390, 0x4388, 0x4378, 0x4368, 0x4358, 0x4350,
|
||||
0x4340, 0x4330, 0x4320, 0x4310, 0x4308, 0x42f8, 0x42e8, 0x42d8,
|
||||
0x42d0, 0x42c0, 0x42b0, 0x42a0, 0x4298, 0x4288, 0x4278, 0x4268,
|
||||
0x4260, 0x4250, 0x4240, 0x4230, 0x4228, 0x4218, 0x4208, 0x41f8,
|
||||
0x41f0, 0x41e0, 0x41d0, 0x41c0, 0x41b8, 0x41a8, 0x4198, 0x4188,
|
||||
0x4180, 0x4170, 0x4160, 0x4158, 0x4148, 0x4138, 0x4128, 0x4120,
|
||||
0x4110, 0x4100, 0x40f8, 0x40e8, 0x40d8, 0x40c8, 0x40c0, 0x40b0,
|
||||
0x40a0, 0x4098, 0x4088, 0x4078, 0x4068, 0x4060, 0x4050, 0x4040,
|
||||
0x4038, 0x4028, 0x4018, 0x4010, 0x4000, 0x3ff0, 0x3fe8, 0x3fd8,
|
||||
0x3fc8, 0x3fb8, 0x3fb0, 0x3fa0, 0x3f90, 0x3f88, 0x3f78, 0x3f68,
|
||||
0x3f60, 0x3f50, 0x3f40, 0x3f38, 0x3f28, 0x3f18, 0x3f10, 0x3f00,
|
||||
0x3ef0, 0x3ee8, 0x3ed8, 0x3ec8, 0x3ec0, 0x3eb0, 0x3ea0, 0x3e98,
|
||||
0x3e88, 0x3e80, 0x3e70, 0x3e60, 0x3e58, 0x3e48, 0x3e38, 0x3e30,
|
||||
0x3e20, 0x3e10, 0x3e08, 0x3df8, 0x3df0, 0x3de0, 0x3dd0, 0x3dc8,
|
||||
0x3db8, 0x3da8, 0x3da0, 0x3d90, 0x3d80, 0x3d78, 0x3d68, 0x3d60,
|
||||
0x3d50, 0x3d40, 0x3d38, 0x3d28, 0x3d20, 0x3d10, 0x3d00, 0x3cf8,
|
||||
0x3ce8, 0x3cd8, 0x3cd0, 0x3cc0, 0x3cb8, 0x3ca8, 0x3c98, 0x3c90,
|
||||
0x3c80, 0x3c78, 0x3c68, 0x3c58, 0x3c50, 0x3c40, 0x3c38, 0x3c28,
|
||||
0x3c20, 0x3c10, 0x3c00, 0x3bf8, 0x3be8, 0x3be0, 0x3bd0, 0x3bc0,
|
||||
0x3bb8, 0x3ba8, 0x3ba0, 0x3b90, 0x3b88, 0x3b78, 0x3b68, 0x3b60,
|
||||
0x3b50, 0x3b48, 0x3b38, 0x3b30, 0x3b20, 0x3b10, 0x3b08, 0x3af8,
|
||||
0x3af0, 0x3ae0, 0x3ad8, 0x3ac8, 0x3ac0, 0x3ab0, 0x3aa0, 0x3a98,
|
||||
0x3a88, 0x3a80, 0x3a70, 0x3a68, 0x3a58, 0x3a50, 0x3a40, 0x3a38,
|
||||
0x3a28, 0x3a20, 0x3a10, 0x3a00, 0x39f8, 0x39e8, 0x39e0, 0x39d0,
|
||||
0x39c8, 0x39b8, 0x39b0, 0x39a0, 0x3998, 0x3988, 0x3980, 0x3970,
|
||||
0x3968, 0x3958, 0x3950, 0x3940, 0x3938, 0x3928, 0x3918, 0x3910,
|
||||
0x3900, 0x38f8, 0x38e8, 0x38e0, 0x38d0, 0x38c8, 0x38b8, 0x38b0,
|
||||
0x38a0, 0x3898, 0x3888, 0x3880, 0x3870, 0x3868, 0x3858, 0x3850,
|
||||
0x3840, 0x3838, 0x3828, 0x3820, 0x3818, 0x3808, 0x3800, 0x37f0,
|
||||
0x37e8, 0x37d8, 0x37d0, 0x37c0, 0x37b8, 0x37a8, 0x37a0, 0x3790,
|
||||
0x3788, 0x3778, 0x3770, 0x3760, 0x3758, 0x3748, 0x3740, 0x3730,
|
||||
0x3728, 0x3720, 0x3710, 0x3708, 0x36f8, 0x36f0, 0x36e0, 0x36d8,
|
||||
0x36c8, 0x36c0, 0x36b0, 0x36a8, 0x3698, 0x3690, 0x3688, 0x3678,
|
||||
0x3670, 0x3660, 0x3658, 0x3648, 0x3640, 0x3630, 0x3628, 0x3620,
|
||||
0x3610, 0x3608, 0x35f8, 0x35f0, 0x35e0, 0x35d8, 0x35d0, 0x35c0,
|
||||
0x35b8, 0x35a8, 0x35a0, 0x3590, 0x3588, 0x3580, 0x3570, 0x3568,
|
||||
0x3558, 0x3550, 0x3540, 0x3538, 0x3530, 0x3520, 0x3518, 0x3508
|
||||
};
|
||||
|
||||
|
||||
// approximate reciprocal sqrt of scalar single precision FP
|
||||
static float32 approximate_rsqrt(float32 op)
|
||||
{
|
||||
float_class_t op_class = float32_class(op);
|
||||
|
||||
int sign = float32_sign(op);
|
||||
|
||||
switch(op_class)
|
||||
{
|
||||
case float_zero:
|
||||
case float_denormal:
|
||||
return packFloat32(sign, 0xFF, 0);
|
||||
|
||||
case float_positive_inf:
|
||||
return 0;
|
||||
|
||||
case float_negative_inf:
|
||||
return float32_default_nan;
|
||||
|
||||
case float_NaN:
|
||||
return convert_to_QNaN(op);
|
||||
|
||||
case float_normalized:
|
||||
break;
|
||||
};
|
||||
|
||||
if (sign == 1)
|
||||
return float32_default_nan;
|
||||
|
||||
Bit32u fraction = float32_fraction(op);
|
||||
Bit16s exp = float32_exp(op);
|
||||
|
||||
/*
|
||||
* Calculate (1/1.yyyyyyyyyy1), the result is always rounded to the
|
||||
* 11th bit after the decimal point by round-to-nearest, regardless
|
||||
* of the current rounding mode.
|
||||
*
|
||||
* Using two precalculated 1024-entry tables.
|
||||
*/
|
||||
|
||||
Bit16u *rsqrt_table = (exp & 1) ? rsqrt_table1 : rsqrt_table0;
|
||||
|
||||
exp = 126 - ((exp - 127) >> 1);
|
||||
/* check for underflow */
|
||||
if (exp <= 0)
|
||||
return packFloat32(sign, 0x00, 0);
|
||||
|
||||
return packFloat32(sign, exp, (Bit32u)(rsqrt_table[fraction >> 13]) << 8);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Opcode: F3 0F 52
|
||||
* Approximate reciprocal of square root of scalar single precision FP value
|
||||
* from XMM2/MEM32.
|
||||
* Possible floating point exceptions: -
|
||||
*/
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RSQRTSS_VssWssR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
float32 op = BX_READ_XMM_REG_LO_DWORD(i->rm());
|
||||
op = approximate_rsqrt(op);
|
||||
BX_WRITE_XMM_REG_LO_DWORD(i->nnn(), op);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Opcode: 0F 52
|
||||
* Approximate reciprocal of square root of packed single precision FP values
|
||||
* from XMM2/MEM.
|
||||
* Possible floating point exceptions: -
|
||||
*/
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::RSQRTPS_VpsWpsR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op = BX_READ_XMM_REG(i->rm());
|
||||
|
||||
op.xmm32u(0) = approximate_rsqrt(op.xmm32u(0));
|
||||
op.xmm32u(1) = approximate_rsqrt(op.xmm32u(1));
|
||||
op.xmm32u(2) = approximate_rsqrt(op.xmm32u(2));
|
||||
op.xmm32u(3) = approximate_rsqrt(op.xmm32u(3));
|
||||
|
||||
BX_WRITE_XMM_REG(i->nnn(), op);
|
||||
#endif
|
||||
}
|
||||
485
simulators/bochs/cpu/sse_string.cc
Executable file
485
simulators/bochs/cpu/sse_string.cc
Executable file
@ -0,0 +1,485 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RCX ECX
|
||||
#endif
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
|
||||
// Compare all pairs of Ai, Bj according to imm8 control
|
||||
static void compare_strings(Bit8u BoolRes[16][16], BxPackedXmmRegister op1, BxPackedXmmRegister op2, Bit8u imm)
|
||||
{
|
||||
unsigned i, j;
|
||||
unsigned aggregation_operation = (imm >> 2) & 3;
|
||||
|
||||
// All possible comparisons are performed, the individual boolean
|
||||
// results of those comparisons are referred by
|
||||
// BoolRes[op2 element index, op1 element index]
|
||||
|
||||
switch (imm & 3) {
|
||||
case 0: /* unsigned bytes compare */
|
||||
for (i=0;i<16;i++) {
|
||||
for (j=0;j<16;j++) {
|
||||
switch (aggregation_operation) {
|
||||
case 0: /* 'equal' comparison */
|
||||
case 2:
|
||||
case 3:
|
||||
BoolRes[j][i] = (op1.xmmubyte(i) == op2.xmmubyte(j));
|
||||
break;
|
||||
case 1: /* 'ranges' comparison */
|
||||
if ((i % 2) == 0)
|
||||
BoolRes[j][i] = (op1.xmmubyte(i) <= op2.xmmubyte(j));
|
||||
else
|
||||
BoolRes[j][i] = (op1.xmmubyte(i) >= op2.xmmubyte(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: /* unsigned words compare */
|
||||
for (i=0;i<8;i++) {
|
||||
for (j=0;j<8;j++) {
|
||||
switch (aggregation_operation) {
|
||||
case 0: /* 'equal' comparison */
|
||||
case 2:
|
||||
case 3:
|
||||
BoolRes[j][i] = (op1.xmm16u(i) == op2.xmm16u(j));
|
||||
break;
|
||||
case 1: /* 'ranges' comparison */
|
||||
if ((i % 2) == 0)
|
||||
BoolRes[j][i] = (op1.xmm16u(i) <= op2.xmm16u(j));
|
||||
else
|
||||
BoolRes[j][i] = (op1.xmm16u(i) >= op2.xmm16u(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* signed bytes compare */
|
||||
for (i=0;i<16;i++) {
|
||||
for (j=0;j<16;j++) {
|
||||
switch (aggregation_operation) {
|
||||
case 0: /* 'equal' comparison */
|
||||
case 2:
|
||||
case 3:
|
||||
BoolRes[j][i] = (op1.xmmsbyte(i) == op2.xmmsbyte(j));
|
||||
break;
|
||||
case 1: /* 'ranges' comparison */
|
||||
if ((i % 2) == 0)
|
||||
BoolRes[j][i] = (op1.xmmsbyte(i) <= op2.xmmsbyte(j));
|
||||
else
|
||||
BoolRes[j][i] = (op1.xmmsbyte(i) >= op2.xmmsbyte(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: /* signed words compare */
|
||||
for (i=0;i<8;i++) {
|
||||
for (j=0;j<8;j++) {
|
||||
switch (aggregation_operation) {
|
||||
case 0: /* 'equal' comparison */
|
||||
case 2:
|
||||
case 3:
|
||||
BoolRes[j][i] = (op1.xmm16s(i) == op2.xmm16s(j));
|
||||
break;
|
||||
case 1: /* 'ranges' comparison */
|
||||
if ((i % 2) == 0)
|
||||
BoolRes[j][i] = (op1.xmm16s(i) <= op2.xmm16s(j));
|
||||
else
|
||||
BoolRes[j][i] = (op1.xmm16s(i) >= op2.xmm16s(j));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned find_eos32(Bit32s reg32, Bit8u imm)
|
||||
{
|
||||
if (imm & 0x1) { // 8 elements
|
||||
if (reg32 > 8 || reg32 < -8) return 8;
|
||||
else return abs(reg32);
|
||||
}
|
||||
else { // 16 elements
|
||||
if (reg32 > 16 || reg32 < -16) return 16;
|
||||
else return abs(reg32);
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
static unsigned find_eos64(Bit64s reg64, Bit8u imm)
|
||||
{
|
||||
if (imm & 0x1) { // 8 elements
|
||||
if (reg64 > 8 || reg64 < -8) return 8;
|
||||
else return (unsigned) abs(reg64);
|
||||
}
|
||||
else { // 16 elements
|
||||
if (reg64 > 16 || reg64 < -16) return 16;
|
||||
else return (unsigned) abs(reg64);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned find_eos(BxPackedXmmRegister op, Bit8u imm)
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
if (imm & 0x1) { // 8 elements
|
||||
for(i=0;i<8;i++)
|
||||
if (op.xmm16u(i) == 0) break;
|
||||
}
|
||||
else { // 16 elements
|
||||
for(i=0;i<16;i++)
|
||||
if (op.xmmubyte(i) == 0) break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static bx_bool override_if_data_invalid(bx_bool val, bx_bool i_valid, bx_bool j_valid, Bit8u imm)
|
||||
{
|
||||
unsigned aggregation_operation = (imm >> 2) & 3;
|
||||
|
||||
switch(aggregation_operation) {
|
||||
case 0: // 'equal any'
|
||||
case 1: // 'ranges'
|
||||
if (! i_valid || ! j_valid) // one of the elements is invalid
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case 2: // 'equal each'
|
||||
if (! i_valid) {
|
||||
if (! j_valid) return 1; // both elements are invalid
|
||||
else return 0; // only i is invalid
|
||||
}
|
||||
else {
|
||||
if (! j_valid) return 0; // only j is invalid
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 'equal ordered'
|
||||
if (! i_valid) { // element i is invalid
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
if (! j_valid) { // only j is invalid
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static Bit16u aggregate(Bit8u BoolRes[16][16], unsigned len1, unsigned len2, Bit8u imm)
|
||||
{
|
||||
unsigned aggregation_operation = (imm >> 2) & 3;
|
||||
unsigned num_elements = (imm & 0x1) ? 8 : 16;
|
||||
unsigned polarity = (imm >> 4) & 3;
|
||||
unsigned i,j,k;
|
||||
|
||||
Bit16u result = 0;
|
||||
|
||||
switch(aggregation_operation) {
|
||||
case 0: // 'equal any'
|
||||
for(j=0; j<num_elements; j++) {
|
||||
bx_bool res = 0;
|
||||
for(i=0; i<num_elements; i++) {
|
||||
if (override_if_data_invalid(BoolRes[j][i], (i < len1), (j < len2), imm)) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
result |= (1<<j);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // 'ranges'
|
||||
for(j=0; j<num_elements; j++) {
|
||||
bx_bool res = 0;
|
||||
for(i=0; i<num_elements; i+=2) {
|
||||
if (override_if_data_invalid(BoolRes[j][i], (i < len1), (j < len2), imm) &&
|
||||
override_if_data_invalid(BoolRes[j][i+1], (i+1 < len1), (j < len2), imm)) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
result |= (1<<j);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // 'equal each'
|
||||
for(j=0; j<num_elements; j++) {
|
||||
if (override_if_data_invalid(BoolRes[j][j], (j < len1), (j < len2), imm))
|
||||
result |= (1<<j);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: // 'equal ordered'
|
||||
for(j=0; j<num_elements; j++) {
|
||||
bx_bool res = 1;
|
||||
for (i=0, k=j; (i < num_elements-j) && (k < num_elements); i++, k++) {
|
||||
if (! override_if_data_invalid(BoolRes[k][i], (i < len1), (k < len2), imm)) {
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res)
|
||||
result |= (1<<j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(polarity) {
|
||||
case 0:
|
||||
case 2:
|
||||
break; // do nothing
|
||||
|
||||
case 1:
|
||||
result ^= (num_elements == 8) ? 0xFF : 0xFFFF;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
for (j=0;j<num_elements;j++)
|
||||
if (j < len2) result ^= (1<<j); // flip the bit
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // BX_CPU_LEVEL >= 6
|
||||
|
||||
/* 66 0F 3A 60 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPESTRM_VdqWdqIbR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn());
|
||||
BxPackedXmmRegister op2 = BX_READ_XMM_REG(i->rm()), result;
|
||||
Bit8u imm8 = i->Ib();
|
||||
|
||||
// compare all pairs of Ai, Bj
|
||||
Bit8u BoolRes[16][16];
|
||||
compare_strings(BoolRes, op1, op2, imm8);
|
||||
unsigned len1, len2, num_elements = (imm8 & 0x1) ? 8 : 16;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
len1 = find_eos64(RAX, imm8);
|
||||
len2 = find_eos64(RDX, imm8);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
len1 = find_eos32(EAX, imm8);
|
||||
len2 = find_eos32(EDX, imm8);
|
||||
}
|
||||
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
|
||||
|
||||
// As defined by imm8[6], result2 is then either stored to the least
|
||||
// significant bits of XMM0 (zero extended to 128 bits) or expanded
|
||||
// into a byte/word-mask and then stored to XMM0
|
||||
if (imm8 & 0x40) {
|
||||
if (num_elements == 8) {
|
||||
for (int index = 0; index < 8; index++)
|
||||
result.xmm16u(index) = (result2 & (1<<index)) ? 0xffff : 0;
|
||||
}
|
||||
else { // num_elements = 16
|
||||
for (int index = 0; index < 16; index++)
|
||||
result.xmmubyte(index) = (result2 & (1<<index)) ? 0xff : 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.xmm64u(1) = 0;
|
||||
result.xmm64u(0) = (Bit64u) result2;
|
||||
}
|
||||
|
||||
Bit32u flags = 0;
|
||||
if (result2 != 0) flags |= EFlagsCFMask;
|
||||
if (len1 < num_elements) flags |= EFlagsSFMask;
|
||||
if (len2 < num_elements) flags |= EFlagsZFMask;
|
||||
if (result2 & 0x1)
|
||||
flags |= EFlagsOFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
|
||||
BX_WRITE_XMM_REG(0, result); /* store result XMM0 */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 3A 61 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPESTRI_VdqWdqIbR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
Bit8u imm8 = i->Ib();
|
||||
|
||||
// compare all pairs of Ai, Bj
|
||||
Bit8u BoolRes[16][16];
|
||||
compare_strings(BoolRes, op1, op2, imm8);
|
||||
unsigned len1, len2, num_elements = (imm8 & 0x1) ? 8 : 16;
|
||||
int index;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
len1 = find_eos64(RAX, imm8);
|
||||
len2 = find_eos64(RDX, imm8);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
len1 = find_eos32(EAX, imm8);
|
||||
len2 = find_eos32(EDX, imm8);
|
||||
}
|
||||
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
|
||||
|
||||
// The index of the first (or last, according to imm8[6]) set bit of result2
|
||||
// is returned to ECX. If no bits are set in IntRes2, ECX is set to 16 (8)
|
||||
if (imm8 & 0x40) {
|
||||
// The index returned to ECX is of the MSB in result2
|
||||
for (index=num_elements-1; index>=0; index--)
|
||||
if (result2 & (1<<index)) break;
|
||||
if (index < 0) index = num_elements;
|
||||
}
|
||||
else {
|
||||
// The index returned to ECX is of the LSB in result2
|
||||
for (index=0; index<(int)num_elements; index++)
|
||||
if (result2 & (1<<index)) break;
|
||||
}
|
||||
RCX = index;
|
||||
|
||||
Bit32u flags = 0;
|
||||
if (result2 != 0) flags |= EFlagsCFMask;
|
||||
if (len1 < num_elements) flags |= EFlagsSFMask;
|
||||
if (len2 < num_elements) flags |= EFlagsZFMask;
|
||||
if (result2 & 0x1)
|
||||
flags |= EFlagsOFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 3A 62 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPISTRM_VdqWdqIbR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn());
|
||||
BxPackedXmmRegister op2 = BX_READ_XMM_REG(i->rm()), result;
|
||||
Bit8u imm8 = i->Ib();
|
||||
|
||||
// compare all pairs of Ai, Bj
|
||||
Bit8u BoolRes[16][16];
|
||||
compare_strings(BoolRes, op1, op2, imm8);
|
||||
|
||||
unsigned num_elements = (imm8 & 0x1) ? 8 : 16;
|
||||
unsigned len1 = find_eos(op1, imm8);
|
||||
unsigned len2 = find_eos(op2, imm8);
|
||||
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
|
||||
|
||||
// As defined by imm8[6], result2 is then either stored to the least
|
||||
// significant bits of XMM0 (zero extended to 128 bits) or expanded
|
||||
// into a byte/word-mask and then stored to XMM0
|
||||
if (imm8 & 0x40) {
|
||||
if (num_elements == 8) {
|
||||
for (int index = 0; index < 8; index++)
|
||||
result.xmm16u(index) = (result2 & (1<<index)) ? 0xffff : 0;
|
||||
}
|
||||
else { // num_elements = 16
|
||||
for (int index = 0; index < 16; index++)
|
||||
result.xmmubyte(index) = (result2 & (1<<index)) ? 0xff : 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.xmm64u(1) = 0;
|
||||
result.xmm64u(0) = (Bit64u) result2;
|
||||
}
|
||||
|
||||
Bit32u flags = 0;
|
||||
if (result2 != 0) flags |= EFlagsCFMask;
|
||||
if (len1 < num_elements) flags |= EFlagsSFMask;
|
||||
if (len2 < num_elements) flags |= EFlagsZFMask;
|
||||
if (result2 & 0x1)
|
||||
flags |= EFlagsOFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
|
||||
BX_WRITE_XMM_REG(0, result); /* store result XMM0 */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 66 0F 3A 63 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PCMPISTRI_VdqWdqIbR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
BxPackedXmmRegister op1 = BX_READ_XMM_REG(i->nnn()), op2 = BX_READ_XMM_REG(i->rm());
|
||||
Bit8u imm8 = i->Ib();
|
||||
|
||||
// compare all pairs of Ai, Bj
|
||||
Bit8u BoolRes[16][16];
|
||||
compare_strings(BoolRes, op1, op2, imm8);
|
||||
unsigned num_elements = (imm8 & 0x1) ? 8 : 16;
|
||||
int index;
|
||||
|
||||
unsigned len1 = find_eos(op1, imm8);
|
||||
unsigned len2 = find_eos(op2, imm8);
|
||||
Bit16u result2 = aggregate(BoolRes, len1, len2, imm8);
|
||||
|
||||
// The index of the first (or last, according to imm8[6]) set bit of result2
|
||||
// is returned to ECX. If no bits are set in IntRes2, ECX is set to 16 (8)
|
||||
if (imm8 & 0x40) {
|
||||
// The index returned to ECX is of the MSB in result2
|
||||
for (index=num_elements-1; index>=0; index--)
|
||||
if (result2 & (1<<index)) break;
|
||||
if (index < 0) index = num_elements;
|
||||
}
|
||||
else {
|
||||
// The index returned to ECX is of the LSB in result2
|
||||
for (index=0; index<(int)num_elements; index++)
|
||||
if (result2 & (1<<index)) break;
|
||||
}
|
||||
RCX = index;
|
||||
|
||||
Bit32u flags = 0;
|
||||
if (result2 != 0) flags |= EFlagsCFMask;
|
||||
if (len1 < num_elements) flags |= EFlagsSFMask;
|
||||
if (len2 < num_elements) flags |= EFlagsZFMask;
|
||||
if (result2 & 0x1)
|
||||
flags |= EFlagsOFMask;
|
||||
setEFlagsOSZAPC(flags);
|
||||
#endif
|
||||
}
|
||||
140
simulators/bochs/cpu/stack.h
Executable file
140
simulators/bochs/cpu/stack.h
Executable file
@ -0,0 +1,140 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_PUSHPOP_H
|
||||
#define BX_PUSHPOP_H
|
||||
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::push_16(Bit16u value16)
|
||||
{
|
||||
/* must use StackAddrSize, and either RSP, ESP or SP accordingly */
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (StackAddrSize64()) {
|
||||
write_virtual_word_64(BX_SEG_REG_SS, RSP-2, value16);
|
||||
RSP -= 2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) { /* StackAddrSize = 32 */
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-2), value16);
|
||||
ESP -= 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-2), value16);
|
||||
SP -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::push_32(Bit32u value32)
|
||||
{
|
||||
/* must use StackAddrSize, and either RSP, ESP or SP accordingly */
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (StackAddrSize64()) {
|
||||
write_virtual_dword_64(BX_SEG_REG_SS, RSP-4, value32);
|
||||
RSP -= 4;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) { /* StackAddrSize = 32 */
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), value32);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (SP-4), value32);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
/* push 64 bit operand */
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE void BX_CPP_AttrRegparmN(1)
|
||||
BX_CPU_C::push_64(Bit64u value64)
|
||||
{
|
||||
write_virtual_qword_64(BX_SEG_REG_SS, RSP-8, value64);
|
||||
RSP -= 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* pop 16 bit operand from the stack */
|
||||
BX_CPP_INLINE Bit16u BX_CPU_C::pop_16(void)
|
||||
{
|
||||
Bit16u value16;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (StackAddrSize64()) {
|
||||
value16 = read_virtual_word_64(BX_SEG_REG_SS, RSP);
|
||||
RSP += 2;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
value16 = read_virtual_word_32(BX_SEG_REG_SS, ESP);
|
||||
ESP += 2;
|
||||
}
|
||||
else {
|
||||
value16 = read_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
SP += 2;
|
||||
}
|
||||
|
||||
return value16;
|
||||
}
|
||||
|
||||
/* pop 32 bit operand from the stack */
|
||||
BX_CPP_INLINE Bit32u BX_CPU_C::pop_32(void)
|
||||
{
|
||||
Bit32u value32;
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (StackAddrSize64()) {
|
||||
value32 = read_virtual_dword_64(BX_SEG_REG_SS, RSP);
|
||||
RSP += 4;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
value32 = read_virtual_dword_32(BX_SEG_REG_SS, ESP);
|
||||
ESP += 4;
|
||||
}
|
||||
else {
|
||||
value32 = read_virtual_dword_32(BX_SEG_REG_SS, SP);
|
||||
SP += 4;
|
||||
}
|
||||
|
||||
return value32;
|
||||
}
|
||||
|
||||
/* pop 64 bit operand from the stack */
|
||||
#if BX_SUPPORT_X86_64
|
||||
BX_CPP_INLINE Bit64u BX_CPU_C::pop_64(void)
|
||||
{
|
||||
Bit64u value64 = read_virtual_qword_64(BX_SEG_REG_SS, RSP);
|
||||
RSP += 8;
|
||||
|
||||
return value64;
|
||||
}
|
||||
#endif // BX_SUPPORT_X86_64
|
||||
|
||||
#endif
|
||||
309
simulators/bochs/cpu/stack16.cc
Normal file
309
simulators/bochs/cpu/stack16.cc
Normal file
@ -0,0 +1,309 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RSP ESP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_RX(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_READ_16BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_CS(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_DS(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_ES(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_FS(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_GS(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH16_SS(bxInstruction_c *i)
|
||||
{
|
||||
push_16(BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_DS(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u ds = pop_16();
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_ES(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u es = pop_16();
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_FS(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u fs = pop_16();
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_GS(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u gs = pop_16();
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP16_SS(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u ss = pop_16();
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
|
||||
|
||||
RSP_COMMIT;
|
||||
|
||||
// POP SS inhibits interrupts, debug exceptions and single-step
|
||||
// trap exceptions until the execution boundary following the
|
||||
// next instruction is reached.
|
||||
// Same code as MOV_SwEw()
|
||||
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS_BY_MOVSS;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_RX(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_16BIT_REG(i->rm(), pop_16());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EwM(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit16u val16 = pop_16();
|
||||
|
||||
// Note: there is one little weirdism here. It is possible to use
|
||||
// SP in the modrm addressing. If used, the value of SP after the
|
||||
// pop is used to calculate the address.
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_word(i->seg(), eaddr, val16);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_Iw(bxInstruction_c *i)
|
||||
{
|
||||
push_16(i->Iw());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_EwM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit16u op1_16 = read_virtual_word(i->seg(), eaddr);
|
||||
|
||||
push_16(op1_16);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHAD16(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u temp_ESP = ESP;
|
||||
Bit16u temp_SP = SP;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 2), AX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 4), CX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 6), DX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 8), BX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 10), temp_SP);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 12), BP);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 14), SI);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP - 16), DI);
|
||||
ESP -= 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 2), AX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 4), CX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 6), DX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 8), BX);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 10), temp_SP);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 12), BP);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 14), SI);
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP - 16), DI);
|
||||
SP -= 16;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPAD16(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u di, si, bp, bx, dx, cx, ax, dummy;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
{
|
||||
Bit32u temp_ESP = ESP;
|
||||
di = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 0));
|
||||
si = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 2));
|
||||
bp = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 4));
|
||||
dummy = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 6));
|
||||
bx = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 8));
|
||||
dx = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 10));
|
||||
cx = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 12));
|
||||
ax = read_virtual_word_32(BX_SEG_REG_SS, (Bit32u)(temp_ESP + 14));
|
||||
ESP += 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
Bit16u temp_SP = SP;
|
||||
di = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 0));
|
||||
si = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 2));
|
||||
bp = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 4));
|
||||
dummy = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 6));
|
||||
bx = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 8));
|
||||
dx = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 10));
|
||||
cx = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 12));
|
||||
ax = read_virtual_word_32(BX_SEG_REG_SS, (Bit16u)(temp_SP + 14));
|
||||
SP += 16;
|
||||
}
|
||||
|
||||
DI = di;
|
||||
SI = si;
|
||||
BP = bp;
|
||||
BX = bx;
|
||||
DX = dx;
|
||||
CX = cx;
|
||||
AX = ax;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ENTER16_IwIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u imm16 = i->Iw();
|
||||
Bit8u level = i->Ib2();
|
||||
level &= 0x1F;
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
push_16(BP);
|
||||
Bit16u frame_ptr16 = SP;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
Bit32u ebp = EBP; // Use temp copy for case of exception.
|
||||
|
||||
if (level > 0) {
|
||||
/* do level-1 times */
|
||||
while (--level) {
|
||||
ebp -= 2;
|
||||
Bit16u temp16 = read_virtual_word_32(BX_SEG_REG_SS, ebp);
|
||||
push_16(temp16);
|
||||
}
|
||||
|
||||
/* push(frame pointer) */
|
||||
push_16(frame_ptr16);
|
||||
}
|
||||
|
||||
ESP -= imm16;
|
||||
|
||||
// ENTER finishes with memory write check on the final stack pointer
|
||||
// the memory is touched but no write actually occurs
|
||||
// emulate it by doing RMW read access from SS:ESP
|
||||
read_RMW_virtual_word(BX_SEG_REG_SS, ESP);
|
||||
|
||||
BP = frame_ptr16;
|
||||
}
|
||||
else {
|
||||
Bit16u bp = BP;
|
||||
|
||||
if (level > 0) {
|
||||
/* do level-1 times */
|
||||
while (--level) {
|
||||
bp -= 2;
|
||||
Bit16u temp16 = read_virtual_word_32(BX_SEG_REG_SS, bp);
|
||||
push_16(temp16);
|
||||
}
|
||||
|
||||
/* push(frame pointer) */
|
||||
push_16(frame_ptr16);
|
||||
}
|
||||
|
||||
SP -= imm16;
|
||||
|
||||
// ENTER finishes with memory write check on the final stack pointer
|
||||
// the memory is touched but no write actually occurs
|
||||
// emulate it by doing RMW read access from SS:SP
|
||||
read_RMW_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
}
|
||||
|
||||
BP = frame_ptr16;
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEAVE16(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit16u value16;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
value16 = read_virtual_word_32(BX_SEG_REG_SS, EBP);
|
||||
ESP = EBP + 2;
|
||||
}
|
||||
else {
|
||||
value16 = read_virtual_word_32(BX_SEG_REG_SS, BP);
|
||||
SP = BP + 2;
|
||||
}
|
||||
|
||||
BP = value16;
|
||||
}
|
||||
397
simulators/bochs/cpu/stack32.cc
Normal file
397
simulators/bochs/cpu/stack32.cc
Normal file
@ -0,0 +1,397 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RSP ESP
|
||||
#endif
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EdM(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit32u val32 = pop_32();
|
||||
|
||||
// Note: there is one little weirdism here. It is possible to use
|
||||
// ESP in the modrm addressing. If used, the value of ESP after the
|
||||
// pop is used to calculate the address.
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_dword_32(i->seg(), eaddr, val32);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_ERX(bxInstruction_c *i)
|
||||
{
|
||||
push_32(BX_READ_32BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_ERX(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_32BIT_REGZ(i->rm(), pop_32());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_CS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_DS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_ES(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_FS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_GS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH32_SS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u val_16 = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit32u) (ESP-4), val_16);
|
||||
ESP -= 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_word_32(BX_SEG_REG_SS, (Bit16u) (SP-4), val_16);
|
||||
SP -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_DS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u ds;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
ds = read_virtual_word_32(BX_SEG_REG_SS, ESP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
|
||||
ESP += 4;
|
||||
}
|
||||
else {
|
||||
ds = read_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], ds);
|
||||
SP += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_ES(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u es;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
es = read_virtual_word_32(BX_SEG_REG_SS, ESP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
|
||||
ESP += 4;
|
||||
}
|
||||
else {
|
||||
es = read_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], es);
|
||||
SP += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_FS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u fs;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
fs = read_virtual_word_32(BX_SEG_REG_SS, ESP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
|
||||
ESP += 4;
|
||||
}
|
||||
else {
|
||||
fs = read_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], fs);
|
||||
SP += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_GS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u gs;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
gs = read_virtual_word_32(BX_SEG_REG_SS, ESP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
|
||||
ESP += 4;
|
||||
}
|
||||
else {
|
||||
gs = read_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], gs);
|
||||
SP += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP32_SS(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u ss;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
ss = read_virtual_word_32(BX_SEG_REG_SS, ESP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
|
||||
ESP += 4;
|
||||
}
|
||||
else {
|
||||
ss = read_virtual_word_32(BX_SEG_REG_SS, SP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], ss);
|
||||
SP += 4;
|
||||
}
|
||||
|
||||
// POP SS inhibits interrupts, debug exceptions and single-step
|
||||
// trap exceptions until the execution boundary following the
|
||||
// next instruction is reached.
|
||||
// Same code as MOV_SwEw()
|
||||
BX_CPU_THIS_PTR inhibit_mask |= BX_INHIBIT_INTERRUPTS_BY_MOVSS;
|
||||
BX_CPU_THIS_PTR async_event = 1;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_Id(bxInstruction_c *i)
|
||||
{
|
||||
push_32(i->Id());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_EdM(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u eaddr = (Bit32u) BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit32u op1_32 = read_virtual_dword_32(i->seg(), eaddr);
|
||||
|
||||
push_32(op1_32);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSHAD32(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u temp_ESP = ESP;
|
||||
Bit16u temp_SP = SP;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
{
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 4), EAX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 8), ECX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 12), EDX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 16), EBX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 20), temp_ESP);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 24), EBP);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 28), ESI);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP - 32), EDI);
|
||||
ESP -= 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 4), EAX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 8), ECX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 12), EDX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 16), EBX);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 20), temp_ESP);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 24), EBP);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 28), ESI);
|
||||
write_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP - 32), EDI);
|
||||
SP -= 32;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POPAD32(bxInstruction_c *i)
|
||||
{
|
||||
Bit32u edi, esi, ebp, ebx, edx, ecx, eax, dummy;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
{
|
||||
Bit32u temp_ESP = ESP;
|
||||
edi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 0));
|
||||
esi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 4));
|
||||
ebp = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 8));
|
||||
dummy = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 12));
|
||||
ebx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 16));
|
||||
edx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 20));
|
||||
ecx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 24));
|
||||
eax = read_virtual_dword_32(BX_SEG_REG_SS, (Bit32u) (temp_ESP + 28));
|
||||
ESP += 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
Bit16u temp_SP = SP;
|
||||
edi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 0));
|
||||
esi = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 4));
|
||||
ebp = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 8));
|
||||
dummy = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 12));
|
||||
ebx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 16));
|
||||
edx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 20));
|
||||
ecx = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 24));
|
||||
eax = read_virtual_dword_32(BX_SEG_REG_SS, (Bit16u) (temp_SP + 28));
|
||||
SP += 32;
|
||||
}
|
||||
|
||||
EDI = edi;
|
||||
ESI = esi;
|
||||
EBP = ebp;
|
||||
EBX = ebx;
|
||||
EDX = edx;
|
||||
ECX = ecx;
|
||||
EAX = eax;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ENTER32_IwIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit16u imm16 = i->Iw();
|
||||
Bit8u level = i->Ib2();
|
||||
level &= 0x1F;
|
||||
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
push_32(EBP);
|
||||
Bit32u frame_ptr32 = ESP;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
Bit32u ebp = EBP; // Use temp copy for case of exception.
|
||||
|
||||
if (level > 0) {
|
||||
/* do level-1 times */
|
||||
while (--level) {
|
||||
ebp -= 4;
|
||||
Bit32u temp32 = read_virtual_dword_32(BX_SEG_REG_SS, ebp);
|
||||
push_32(temp32);
|
||||
}
|
||||
|
||||
/* push(frame pointer) */
|
||||
push_32(frame_ptr32);
|
||||
}
|
||||
|
||||
ESP -= imm16;
|
||||
|
||||
// ENTER finishes with memory write check on the final stack pointer
|
||||
// the memory is touched but no write actually occurs
|
||||
// emulate it by doing RMW read access from SS:ESP
|
||||
read_RMW_virtual_dword_32(BX_SEG_REG_SS, ESP);
|
||||
}
|
||||
else {
|
||||
Bit16u bp = BP;
|
||||
|
||||
if (level > 0) {
|
||||
/* do level-1 times */
|
||||
while (--level) {
|
||||
bp -= 4;
|
||||
Bit32u temp32 = read_virtual_dword_32(BX_SEG_REG_SS, bp);
|
||||
push_32(temp32);
|
||||
}
|
||||
|
||||
/* push(frame pointer) */
|
||||
push_32(frame_ptr32);
|
||||
}
|
||||
|
||||
SP -= imm16;
|
||||
|
||||
// ENTER finishes with memory write check on the final stack pointer
|
||||
// the memory is touched but no write actually occurs
|
||||
// emulate it by doing RMW read access from SS:SP
|
||||
read_RMW_virtual_dword_32(BX_SEG_REG_SS, SP);
|
||||
}
|
||||
|
||||
EBP = frame_ptr32;
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEAVE32(bxInstruction_c *i)
|
||||
{
|
||||
BX_ASSERT(BX_CPU_THIS_PTR cpu_mode != BX_MODE_LONG_64);
|
||||
|
||||
Bit32u value32;
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b) {
|
||||
value32 = read_virtual_dword_32(BX_SEG_REG_SS, EBP);
|
||||
ESP = EBP + 4;
|
||||
}
|
||||
else {
|
||||
value32 = read_virtual_dword_32(BX_SEG_REG_SS, BP);
|
||||
SP = BP + 4;
|
||||
}
|
||||
|
||||
EBP = value32;
|
||||
}
|
||||
139
simulators/bochs/cpu/stack64.cc
Normal file
139
simulators/bochs/cpu/stack64.cc
Normal file
@ -0,0 +1,139 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_EqM(bxInstruction_c *i)
|
||||
{
|
||||
RSP_SPECULATIVE;
|
||||
|
||||
Bit64u val64 = pop_64();
|
||||
|
||||
// Note: there is one little weirdism here. It is possible to use
|
||||
// RSP in the modrm addressing. If used, the value of RSP after the
|
||||
// pop is used to calculate the address.
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
write_virtual_qword_64(i->seg(), eaddr, val64);
|
||||
|
||||
RSP_COMMIT;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_RRX(bxInstruction_c *i)
|
||||
{
|
||||
push_64(BX_READ_64BIT_REG(i->rm()));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP_RRX(bxInstruction_c *i)
|
||||
{
|
||||
BX_WRITE_64BIT_REG(i->rm(), pop_64());
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH64_FS(bxInstruction_c *i)
|
||||
{
|
||||
push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH64_GS(bxInstruction_c *i)
|
||||
{
|
||||
push_64(BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP64_FS(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u fs = read_virtual_word_64(BX_SEG_REG_SS, RSP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], (Bit16u) fs);
|
||||
RSP += 8;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::POP64_GS(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u gs = read_virtual_word_64(BX_SEG_REG_SS, RSP);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], (Bit16u) gs);
|
||||
RSP += 8;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH64_Id(bxInstruction_c *i)
|
||||
{
|
||||
Bit64u imm64 = (Bit32s) i->Id();
|
||||
push_64(imm64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::PUSH_EqM(bxInstruction_c *i)
|
||||
{
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
|
||||
Bit64u op1_64 = read_virtual_qword_64(i->seg(), eaddr);
|
||||
|
||||
push_64(op1_64);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::ENTER64_IwIb(bxInstruction_c *i)
|
||||
{
|
||||
Bit8u level = i->Ib2();
|
||||
level &= 0x1F;
|
||||
|
||||
Bit64u temp_RSP = RSP, temp_RBP = RBP;
|
||||
|
||||
temp_RSP -= 8;
|
||||
write_virtual_qword_64(BX_SEG_REG_SS, temp_RSP, temp_RBP);
|
||||
|
||||
Bit64u frame_ptr64 = temp_RSP;
|
||||
|
||||
if (level > 0) {
|
||||
/* do level-1 times */
|
||||
while (--level) {
|
||||
temp_RBP -= 8;
|
||||
Bit64u temp64 = read_virtual_qword_64(BX_SEG_REG_SS, temp_RBP);
|
||||
temp_RSP -= 8;
|
||||
write_virtual_qword_64(BX_SEG_REG_SS, temp_RSP, temp64);
|
||||
} /* while (--level) */
|
||||
|
||||
/* push(frame pointer) */
|
||||
temp_RSP -= 8;
|
||||
write_virtual_qword_64(BX_SEG_REG_SS, temp_RSP, frame_ptr64);
|
||||
} /* if (level > 0) ... */
|
||||
|
||||
temp_RSP -= i->Iw();
|
||||
|
||||
// ENTER finishes with memory write check on the final stack pointer
|
||||
// the memory is touched but no write actually occurs
|
||||
// emulate it by doing RMW read access from SS:RSP
|
||||
read_RMW_virtual_qword_64(BX_SEG_REG_SS, temp_RSP);
|
||||
|
||||
RBP = frame_ptr64;
|
||||
RSP = temp_RSP;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::LEAVE64(bxInstruction_c *i)
|
||||
{
|
||||
// restore frame pointer
|
||||
Bit64u temp64 = read_virtual_qword_64(BX_SEG_REG_SS, RBP);
|
||||
RSP = RBP + 8;
|
||||
RBP = temp64;
|
||||
}
|
||||
|
||||
#endif /* if BX_SUPPORT_X86_64 */
|
||||
2112
simulators/bochs/cpu/string.cc
Normal file
2112
simulators/bochs/cpu/string.cc
Normal file
File diff suppressed because it is too large
Load Diff
798
simulators/bochs/cpu/tasking.cc
Normal file
798
simulators/bochs/cpu/tasking.cc
Normal file
@ -0,0 +1,798 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2010 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Notes:
|
||||
// ======
|
||||
|
||||
// ======================
|
||||
// 286 Task State Segment
|
||||
// ======================
|
||||
// dynamic item | hex dec offset
|
||||
// 0 task LDT selector | 2a 42
|
||||
// 1 DS selector | 28 40
|
||||
// 1 SS selector | 26 38
|
||||
// 1 CS selector | 24 36
|
||||
// 1 ES selector | 22 34
|
||||
// 1 DI | 20 32
|
||||
// 1 SI | 1e 30
|
||||
// 1 BP | 1c 28
|
||||
// 1 SP | 1a 26
|
||||
// 1 BX | 18 24
|
||||
// 1 DX | 16 22
|
||||
// 1 CX | 14 20
|
||||
// 1 AX | 12 18
|
||||
// 1 flag word | 10 16
|
||||
// 1 IP (entry point) | 0e 14
|
||||
// 0 SS for CPL 2 | 0c 12
|
||||
// 0 SP for CPL 2 | 0a 10
|
||||
// 0 SS for CPL 1 | 08 08
|
||||
// 0 SP for CPL 1 | 06 06
|
||||
// 0 SS for CPL 0 | 04 04
|
||||
// 0 SP for CPL 0 | 02 02
|
||||
// back link selector to TSS | 00 00
|
||||
|
||||
|
||||
// ======================
|
||||
// 386 Task State Segment
|
||||
// ======================
|
||||
// |31 16|15 0| hex dec
|
||||
// |I/O Map Base |000000000000000000000|T| 64 100 static
|
||||
// |0000000000000000| LDT | 60 96 static
|
||||
// |0000000000000000| GS selector | 5c 92 dynamic
|
||||
// |0000000000000000| FS selector | 58 88 dynamic
|
||||
// |0000000000000000| DS selector | 54 84 dynamic
|
||||
// |0000000000000000| SS selector | 50 80 dynamic
|
||||
// |0000000000000000| CS selector | 4c 76 dynamic
|
||||
// |0000000000000000| ES selector | 48 72 dynamic
|
||||
// | EDI | 44 68 dynamic
|
||||
// | ESI | 40 64 dynamic
|
||||
// | EBP | 3c 60 dynamic
|
||||
// | ESP | 38 56 dynamic
|
||||
// | EBX | 34 52 dynamic
|
||||
// | EDX | 30 48 dynamic
|
||||
// | ECX | 2c 44 dynamic
|
||||
// | EAX | 28 40 dynamic
|
||||
// | EFLAGS | 24 36 dynamic
|
||||
// | EIP (entry point) | 20 32 dynamic
|
||||
// | CR3 (PDPR) | 1c 28 static
|
||||
// |000000000000000 | SS for CPL 2 | 18 24 static
|
||||
// | ESP for CPL 2 | 14 20 static
|
||||
// |000000000000000 | SS for CPL 1 | 10 16 static
|
||||
// | ESP for CPL 1 | 0c 12 static
|
||||
// |000000000000000 | SS for CPL 0 | 08 08 static
|
||||
// | ESP for CPL 0 | 04 04 static
|
||||
// |000000000000000 | back link to prev TSS | 00 00 dynamic (updated only when return expected)
|
||||
|
||||
|
||||
// ==================================================
|
||||
// Effect of task switch on Busy, NT, and Link Fields
|
||||
// ==================================================
|
||||
|
||||
// Field jump call/interrupt iret
|
||||
// ------------------------------------------------------
|
||||
// new busy bit Set Set No change
|
||||
// old busy bit Cleared No change Cleared
|
||||
// new NT flag No change Set No change
|
||||
// old NT flag No change No change Cleared
|
||||
// new link No change old TSS selector No change
|
||||
// old link No change No change No change
|
||||
// CR0.TS Set Set Set
|
||||
|
||||
// Note: I checked 386, 486, and Pentium, and they all exhibited
|
||||
// exactly the same behaviour as above. There seems to
|
||||
// be some misprints in the Intel docs.
|
||||
|
||||
void BX_CPU_C::task_switch(bxInstruction_c *i, bx_selector_t *tss_selector,
|
||||
bx_descriptor_t *tss_descriptor, unsigned source,
|
||||
Bit32u dword1, Bit32u dword2)
|
||||
{
|
||||
Bit32u obase32; // base address of old TSS
|
||||
Bit32u nbase32; // base address of new TSS
|
||||
Bit32u temp32, newCR3;
|
||||
Bit16u raw_cs_selector, raw_ss_selector, raw_ds_selector, raw_es_selector,
|
||||
raw_fs_selector, raw_gs_selector, raw_ldt_selector;
|
||||
Bit16u trap_word;
|
||||
bx_selector_t cs_selector, ss_selector, ds_selector, es_selector,
|
||||
fs_selector, gs_selector, ldt_selector;
|
||||
bx_descriptor_t cs_descriptor, ss_descriptor, ldt_descriptor;
|
||||
Bit32u old_TSS_max, new_TSS_max, old_TSS_limit, new_TSS_limit;
|
||||
Bit32u newEAX, newECX, newEDX, newEBX;
|
||||
Bit32u newESP, newEBP, newESI, newEDI;
|
||||
Bit32u newEFLAGS, newEIP;
|
||||
|
||||
BX_DEBUG(("TASKING: ENTER"));
|
||||
|
||||
invalidate_prefetch_q();
|
||||
|
||||
// Discard any traps and inhibits for new context; traps will
|
||||
// resume upon return.
|
||||
BX_CPU_THIS_PTR debug_trap = 0;
|
||||
BX_CPU_THIS_PTR inhibit_mask = 0;
|
||||
|
||||
// STEP 1: The following checks are made before calling task_switch(),
|
||||
// for JMP & CALL only. These checks are NOT made for exceptions,
|
||||
// interrupts & IRET.
|
||||
//
|
||||
// 1) TSS DPL must be >= CPL
|
||||
// 2) TSS DPL must be >= TSS selector RPL
|
||||
// 3) TSS descriptor is not busy.
|
||||
|
||||
// STEP 2: The processor performs limit-checking on the target TSS
|
||||
// to verify that the TSS limit is greater than or equal
|
||||
// to 67h (2Bh for 16-bit TSS).
|
||||
|
||||
// Gather info about new TSS
|
||||
if (tss_descriptor->type <= 3) { // {1,3}
|
||||
new_TSS_max = 0x2B;
|
||||
}
|
||||
else { // tss_descriptor->type = {9,11}
|
||||
new_TSS_max = 0x67;
|
||||
}
|
||||
|
||||
nbase32 = (Bit32u) tss_descriptor->u.segment.base;
|
||||
new_TSS_limit = tss_descriptor->u.segment.limit_scaled;
|
||||
|
||||
if (new_TSS_limit < new_TSS_max) {
|
||||
BX_ERROR(("task_switch(): new TSS limit < %d", new_TSS_max));
|
||||
exception(BX_TS_EXCEPTION, tss_selector->value & 0xfffc);
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
VMexit_TaskSwitch(i, tss_selector->value, source);
|
||||
#endif
|
||||
|
||||
// Gather info about old TSS
|
||||
if (BX_CPU_THIS_PTR tr.cache.type <= 3) {
|
||||
old_TSS_max = 0x29;
|
||||
}
|
||||
else {
|
||||
old_TSS_max = 0x5F;
|
||||
}
|
||||
|
||||
obase32 = (Bit32u) BX_CPU_THIS_PTR tr.cache.u.segment.base; // old TSS.base
|
||||
old_TSS_limit = BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled;
|
||||
|
||||
if (old_TSS_limit < old_TSS_max) {
|
||||
BX_ERROR(("task_switch(): old TSS limit < %d", old_TSS_max));
|
||||
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
if (obase32 == nbase32) {
|
||||
BX_INFO(("TASK SWITCH: switching to the same TSS !"));
|
||||
}
|
||||
|
||||
// Check that old TSS, new TSS, and all segment descriptors
|
||||
// used in the task switch are paged in.
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG())
|
||||
{
|
||||
dtranslate_linear(nbase32, 0, BX_READ); // old TSS
|
||||
dtranslate_linear(nbase32 + new_TSS_max, 0, BX_READ);
|
||||
|
||||
// ??? Humm, we check the new TSS region with READ above,
|
||||
// but sometimes we need to write the link field in that
|
||||
// region. We also sometimes update other fields, perhaps
|
||||
// we need to WRITE check them here also, so that we keep
|
||||
// the written state consistent (ie, we don't encounter a
|
||||
// page fault in the middle).
|
||||
|
||||
if (source == BX_TASK_FROM_CALL || source == BX_TASK_FROM_INT)
|
||||
{
|
||||
dtranslate_linear(nbase32, 0, BX_WRITE);
|
||||
dtranslate_linear(nbase32 + 1, 0, BX_WRITE);
|
||||
}
|
||||
}
|
||||
|
||||
// Privilege and busy checks done in CALL, JUMP, INT, IRET
|
||||
|
||||
// Step 3: If JMP or IRET, clear busy bit in old task TSS descriptor,
|
||||
// otherwise leave set.
|
||||
|
||||
// effect on Busy bit of old task
|
||||
if (source == BX_TASK_FROM_JUMP || source == BX_TASK_FROM_IRET) {
|
||||
// Bit is cleared
|
||||
Bit32u laddr = (Bit32u) BX_CPU_THIS_PTR gdtr.base + (BX_CPU_THIS_PTR tr.selector.index<<3) + 4;
|
||||
access_read_linear(laddr, 4, 0, BX_RW, &temp32);
|
||||
temp32 &= ~0x200;
|
||||
access_write_linear(laddr, 4, 0, &temp32);
|
||||
}
|
||||
|
||||
// STEP 4: If the task switch was initiated with an IRET instruction,
|
||||
// clears the NT flag in a temporarily saved EFLAGS image;
|
||||
// if initiated with a CALL or JMP instruction, an exception, or
|
||||
// an interrupt, the NT flag is left unchanged.
|
||||
|
||||
Bit32u oldEFLAGS = read_eflags();
|
||||
|
||||
/* if moving to busy task, clear NT bit */
|
||||
if (tss_descriptor->type == BX_SYS_SEGMENT_BUSY_286_TSS ||
|
||||
tss_descriptor->type == BX_SYS_SEGMENT_BUSY_386_TSS)
|
||||
{
|
||||
oldEFLAGS &= ~EFlagsNTMask;
|
||||
}
|
||||
|
||||
// STEP 5: Save the current task state in the TSS. Up to this point,
|
||||
// any exception that occurs aborts the task switch without
|
||||
// changing the processor state.
|
||||
|
||||
/* save current machine state in old task's TSS */
|
||||
|
||||
if (BX_CPU_THIS_PTR tr.cache.type <= 3) {
|
||||
// check that we won't page fault while writing
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG()) {
|
||||
dtranslate_linear(Bit32u(obase32 + 14), 0, BX_WRITE);
|
||||
dtranslate_linear(Bit32u(obase32 + 41), 0, BX_WRITE);
|
||||
}
|
||||
|
||||
system_write_word(Bit32u(obase32 + 14), IP);
|
||||
system_write_word(Bit32u(obase32 + 16), oldEFLAGS);
|
||||
system_write_word(Bit32u(obase32 + 18), AX);
|
||||
system_write_word(Bit32u(obase32 + 20), CX);
|
||||
system_write_word(Bit32u(obase32 + 22), DX);
|
||||
system_write_word(Bit32u(obase32 + 24), BX);
|
||||
system_write_word(Bit32u(obase32 + 26), SP);
|
||||
system_write_word(Bit32u(obase32 + 28), BP);
|
||||
system_write_word(Bit32u(obase32 + 30), SI);
|
||||
system_write_word(Bit32u(obase32 + 32), DI);
|
||||
|
||||
system_write_word(Bit32u(obase32 + 34),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 36),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 38),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 40),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
}
|
||||
else {
|
||||
// check that we won't page fault while writing
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG()) {
|
||||
dtranslate_linear(Bit32u(obase32 + 0x20), 0, BX_WRITE);
|
||||
dtranslate_linear(Bit32u(obase32 + 0x5d), 0, BX_WRITE);
|
||||
}
|
||||
|
||||
system_write_dword(Bit32u(obase32 + 0x20), EIP);
|
||||
system_write_dword(Bit32u(obase32 + 0x24), oldEFLAGS);
|
||||
system_write_dword(Bit32u(obase32 + 0x28), EAX);
|
||||
system_write_dword(Bit32u(obase32 + 0x2c), ECX);
|
||||
system_write_dword(Bit32u(obase32 + 0x30), EDX);
|
||||
system_write_dword(Bit32u(obase32 + 0x34), EBX);
|
||||
system_write_dword(Bit32u(obase32 + 0x38), ESP);
|
||||
system_write_dword(Bit32u(obase32 + 0x3c), EBP);
|
||||
system_write_dword(Bit32u(obase32 + 0x40), ESI);
|
||||
system_write_dword(Bit32u(obase32 + 0x44), EDI);
|
||||
|
||||
system_write_word(Bit32u(obase32 + 0x48),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 0x4c),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 0x50),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 0x54),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 0x58),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value);
|
||||
system_write_word(Bit32u(obase32 + 0x5c),
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value);
|
||||
}
|
||||
|
||||
// effect on link field of new task
|
||||
if (source == BX_TASK_FROM_CALL || source == BX_TASK_FROM_INT)
|
||||
{
|
||||
// set to selector of old task's TSS
|
||||
system_write_word(nbase32, BX_CPU_THIS_PTR tr.selector.value);
|
||||
}
|
||||
|
||||
// STEP 6: The new-task state is loaded from the TSS
|
||||
|
||||
if (tss_descriptor->type <= 3) {
|
||||
newEIP = system_read_word(Bit32u(nbase32 + 14));
|
||||
newEFLAGS = system_read_word(Bit32u(nbase32 + 16));
|
||||
|
||||
// incoming TSS is 16bit:
|
||||
// - upper word of general registers is set to 0xFFFF
|
||||
// - upper word of eflags is zero'd
|
||||
// - FS, GS are zero'd
|
||||
// - upper word of eIP is zero'd
|
||||
Bit16u temp16 = system_read_word(Bit32u(nbase32 + 18));
|
||||
newEAX = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 20));
|
||||
newECX = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 22));
|
||||
newEDX = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 24));
|
||||
newEBX = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 26));
|
||||
newESP = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 28));
|
||||
newEBP = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 30));
|
||||
newESI = 0xffff0000 | temp16;
|
||||
temp16 = system_read_word(Bit32u(nbase32 + 32));
|
||||
newEDI = 0xffff0000 | temp16;
|
||||
|
||||
raw_es_selector = system_read_word(Bit32u(nbase32 + 34));
|
||||
raw_cs_selector = system_read_word(Bit32u(nbase32 + 36));
|
||||
raw_ss_selector = system_read_word(Bit32u(nbase32 + 38));
|
||||
raw_ds_selector = system_read_word(Bit32u(nbase32 + 40));
|
||||
raw_ldt_selector = system_read_word(Bit32u(nbase32 + 42));
|
||||
|
||||
raw_fs_selector = 0; // use a NULL selector
|
||||
raw_gs_selector = 0; // use a NULL selector
|
||||
// No CR3 change for 286 task switch
|
||||
newCR3 = 0; // keep compiler happy (not used)
|
||||
trap_word = 0; // keep compiler happy (not used)
|
||||
}
|
||||
else {
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG())
|
||||
newCR3 = system_read_dword(Bit32u(nbase32 + 0x1c));
|
||||
else
|
||||
newCR3 = 0; // keep compiler happy (not used)
|
||||
|
||||
newEIP = system_read_dword(Bit32u(nbase32 + 0x20));
|
||||
newEFLAGS = system_read_dword(Bit32u(nbase32 + 0x24));
|
||||
newEAX = system_read_dword(Bit32u(nbase32 + 0x28));
|
||||
newECX = system_read_dword(Bit32u(nbase32 + 0x2c));
|
||||
newEDX = system_read_dword(Bit32u(nbase32 + 0x30));
|
||||
newEBX = system_read_dword(Bit32u(nbase32 + 0x34));
|
||||
newESP = system_read_dword(Bit32u(nbase32 + 0x38));
|
||||
newEBP = system_read_dword(Bit32u(nbase32 + 0x3c));
|
||||
newESI = system_read_dword(Bit32u(nbase32 + 0x40));
|
||||
newEDI = system_read_dword(Bit32u(nbase32 + 0x44));
|
||||
|
||||
raw_es_selector = system_read_word(Bit32u(nbase32 + 0x48));
|
||||
raw_cs_selector = system_read_word(Bit32u(nbase32 + 0x4c));
|
||||
raw_ss_selector = system_read_word(Bit32u(nbase32 + 0x50));
|
||||
raw_ds_selector = system_read_word(Bit32u(nbase32 + 0x54));
|
||||
raw_fs_selector = system_read_word(Bit32u(nbase32 + 0x58));
|
||||
raw_gs_selector = system_read_word(Bit32u(nbase32 + 0x5c));
|
||||
raw_ldt_selector = system_read_word(Bit32u(nbase32 + 0x60));
|
||||
trap_word = system_read_word(Bit32u(nbase32 + 0x64));
|
||||
}
|
||||
|
||||
// Step 7: If CALL, interrupt, or JMP, set busy flag in new task's
|
||||
// TSS descriptor. If IRET, leave set.
|
||||
|
||||
if (source != BX_TASK_FROM_IRET)
|
||||
{
|
||||
// set the new task's busy bit
|
||||
Bit32u laddr = (Bit32u)(BX_CPU_THIS_PTR gdtr.base) + (tss_selector->index<<3) + 4;
|
||||
access_read_linear(laddr, 4, 0, BX_RW, &dword2);
|
||||
dword2 |= 0x200;
|
||||
access_write_linear(laddr, 4, 0, &dword2);
|
||||
}
|
||||
|
||||
//
|
||||
// Commit point. At this point, we commit to the new
|
||||
// context. If an unrecoverable error occurs in further
|
||||
// processing, we complete the task switch without performing
|
||||
// additional access and segment availablility checks and
|
||||
// generate the appropriate exception prior to beginning
|
||||
// execution of the new task.
|
||||
//
|
||||
|
||||
// Step 8: Load the task register with the segment selector and
|
||||
// descriptor for the new task TSS.
|
||||
|
||||
BX_CPU_THIS_PTR tr.selector = *tss_selector;
|
||||
BX_CPU_THIS_PTR tr.cache = *tss_descriptor;
|
||||
BX_CPU_THIS_PTR tr.cache.type |= 2; // mark TSS in TR as busy
|
||||
|
||||
// Step 9: Set TS flag in the CR0 image stored in the new task TSS.
|
||||
BX_CPU_THIS_PTR cr0.set_TS(1);
|
||||
|
||||
// Task switch clears LE/L3/L2/L1/L0 in DR7
|
||||
BX_CPU_THIS_PTR dr7 &= ~0x00000155;
|
||||
|
||||
// Step 10: If call or interrupt, set the NT flag in the eflags
|
||||
// image stored in new task's TSS. If IRET or JMP,
|
||||
// NT is restored from new TSS eflags image. (no change)
|
||||
|
||||
// effect on NT flag of new task
|
||||
if (source == BX_TASK_FROM_CALL || source == BX_TASK_FROM_INT) {
|
||||
newEFLAGS |= EFlagsNTMask; // NT flag is set
|
||||
}
|
||||
|
||||
// Step 11: Load the new task (dynamic) state from new TSS.
|
||||
// Any errors associated with loading and qualification of
|
||||
// segment descriptors in this step occur in the new task's
|
||||
// context. State loaded here includes LDTR, CR3,
|
||||
// EFLAGS, EIP, general purpose registers, and segment
|
||||
// descriptor parts of the segment registers.
|
||||
|
||||
BX_CPU_THIS_PTR prev_rip = EIP = newEIP;
|
||||
|
||||
EAX = newEAX;
|
||||
ECX = newECX;
|
||||
EDX = newEDX;
|
||||
EBX = newEBX;
|
||||
ESP = newESP;
|
||||
EBP = newEBP;
|
||||
ESI = newESI;
|
||||
EDI = newEDI;
|
||||
|
||||
BX_CPU_THIS_PTR speculative_rsp = 0;
|
||||
|
||||
writeEFlags(newEFLAGS, EFlagsValidMask);
|
||||
|
||||
// Fill in selectors for all segment registers. If errors
|
||||
// occur later, the selectors will at least be loaded.
|
||||
parse_selector(raw_cs_selector, &cs_selector);
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector = cs_selector;
|
||||
parse_selector(raw_ss_selector, &ss_selector);
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector = ss_selector;
|
||||
parse_selector(raw_ds_selector, &ds_selector);
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector = ds_selector;
|
||||
parse_selector(raw_es_selector, &es_selector);
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector = es_selector;
|
||||
parse_selector(raw_fs_selector, &fs_selector);
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector = fs_selector;
|
||||
parse_selector(raw_gs_selector, &gs_selector);
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector = gs_selector;
|
||||
parse_selector(raw_ldt_selector, &ldt_selector);
|
||||
BX_CPU_THIS_PTR ldtr.selector = ldt_selector;
|
||||
|
||||
// Start out with invalid descriptor caches, fill in with
|
||||
// values only as they are validated
|
||||
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].cache.valid = 0;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].cache.valid = 0;
|
||||
|
||||
if ((tss_descriptor->type >= 9) && BX_CPU_THIS_PTR cr0.get_PG()) {
|
||||
// change CR3 only if it actually modified
|
||||
if (newCR3 != BX_CPU_THIS_PTR cr3) {
|
||||
BX_DEBUG(("task_switch changing CR3 to 0x%08x", newCR3));
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
if (BX_CPU_THIS_PTR cr0.get_PG() && BX_CPU_THIS_PTR cr4.get_PAE()) {
|
||||
if (! CheckPDPTR(newCR3)) {
|
||||
BX_ERROR(("task_switch(exception after commit point): PDPTR check failed !"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (! SetCR3(newCR3)) // Tell paging unit about new cr3 value
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_TASKSWITCH, newCR3);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned save_CPL = CPL;
|
||||
/* set CPL to 3 to force a privilege level change and stack switch if SS
|
||||
is not properly loaded */
|
||||
CPL = 3;
|
||||
|
||||
// LDTR
|
||||
if (ldt_selector.ti) {
|
||||
// LDT selector must be in GDT
|
||||
BX_INFO(("task_switch(exception after commit point): bad LDT selector TI=1"));
|
||||
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
|
||||
}
|
||||
|
||||
if ((raw_ldt_selector & 0xfffc) != 0) {
|
||||
bx_bool good = fetch_raw_descriptor2(&ldt_selector, &dword1, &dword2);
|
||||
if (!good) {
|
||||
BX_ERROR(("task_switch(exception after commit point): bad LDT fetch"));
|
||||
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &ldt_descriptor);
|
||||
|
||||
// LDT selector of new task is valid, else #TS(new task's LDT)
|
||||
if (ldt_descriptor.valid==0 ||
|
||||
ldt_descriptor.type!=BX_SYS_SEGMENT_LDT ||
|
||||
ldt_descriptor.segment)
|
||||
{
|
||||
BX_ERROR(("task_switch(exception after commit point): bad LDT segment"));
|
||||
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// LDT of new task is present in memory, else #TS(new tasks's LDT)
|
||||
if (! IS_PRESENT(ldt_descriptor)) {
|
||||
BX_ERROR(("task_switch(exception after commit point): LDT not present"));
|
||||
exception(BX_TS_EXCEPTION, raw_ldt_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// All checks pass, fill in LDTR shadow cache
|
||||
BX_CPU_THIS_PTR ldtr.cache = ldt_descriptor;
|
||||
}
|
||||
else {
|
||||
// NULL LDT selector is OK, leave cache invalid
|
||||
}
|
||||
|
||||
if (v8086_mode()) {
|
||||
// load seg regs as 8086 registers
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], raw_ss_selector);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS], raw_ds_selector);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES], raw_es_selector);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS], raw_fs_selector);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS], raw_gs_selector);
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], raw_cs_selector);
|
||||
// CPL is set from CS selector
|
||||
}
|
||||
else {
|
||||
|
||||
// SS
|
||||
if ((raw_ss_selector & 0xfffc) != 0)
|
||||
{
|
||||
bx_bool good = fetch_raw_descriptor2(&ss_selector, &dword1, &dword2);
|
||||
if (!good) {
|
||||
BX_ERROR(("task_switch(exception after commit point): bad SS fetch"));
|
||||
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &ss_descriptor);
|
||||
|
||||
// SS selector must be within its descriptor table limits else #TS(SS)
|
||||
// SS descriptor AR byte must must indicate writable data segment,
|
||||
// else #TS(SS)
|
||||
if (ss_descriptor.valid==0 || ss_descriptor.segment==0 ||
|
||||
IS_CODE_SEGMENT(ss_descriptor.type) ||
|
||||
!IS_DATA_SEGMENT_WRITEABLE(ss_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("task_switch(exception after commit point): SS not valid or writeable segment"));
|
||||
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
//
|
||||
// Stack segment is present in memory, else #SS(new stack segment)
|
||||
//
|
||||
if (! IS_PRESENT(ss_descriptor)) {
|
||||
BX_ERROR(("task_switch(exception after commit point): SS not present"));
|
||||
exception(BX_SS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// Stack segment DPL matches CS.RPL, else #TS(new stack segment)
|
||||
if (ss_descriptor.dpl != cs_selector.rpl) {
|
||||
BX_ERROR(("task_switch(exception after commit point): SS.rpl != CS.RPL"));
|
||||
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// Stack segment DPL matches selector RPL, else #TS(new stack segment)
|
||||
if (ss_descriptor.dpl != ss_selector.rpl) {
|
||||
BX_ERROR(("task_switch(exception after commit point): SS.dpl != SS.rpl"));
|
||||
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
touch_segment(&ss_selector, &ss_descriptor);
|
||||
|
||||
// All checks pass, fill in shadow cache
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache = ss_descriptor;
|
||||
}
|
||||
else {
|
||||
// SS selector is valid, else #TS(new stack segment)
|
||||
BX_ERROR(("task_switch(exception after commit point): SS NULL"));
|
||||
exception(BX_TS_EXCEPTION, raw_ss_selector & 0xfffc);
|
||||
}
|
||||
|
||||
CPL = save_CPL;
|
||||
|
||||
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS],
|
||||
&ds_selector, raw_ds_selector, cs_selector.rpl);
|
||||
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES],
|
||||
&es_selector, raw_es_selector, cs_selector.rpl);
|
||||
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS],
|
||||
&fs_selector, raw_fs_selector, cs_selector.rpl);
|
||||
task_switch_load_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS],
|
||||
&gs_selector, raw_gs_selector, cs_selector.rpl);
|
||||
|
||||
// if new selector is not null then perform following checks:
|
||||
// index must be within its descriptor table limits else #TS(selector)
|
||||
// AR byte must indicate data or readable code else #TS(selector)
|
||||
// if data or non-conforming code then:
|
||||
// DPL must be >= CPL else #TS(selector)
|
||||
// DPL must be >= RPL else #TS(selector)
|
||||
// AR byte must indicate PRESENT else #NP(selector)
|
||||
// load cache with new segment descriptor and set valid bit
|
||||
|
||||
// CS
|
||||
if ((raw_cs_selector & 0xfffc) != 0) {
|
||||
bx_bool good = fetch_raw_descriptor2(&cs_selector, &dword1, &dword2);
|
||||
if (!good) {
|
||||
BX_ERROR(("task_switch(exception after commit point): bad CS fetch"));
|
||||
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &cs_descriptor);
|
||||
|
||||
// CS descriptor AR byte must indicate code segment else #TS(CS)
|
||||
if (cs_descriptor.valid==0 || cs_descriptor.segment==0 ||
|
||||
IS_DATA_SEGMENT(cs_descriptor.type))
|
||||
{
|
||||
BX_ERROR(("task_switch(exception after commit point): CS not valid executable seg"));
|
||||
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// if non-conforming then DPL must equal selector RPL else #TS(CS)
|
||||
if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) &&
|
||||
cs_descriptor.dpl != cs_selector.rpl)
|
||||
{
|
||||
BX_ERROR(("task_switch(exception after commit point): non-conforming: CS.dpl!=CS.RPL"));
|
||||
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// if conforming then DPL must be <= selector RPL else #TS(CS)
|
||||
if (IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) &&
|
||||
cs_descriptor.dpl > cs_selector.rpl)
|
||||
{
|
||||
BX_ERROR(("task_switch(exception after commit point): conforming: CS.dpl>RPL"));
|
||||
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
// Code segment is present in memory, else #NP(new code segment)
|
||||
if (! IS_PRESENT(cs_descriptor)) {
|
||||
BX_ERROR(("task_switch(exception after commit point): CS.p==0"));
|
||||
exception(BX_NP_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
touch_segment(&cs_selector, &cs_descriptor);
|
||||
|
||||
#ifdef BX_SUPPORT_CS_LIMIT_DEMOTION
|
||||
// Handle special case of CS.LIMIT demotion (new descriptor limit is
|
||||
// smaller than current one)
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled > cs_descriptor.u.segment.limit_scaled)
|
||||
BX_CPU_THIS_PTR iCache.flushICacheEntries();
|
||||
#endif
|
||||
|
||||
// All checks pass, fill in shadow cache
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache = cs_descriptor;
|
||||
}
|
||||
else {
|
||||
// If new cs selector is null #TS(CS)
|
||||
BX_ERROR(("task_switch(exception after commit point): CS NULL"));
|
||||
exception(BX_TS_EXCEPTION, raw_cs_selector & 0xfffc);
|
||||
}
|
||||
|
||||
updateFetchModeMask(/* CS reloaded */);
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck(); // task switch, CPL was modified
|
||||
#endif
|
||||
}
|
||||
|
||||
if (tss_descriptor->type >= 9 && (trap_word & 0x1)) {
|
||||
BX_CPU_THIS_PTR debug_trap |= BX_DEBUG_TRAP_TASK_SWITCH_BIT; // BT flag
|
||||
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
|
||||
BX_INFO(("task_switch: T bit set in new TSS"));
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
handleSseModeChange(); /* CR0.TS changes */
|
||||
#endif
|
||||
|
||||
//
|
||||
// Step 12: Begin execution of new task.
|
||||
//
|
||||
BX_DEBUG(("TASKING: LEAVE"));
|
||||
}
|
||||
|
||||
void BX_CPU_C::task_switch_load_selector(bx_segment_reg_t *seg,
|
||||
bx_selector_t *selector, Bit16u raw_selector, Bit8u cs_rpl)
|
||||
{
|
||||
bx_descriptor_t descriptor;
|
||||
Bit32u dword1, dword2;
|
||||
|
||||
// NULL selector is OK, will leave cache invalid
|
||||
if ((raw_selector & 0xfffc) != 0)
|
||||
{
|
||||
bx_bool good = fetch_raw_descriptor2(selector, &dword1, &dword2);
|
||||
if (!good) {
|
||||
BX_ERROR(("task_switch(%s): bad selector fetch !", strseg(seg)));
|
||||
exception(BX_TS_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
parse_descriptor(dword1, dword2, &descriptor);
|
||||
|
||||
/* AR byte must indicate data or readable code segment else #TS(selector) */
|
||||
if (descriptor.segment==0 || (IS_CODE_SEGMENT(descriptor.type) &&
|
||||
IS_CODE_SEGMENT_READABLE(descriptor.type) == 0))
|
||||
{
|
||||
BX_ERROR(("task_switch(%s): not data or readable code !", strseg(seg)));
|
||||
exception(BX_TS_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
/* If data or non-conforming code, then both the RPL and the CPL
|
||||
* must be less than or equal to DPL in AR byte else #GP(selector) */
|
||||
if (IS_DATA_SEGMENT(descriptor.type) ||
|
||||
IS_CODE_SEGMENT_NON_CONFORMING(descriptor.type))
|
||||
{
|
||||
if ((selector->rpl > descriptor.dpl) || (cs_rpl > descriptor.dpl)) {
|
||||
BX_ERROR(("load_seg_reg(%s): RPL & CPL must be <= DPL", strseg(seg)));
|
||||
exception(BX_TS_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
}
|
||||
|
||||
if (! IS_PRESENT(descriptor)) {
|
||||
BX_ERROR(("task_switch(%s): descriptor not present !", strseg(seg)));
|
||||
exception(BX_NP_EXCEPTION, raw_selector & 0xfffc);
|
||||
}
|
||||
|
||||
touch_segment(selector, &descriptor);
|
||||
|
||||
// All checks pass, fill in shadow cache
|
||||
seg->cache = descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPU_C::get_SS_ESP_from_TSS(unsigned pl, Bit16u *ss, Bit32u *esp)
|
||||
{
|
||||
if (BX_CPU_THIS_PTR tr.cache.valid==0)
|
||||
BX_PANIC(("get_SS_ESP_from_TSS: TR.cache invalid"));
|
||||
|
||||
if (BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_AVAIL_386_TSS ||
|
||||
BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_BUSY_386_TSS)
|
||||
{
|
||||
// 32-bit TSS
|
||||
Bit32u TSSstackaddr = 8*pl + 4;
|
||||
if ((TSSstackaddr+7) > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
|
||||
BX_DEBUG(("get_SS_ESP_from_TSS(386): TSSstackaddr > TSS.LIMIT"));
|
||||
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
|
||||
}
|
||||
*ss = system_read_word (BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr + 4);
|
||||
*esp = system_read_dword(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr);
|
||||
}
|
||||
else if (BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_AVAIL_286_TSS ||
|
||||
BX_CPU_THIS_PTR tr.cache.type==BX_SYS_SEGMENT_BUSY_286_TSS)
|
||||
{
|
||||
// 16-bit TSS
|
||||
Bit32u TSSstackaddr = 4*pl + 2;
|
||||
if ((TSSstackaddr+3) > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
|
||||
BX_DEBUG(("get_SS_ESP_from_TSS(286): TSSstackaddr > TSS.LIMIT"));
|
||||
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
|
||||
}
|
||||
*ss = system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr + 2);
|
||||
*esp = (Bit32u) system_read_word(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr);
|
||||
}
|
||||
else {
|
||||
BX_PANIC(("get_SS_ESP_from_TSS: TR is bogus type (%u)", (unsigned) BX_CPU_THIS_PTR tr.cache.type));
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
Bit64u BX_CPU_C::get_RSP_from_TSS(unsigned pl)
|
||||
{
|
||||
if (BX_CPU_THIS_PTR tr.cache.valid==0)
|
||||
BX_PANIC(("get_RSP_from_TSS: TR.cache invalid"));
|
||||
|
||||
// 32-bit TSS
|
||||
Bit32u TSSstackaddr = 8*pl + 4;
|
||||
if ((TSSstackaddr+7) > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
|
||||
BX_DEBUG(("get_RSP_from_TSS(): TSSstackaddr > TSS.LIMIT"));
|
||||
exception(BX_TS_EXCEPTION, BX_CPU_THIS_PTR tr.selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
Bit64u rsp = system_read_qword(BX_CPU_THIS_PTR tr.cache.u.segment.base + TSSstackaddr);
|
||||
|
||||
if (! IsCanonical(rsp)) {
|
||||
BX_ERROR(("get_RSP_from_TSS: canonical address failure 0x%08x%08x", GET32H(rsp), GET32L(rsp)));
|
||||
exception(BX_SS_EXCEPTION, BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value & 0xfffc);
|
||||
}
|
||||
|
||||
return rsp;
|
||||
}
|
||||
#endif // #if BX_SUPPORT_X86_64
|
||||
52
simulators/bochs/cpu/todo
Executable file
52
simulators/bochs/cpu/todo
Executable file
@ -0,0 +1,52 @@
|
||||
TODO (know issues in CPU model):
|
||||
-------------------------------
|
||||
|
||||
[!] The following 3DNow! instructions still not implemented:
|
||||
PF2IW_PqQq
|
||||
PFNACC_PqQq
|
||||
PFPNACC_PqQq
|
||||
PFCMPGE_PqQq
|
||||
PFCMPGT_PqQq
|
||||
PFCMPEQ_PqQq
|
||||
PFMIN_PqQq
|
||||
PFMAX_PqQq
|
||||
PFRCP_PqQq
|
||||
PFRSQRT_PqQq
|
||||
PFSUB_PqQq
|
||||
PFSUBR_PqQq
|
||||
PFADD_PqQq
|
||||
PFACC_PqQq,
|
||||
PFMUL_PqQq
|
||||
PFRCPIT1_PqQq
|
||||
PFRSQIT1_PqQq
|
||||
PFRCPIT2_PqQq
|
||||
|
||||
[!] CPUID does not report 3DNow! instruction set
|
||||
|
||||
[!] Some of APIC functionality still not implemented, for example
|
||||
|
||||
- LVT pins handling
|
||||
- Filter interrupts according processor priority (PPR)
|
||||
|
||||
[!] REP NOP is PAUSE (on P4/XEON)
|
||||
|
||||
When running in SMP mode, this means that we are in a spin loop.
|
||||
This processor should yield to the other one, as we are anyhow waiting
|
||||
for a lock, and any other processor is responsible for this.
|
||||
|
||||
[!] 32-bit linear address wrap when executing in legacy mode might be
|
||||
not implemented correctly for system memory accesses (like descriptor
|
||||
tables and etc)
|
||||
|
||||
[!] AMD and Intel x86_64 implementations are different.
|
||||
Currently Bochs emulation is according to Intel version.
|
||||
Do we need to support both ?
|
||||
|
||||
[!] More flexible CPUID - vendor and etc
|
||||
|
||||
[!] VMX:
|
||||
|
||||
- Dual-monitor treatment of SMIs and SMM not implemented yet
|
||||
- VMENTER to not-active state not supported yet
|
||||
|
||||
[!] SSE4A, SMX, SVM, AVX
|
||||
263
simulators/bochs/cpu/vm8086.cc
Normal file
263
simulators/bochs/cpu/vm8086.cc
Normal file
@ -0,0 +1,263 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (C) 2001-2009 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 B 02110-1301 USA
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
//
|
||||
// Notes:
|
||||
//
|
||||
// The high bits of the 32bit eip image are ignored by
|
||||
// the IRET to VM. The high bits of the 32bit esp image
|
||||
// are loaded into ESP. A subsequent push uses
|
||||
// only the low 16bits since it's in VM. In neither case
|
||||
// did a protection fault occur during actual tests. This
|
||||
// is contrary to the Intel docs which claim a #GP for
|
||||
// eIP out of code limits.
|
||||
//
|
||||
// IRET to VM does affect IOPL, IF, VM, and RF
|
||||
//
|
||||
|
||||
#if BX_CPU_LEVEL >= 3
|
||||
|
||||
void BX_CPU_C::stack_return_to_v86(Bit32u new_eip, Bit32u raw_cs_selector, Bit32u flags32)
|
||||
{
|
||||
Bit32u temp_ESP, new_esp;
|
||||
Bit16u raw_es_selector, raw_ds_selector, raw_fs_selector,
|
||||
raw_gs_selector, raw_ss_selector;
|
||||
|
||||
// Must be 32bit effective opsize, VM is set in upper 16bits of eFLAGS
|
||||
// and CPL = 0 to get here
|
||||
|
||||
// ----------------
|
||||
// | | OLD GS | eSP+32
|
||||
// | | OLD FS | eSP+28
|
||||
// | | OLD DS | eSP+24
|
||||
// | | OLD ES | eSP+20
|
||||
// | | OLD SS | eSP+16
|
||||
// | OLD ESP | eSP+12
|
||||
// | OLD EFLAGS | eSP+8
|
||||
// | | OLD CS | eSP+4
|
||||
// | OLD EIP | eSP+0
|
||||
// ----------------
|
||||
|
||||
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b)
|
||||
temp_ESP = ESP;
|
||||
else
|
||||
temp_ESP = SP;
|
||||
|
||||
// load SS:ESP from stack
|
||||
new_esp = read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+12);
|
||||
raw_ss_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+16);
|
||||
|
||||
// load ES,DS,FS,GS from stack
|
||||
raw_es_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+20);
|
||||
raw_ds_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+24);
|
||||
raw_fs_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+28);
|
||||
raw_gs_selector = (Bit16u) read_virtual_dword_32(BX_SEG_REG_SS, temp_ESP+32);
|
||||
|
||||
writeEFlags(flags32, EFlagsValidMask);
|
||||
|
||||
// load CS:IP from stack; already read and passed as args
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = raw_cs_selector;
|
||||
EIP = new_eip & 0xffff;
|
||||
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = raw_es_selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = raw_ds_selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_FS].selector.value = raw_fs_selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_GS].selector.value = raw_gs_selector;
|
||||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = raw_ss_selector;
|
||||
ESP = new_esp; // full 32 bit are loaded
|
||||
|
||||
init_v8086_mode();
|
||||
}
|
||||
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
#define BX_CR4_VME_ENABLED (BX_CPU_THIS_PTR cr4.get_VME())
|
||||
#else
|
||||
#define BX_CR4_VME_ENABLED (0)
|
||||
#endif
|
||||
|
||||
void BX_CPU_C::iret16_stack_return_from_v86(bxInstruction_c *i)
|
||||
{
|
||||
if ((BX_CPU_THIS_PTR get_IOPL() < 3) && (BX_CR4_VME_ENABLED == 0)) {
|
||||
// trap to virtual 8086 monitor
|
||||
BX_DEBUG(("IRET in vm86 with IOPL != 3, VME = 0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit16u ip, cs_raw, flags16;
|
||||
|
||||
ip = pop_16();
|
||||
cs_raw = pop_16();
|
||||
flags16 = pop_16();
|
||||
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_VME() && BX_CPU_THIS_PTR get_IOPL() < 3)
|
||||
{
|
||||
if (((flags16 & EFlagsIFMask) && BX_CPU_THIS_PTR get_VIP()) ||
|
||||
(flags16 & EFlagsTFMask))
|
||||
{
|
||||
BX_DEBUG(("iret16_stack_return_from_v86(): #GP(0) in VME mode"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = (Bit32u) ip;
|
||||
|
||||
// IF, IOPL unchanged, EFLAGS.VIF = TMP_FLAGS.IF
|
||||
Bit32u changeMask = EFlagsOSZAPCMask | EFlagsTFMask |
|
||||
EFlagsDFMask | EFlagsNTMask | EFlagsVIFMask;
|
||||
Bit32u flags32 = (Bit32u) flags16;
|
||||
if (flags16 & EFlagsIFMask) flags32 |= EFlagsVIFMask;
|
||||
writeEFlags(flags32, changeMask);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], cs_raw);
|
||||
EIP = (Bit32u) ip;
|
||||
write_flags(flags16, /*IOPL*/ 0, /*IF*/ 1);
|
||||
}
|
||||
|
||||
void BX_CPU_C::iret32_stack_return_from_v86(bxInstruction_c *i)
|
||||
{
|
||||
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
|
||||
// trap to virtual 8086 monitor
|
||||
BX_DEBUG(("IRET in vm86 with IOPL != 3, VME = 0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit32u eip, cs_raw, flags32;
|
||||
// Build a mask of the following bits:
|
||||
// ID,VIP,VIF,AC,VM,RF,x,NT,IOPL,OF,DF,IF,TF,SF,ZF,x,AF,x,PF,x,CF
|
||||
Bit32u change_mask = EFlagsOSZAPCMask | EFlagsTFMask | EFlagsIFMask
|
||||
| EFlagsDFMask | EFlagsNTMask | EFlagsRFMask;
|
||||
|
||||
#if BX_CPU_LEVEL >= 4
|
||||
change_mask |= (EFlagsIDMask | EFlagsACMask); // ID/AC
|
||||
#endif
|
||||
|
||||
eip = pop_32();
|
||||
cs_raw = pop_32();
|
||||
flags32 = pop_32();
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) cs_raw);
|
||||
EIP = eip;
|
||||
// VIF, VIP, VM, IOPL unchanged
|
||||
writeEFlags(flags32, change_mask);
|
||||
}
|
||||
|
||||
int BX_CPU_C::v86_redirect_interrupt(Bit8u vector)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 5
|
||||
if (BX_CPU_THIS_PTR cr4.get_VME())
|
||||
{
|
||||
bx_address tr_base = BX_CPU_THIS_PTR tr.cache.u.segment.base;
|
||||
if (BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled < 103) {
|
||||
BX_ERROR(("INT_Ib(): TR.limit < 103 in VME"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit32u io_base = system_read_word(tr_base + 102), offset = io_base - 32 + (vector >> 3);
|
||||
if (offset > BX_CPU_THIS_PTR tr.cache.u.segment.limit_scaled) {
|
||||
BX_ERROR(("INT_Ib(): failed to fetch VME redirection bitmap"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
Bit8u vme_redirection_bitmap = system_read_byte(tr_base + offset);
|
||||
if (!(vme_redirection_bitmap & (1 << (vector & 7))))
|
||||
{
|
||||
// redirect interrupt through virtual-mode idt
|
||||
Bit16u temp_flags = (Bit16u) read_eflags();
|
||||
|
||||
Bit16u temp_CS = system_read_word(vector*4 + 2);
|
||||
Bit16u temp_IP = system_read_word(vector*4);
|
||||
|
||||
if (BX_CPU_THIS_PTR get_IOPL() < 3) {
|
||||
temp_flags |= EFlagsIOPLMask;
|
||||
if (BX_CPU_THIS_PTR get_VIF())
|
||||
temp_flags |= EFlagsIFMask;
|
||||
else
|
||||
temp_flags &= ~EFlagsIFMask;
|
||||
}
|
||||
|
||||
Bit16u old_IP = IP;
|
||||
Bit16u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value;
|
||||
|
||||
push_16(temp_flags);
|
||||
// push return address onto new stack
|
||||
push_16(old_CS);
|
||||
push_16(old_IP);
|
||||
|
||||
load_seg_reg(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS], (Bit16u) temp_CS);
|
||||
EIP = temp_IP;
|
||||
|
||||
BX_CPU_THIS_PTR clear_TF();
|
||||
BX_CPU_THIS_PTR clear_RF();
|
||||
if (BX_CPU_THIS_PTR get_IOPL() == 3)
|
||||
BX_CPU_THIS_PTR clear_IF();
|
||||
else
|
||||
BX_CPU_THIS_PTR clear_VIF();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// interrupt is not redirected or VME is OFF
|
||||
if (BX_CPU_THIS_PTR get_IOPL() < 3)
|
||||
{
|
||||
BX_DEBUG(("INT_Ib(): Interrupt cannot be redirected, generate #GP(0)"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BX_CPU_C::init_v8086_mode(void)
|
||||
{
|
||||
for(unsigned sreg = 0; sreg < 6; sreg++) {
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.valid = SegValidCache | SegAccessROK | SegAccessWOK;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.p = 1;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.dpl = 3;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.segment = 1;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.type = BX_DATA_READ_WRITE_ACCESSED;
|
||||
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.base =
|
||||
BX_CPU_THIS_PTR sregs[sreg].selector.value << 4;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.limit_scaled = 0xffff;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.g = 0;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.d_b = 0;
|
||||
BX_CPU_THIS_PTR sregs[sreg].cache.u.segment.avl = 0;
|
||||
BX_CPU_THIS_PTR sregs[sreg].selector.rpl = 3;
|
||||
}
|
||||
|
||||
handleCpuModeChange();
|
||||
|
||||
#if BX_CPU_LEVEL >= 4 && BX_SUPPORT_ALIGNMENT_CHECK
|
||||
handleAlignmentCheck(/* CPL change */);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* BX_CPU_LEVEL >= 3 */
|
||||
324
simulators/bochs/cpu/vmcs.cc
Executable file
324
simulators/bochs/cpu/vmcs.cc
Executable file
@ -0,0 +1,324 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
|
||||
static unsigned vmcs_map[16][1+VMX_HIGHEST_VMCS_ENCODING];
|
||||
|
||||
void BX_CPU_C::init_VMCS(void)
|
||||
{
|
||||
static bx_bool vmcs_map_ready = 0;
|
||||
unsigned type, field;
|
||||
|
||||
if (vmcs_map_ready) return;
|
||||
vmcs_map_ready = 1;
|
||||
|
||||
for (type=0; type<16; type++) {
|
||||
for (field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
|
||||
vmcs_map[type][field] = 0xffffffff;
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
// try to build generic VMCS map
|
||||
for (type=0; type<16; type++) {
|
||||
for (field=0; field <= VMX_HIGHEST_VMCS_ENCODING; field++) {
|
||||
unsigned encoding = ((type & 0xc) << 11) + ((type & 3) << 10) + field;
|
||||
if (vmcs_map[type][field] != 0xffffffff) {
|
||||
BX_PANIC(("VMCS type %d field %d (encoding = 0x%08x) is already initialized", type, field, encoding));
|
||||
}
|
||||
if (vmcs_field_supported(encoding)) {
|
||||
// allocate 64 fields (4 byte each) per type
|
||||
vmcs_map[type][field] = VMCS_DATA_OFFSET + (type*64 + field) * 4;
|
||||
if(vmcs_map[type][field] >= VMX_VMCS_AREA_SIZE) {
|
||||
BX_PANIC(("VMCS type %d field %d (encoding = 0x%08x) is out of VMCS boundaries", type, field, encoding));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
// define your own VMCS format
|
||||
#include "vmcs.h"
|
||||
#endif
|
||||
}
|
||||
|
||||
#define VMCS_ENCODING_RESERVED_BITS (0xffff9000)
|
||||
|
||||
unsigned vmcs_field_offset(Bit32u encoding)
|
||||
{
|
||||
if (encoding & VMCS_ENCODING_RESERVED_BITS)
|
||||
return 0xffffffff;
|
||||
|
||||
unsigned field = VMCS_FIELD(encoding);
|
||||
if (field >= VMX_HIGHEST_VMCS_ENCODING)
|
||||
return 0xffffffff;
|
||||
|
||||
return vmcs_map[VMCS_FIELD_INDEX(encoding)][field];
|
||||
}
|
||||
|
||||
bx_bool BX_CPU_C::vmcs_field_supported(Bit32u encoding)
|
||||
{
|
||||
switch(encoding)
|
||||
{
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
/* VMCS 16-bit control fields */
|
||||
/* binary 0000_00xx_xxxx_xxx0 */
|
||||
case VMCS_16BIT_CONTROL_VPID:
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* VMCS 16-bit guest-state fields */
|
||||
/* binary 0000_10xx_xxxx_xxx0 */
|
||||
case VMCS_16BIT_GUEST_ES_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_CS_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_SS_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_DS_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_FS_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_GS_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_LDTR_SELECTOR:
|
||||
case VMCS_16BIT_GUEST_TR_SELECTOR:
|
||||
return 1;
|
||||
|
||||
/* VMCS 16-bit host-state fields */
|
||||
/* binary 0000_11xx_xxxx_xxx0 */
|
||||
case VMCS_16BIT_HOST_ES_SELECTOR:
|
||||
case VMCS_16BIT_HOST_CS_SELECTOR:
|
||||
case VMCS_16BIT_HOST_SS_SELECTOR:
|
||||
case VMCS_16BIT_HOST_DS_SELECTOR:
|
||||
case VMCS_16BIT_HOST_FS_SELECTOR:
|
||||
case VMCS_16BIT_HOST_GS_SELECTOR:
|
||||
case VMCS_16BIT_HOST_TR_SELECTOR:
|
||||
return 1;
|
||||
|
||||
/* VMCS 32_bit control fields */
|
||||
/* binary 0100_00xx_xxxx_xxx0 */
|
||||
case VMCS_32BIT_CONTROL_PIN_BASED_EXEC_CONTROLS:
|
||||
case VMCS_32BIT_CONTROL_PROCESSOR_BASED_VMEXEC_CONTROLS:
|
||||
case VMCS_32BIT_CONTROL_EXECUTION_BITMAP:
|
||||
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MASK:
|
||||
case VMCS_32BIT_CONTROL_PAGE_FAULT_ERR_CODE_MATCH:
|
||||
case VMCS_32BIT_CONTROL_CR3_TARGET_COUNT:
|
||||
case VMCS_32BIT_CONTROL_VMEXIT_CONTROLS:
|
||||
case VMCS_32BIT_CONTROL_VMEXIT_MSR_STORE_COUNT:
|
||||
case VMCS_32BIT_CONTROL_VMEXIT_MSR_LOAD_COUNT:
|
||||
case VMCS_32BIT_CONTROL_VMENTRY_CONTROLS:
|
||||
case VMCS_32BIT_CONTROL_VMENTRY_MSR_LOAD_COUNT:
|
||||
case VMCS_32BIT_CONTROL_VMENTRY_INTERRUPTION_INFO:
|
||||
case VMCS_32BIT_CONTROL_VMENTRY_EXCEPTION_ERR_CODE:
|
||||
case VMCS_32BIT_CONTROL_VMENTRY_INSTRUCTION_LENGTH:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case VMCS_32BIT_CONTROL_TPR_THRESHOLD:
|
||||
#endif
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case VMCS_32BIT_CONTROL_SECONDARY_VMEXEC_CONTROLS:
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
/* VMCS 32-bit read only data fields */
|
||||
/* binary 0100_01xx_xxxx_xxx0 */
|
||||
case VMCS_32BIT_INSTRUCTION_ERROR:
|
||||
case VMCS_32BIT_VMEXIT_REASON:
|
||||
case VMCS_32BIT_VMEXIT_INTERRUPTION_INFO:
|
||||
case VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE:
|
||||
case VMCS_32BIT_IDT_VECTORING_INFO:
|
||||
case VMCS_32BIT_IDT_VECTORING_ERR_CODE:
|
||||
case VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH:
|
||||
case VMCS_32BIT_VMEXIT_INSTRUCTION_INFO:
|
||||
return 1;
|
||||
|
||||
/* VMCS 32-bit guest-state fields */
|
||||
/* binary 0100_10xx_xxxx_xxx0 */
|
||||
case VMCS_32BIT_GUEST_ES_LIMIT:
|
||||
case VMCS_32BIT_GUEST_CS_LIMIT:
|
||||
case VMCS_32BIT_GUEST_SS_LIMIT:
|
||||
case VMCS_32BIT_GUEST_DS_LIMIT:
|
||||
case VMCS_32BIT_GUEST_FS_LIMIT:
|
||||
case VMCS_32BIT_GUEST_GS_LIMIT:
|
||||
case VMCS_32BIT_GUEST_LDTR_LIMIT:
|
||||
case VMCS_32BIT_GUEST_TR_LIMIT:
|
||||
case VMCS_32BIT_GUEST_GDTR_LIMIT:
|
||||
case VMCS_32BIT_GUEST_IDTR_LIMIT:
|
||||
case VMCS_32BIT_GUEST_ES_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_CS_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_SS_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_DS_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_FS_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_GS_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_LDTR_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_TR_ACCESS_RIGHTS:
|
||||
case VMCS_32BIT_GUEST_INTERRUPTIBILITY_STATE:
|
||||
case VMCS_32BIT_GUEST_ACTIVITY_STATE:
|
||||
case VMCS_32BIT_GUEST_SMBASE:
|
||||
case VMCS_32BIT_GUEST_IA32_SYSENTER_CS_MSR:
|
||||
return 1;
|
||||
|
||||
/* VMCS 32-bit host-state fields */
|
||||
/* binary 0100_11xx_xxxx_xxx0 */
|
||||
case VMCS_32BIT_HOST_IA32_SYSENTER_CS_MSR:
|
||||
return 1;
|
||||
|
||||
/* VMCS 64-bit control fields */
|
||||
/* binary 0010_00xx_xxxx_xxx0 */
|
||||
case VMCS_64BIT_CONTROL_IO_BITMAP_A:
|
||||
case VMCS_64BIT_CONTROL_IO_BITMAP_A_HI:
|
||||
case VMCS_64BIT_CONTROL_IO_BITMAP_B:
|
||||
case VMCS_64BIT_CONTROL_IO_BITMAP_B_HI:
|
||||
case VMCS_64BIT_CONTROL_MSR_BITMAPS:
|
||||
case VMCS_64BIT_CONTROL_MSR_BITMAPS_HI:
|
||||
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR:
|
||||
case VMCS_64BIT_CONTROL_VMEXIT_MSR_STORE_ADDR_HI:
|
||||
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR:
|
||||
case VMCS_64BIT_CONTROL_VMEXIT_MSR_LOAD_ADDR_HI:
|
||||
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR:
|
||||
case VMCS_64BIT_CONTROL_VMENTRY_MSR_LOAD_ADDR_HI:
|
||||
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR:
|
||||
case VMCS_64BIT_CONTROL_EXECUTIVE_VMCS_PTR_HI:
|
||||
case VMCS_64BIT_CONTROL_TSC_OFFSET:
|
||||
case VMCS_64BIT_CONTROL_TSC_OFFSET_HI:
|
||||
#if BX_SUPPORT_X86_64
|
||||
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR:
|
||||
case VMCS_64BIT_CONTROL_VIRTUAL_APIC_PAGE_ADDR_HI:
|
||||
#endif
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case VMCS_64BIT_CONTROL_APIC_ACCESS_ADDR:
|
||||
case VMCS_64BIT_CONTROL_APIC_ACCESS_ADDR_HI:
|
||||
case VMCS_64BIT_CONTROL_EPTPTR:
|
||||
case VMCS_64BIT_CONTROL_EPTPTR_HI:
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
/* VMCS 64-bit read only data fields */
|
||||
/* binary 0010_01xx_xxxx_xxx0 */
|
||||
case VMCS_64BIT_GUEST_PHYSICAL_ADDR:
|
||||
case VMCS_64BIT_GUEST_PHYSICAL_ADDR_HI:
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* VMCS 64-bit guest state fields */
|
||||
/* binary 0010_10xx_xxxx_xxx0 */
|
||||
case VMCS_64BIT_GUEST_LINK_POINTER:
|
||||
case VMCS_64BIT_GUEST_LINK_POINTER_HI:
|
||||
case VMCS_64BIT_GUEST_IA32_DEBUGCTL:
|
||||
case VMCS_64BIT_GUEST_IA32_DEBUGCTL_HI:
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case VMCS_64BIT_GUEST_IA32_PAT:
|
||||
case VMCS_64BIT_GUEST_IA32_PAT_HI:
|
||||
case VMCS_64BIT_GUEST_IA32_EFER:
|
||||
case VMCS_64BIT_GUEST_IA32_EFER_HI:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE0:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE0_HI:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE1:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE1_HI:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE2:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE2_HI:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE3:
|
||||
case VMCS_64BIT_GUEST_IA32_PDPTE3_HI:
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
/* VMCS 64-bit host state fields */
|
||||
/* binary 0010_11xx_xxxx_xxx0 */
|
||||
case VMCS_64BIT_HOST_IA32_PAT:
|
||||
case VMCS_64BIT_HOST_IA32_PAT_HI:
|
||||
case VMCS_64BIT_HOST_IA32_EFER:
|
||||
case VMCS_64BIT_HOST_IA32_EFER_HI:
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
/* VMCS natural width control fields */
|
||||
/* binary 0110_00xx_xxxx_xxx0 */
|
||||
case VMCS_CONTROL_CR0_GUEST_HOST_MASK:
|
||||
case VMCS_CONTROL_CR4_GUEST_HOST_MASK:
|
||||
case VMCS_CONTROL_CR0_READ_SHADOW:
|
||||
case VMCS_CONTROL_CR4_READ_SHADOW:
|
||||
case VMCS_CR3_TARGET0:
|
||||
case VMCS_CR3_TARGET1:
|
||||
case VMCS_CR3_TARGET2:
|
||||
case VMCS_CR3_TARGET3:
|
||||
return 1;
|
||||
|
||||
/* VMCS natural width read only data fields */
|
||||
/* binary 0110_01xx_xxxx_xxx0 */
|
||||
case VMCS_VMEXIT_QUALIFICATION:
|
||||
case VMCS_IO_RCX:
|
||||
case VMCS_IO_RSI:
|
||||
case VMCS_IO_RDI:
|
||||
case VMCS_IO_RIP:
|
||||
case VMCS_GUEST_LINEAR_ADDR:
|
||||
return 1;
|
||||
|
||||
/* VMCS natural width guest state fields */
|
||||
/* binary 0110_10xx_xxxx_xxx0 */
|
||||
case VMCS_GUEST_CR0:
|
||||
case VMCS_GUEST_CR3:
|
||||
case VMCS_GUEST_CR4:
|
||||
case VMCS_GUEST_ES_BASE:
|
||||
case VMCS_GUEST_CS_BASE:
|
||||
case VMCS_GUEST_SS_BASE:
|
||||
case VMCS_GUEST_DS_BASE:
|
||||
case VMCS_GUEST_FS_BASE:
|
||||
case VMCS_GUEST_GS_BASE:
|
||||
case VMCS_GUEST_LDTR_BASE:
|
||||
case VMCS_GUEST_TR_BASE:
|
||||
case VMCS_GUEST_GDTR_BASE:
|
||||
case VMCS_GUEST_IDTR_BASE:
|
||||
case VMCS_GUEST_DR7:
|
||||
case VMCS_GUEST_RSP:
|
||||
case VMCS_GUEST_RIP:
|
||||
case VMCS_GUEST_RFLAGS:
|
||||
case VMCS_GUEST_PENDING_DBG_EXCEPTIONS:
|
||||
case VMCS_GUEST_IA32_SYSENTER_ESP_MSR:
|
||||
case VMCS_GUEST_IA32_SYSENTER_EIP_MSR:
|
||||
return 1;
|
||||
|
||||
/* VMCS natural width host state fields */
|
||||
/* binary 0110_11xx_xxxx_xxx0 */
|
||||
case VMCS_HOST_CR0:
|
||||
case VMCS_HOST_CR3:
|
||||
case VMCS_HOST_CR4:
|
||||
case VMCS_HOST_FS_BASE:
|
||||
case VMCS_HOST_GS_BASE:
|
||||
case VMCS_HOST_TR_BASE:
|
||||
case VMCS_HOST_GDTR_BASE:
|
||||
case VMCS_HOST_IDTR_BASE:
|
||||
case VMCS_HOST_IA32_SYSENTER_ESP_MSR:
|
||||
case VMCS_HOST_IA32_SYSENTER_EIP_MSR:
|
||||
case VMCS_HOST_RSP:
|
||||
case VMCS_HOST_RIP:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
792
simulators/bochs/cpu/vmexit.cc
Executable file
792
simulators/bochs/cpu/vmexit.cc
Executable file
@ -0,0 +1,792 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2009-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
// Make life easier for merging cpu64 and cpu32 code.
|
||||
#define RIP EIP
|
||||
#define RDI EDI
|
||||
#define RSI ESI
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_VMX
|
||||
|
||||
Bit32u gen_instruction_info(bxInstruction_c *i, Bit32u reason)
|
||||
{
|
||||
Bit32u instr_info = 0;
|
||||
|
||||
switch(reason) {
|
||||
case VMX_VMEXIT_VMREAD:
|
||||
case VMX_VMEXIT_VMWRITE:
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case VMX_VMEXIT_GDTR_IDTR_ACCESS:
|
||||
case VMX_VMEXIT_LDTR_TR_ACCESS:
|
||||
case VMX_VMEXIT_INVEPT:
|
||||
case VMX_VMEXIT_INVVPID:
|
||||
#endif
|
||||
instr_info |= i->nnn() << 28;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
// instruction information field format
|
||||
// --------------------------------------
|
||||
//
|
||||
// [.2:.0] | Memory operand scale field (encoded)
|
||||
// [.6:.3] | Reg1, undefined when memory operand
|
||||
// [.9:.7] | Memory operand address size
|
||||
// [10:10] | Memory/Register format (0 - mem, 1 - reg)
|
||||
// [14:11] | Reserved
|
||||
// [17:15] | Memory operand segment register field
|
||||
// [21:18] | Memory operand index field
|
||||
// [22:22] | Memory operand index field invalid
|
||||
// [26:23] | Memory operand base field
|
||||
// [27:27] | Memory operand base field invalid
|
||||
// [31:28] | Reg2, if exists
|
||||
//
|
||||
if (i->modC0()) {
|
||||
// reg/reg format
|
||||
instr_info |= (1 << 10) | (i->rm() << 3);
|
||||
}
|
||||
else {
|
||||
// memory format
|
||||
if (i->as64L())
|
||||
instr_info |= 1 << 8;
|
||||
else if (i->as32L())
|
||||
instr_info |= 1 << 7;
|
||||
|
||||
instr_info |= i->seg() << 15;
|
||||
|
||||
if (i->sibIndex() != BX_NIL_REGISTER)
|
||||
instr_info |= i->sibScale() | (i->sibIndex() << 18);
|
||||
else
|
||||
instr_info |= 1 << 22; // index invalid
|
||||
|
||||
if (i->sibBase() != BX_NIL_REGISTER)
|
||||
instr_info |= i->sibBase() << 23;
|
||||
else
|
||||
instr_info |= 1 << 27; // base invalid
|
||||
}
|
||||
|
||||
return instr_info;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_Instruction(bxInstruction_c *i, Bit32u reason)
|
||||
{
|
||||
Bit64u qualification = 0;
|
||||
Bit32u instr_info = 0;
|
||||
|
||||
switch(reason) {
|
||||
case VMX_VMEXIT_VMCALL:
|
||||
case VMX_VMEXIT_VMLAUNCH:
|
||||
case VMX_VMEXIT_VMRESUME:
|
||||
case VMX_VMEXIT_VMXOFF:
|
||||
// do not have VMEXIT instruction info
|
||||
break;
|
||||
case VMX_VMEXIT_VMREAD:
|
||||
case VMX_VMEXIT_VMWRITE:
|
||||
case VMX_VMEXIT_VMPTRLD:
|
||||
case VMX_VMEXIT_VMPTRST:
|
||||
case VMX_VMEXIT_VMCLEAR:
|
||||
case VMX_VMEXIT_VMXON:
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
case VMX_VMEXIT_GDTR_IDTR_ACCESS:
|
||||
case VMX_VMEXIT_LDTR_TR_ACCESS:
|
||||
case VMX_VMEXIT_INVEPT:
|
||||
case VMX_VMEXIT_INVVPID:
|
||||
#endif
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (long64_mode()) {
|
||||
qualification = (Bit64u) i->displ32s();
|
||||
if (i->sibBase() == BX_64BIT_REG_RIP)
|
||||
qualification += RIP;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
qualification = (Bit64u) ((Bit32u) i->displ32s());
|
||||
|
||||
instr_info = gen_instruction_info(i, reason);
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_INFO, instr_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("VMexit_Instruction reason %d", reason));
|
||||
}
|
||||
|
||||
VMexit(i, reason, qualification);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_HLT(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_HLT_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: HLT"));
|
||||
VMexit(i, VMX_VMEXIT_HLT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_PAUSE(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_PAUSE_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: PAUSE"));
|
||||
VMexit(i, VMX_VMEXIT_PAUSE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_INVLPG(bxInstruction_c *i, bx_address laddr)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_INVLPG_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: INVLPG 0x" FMT_ADDRX, laddr));
|
||||
VMexit(i, VMX_VMEXIT_INVLPG, laddr);
|
||||
}
|
||||
}
|
||||
|
||||
Bit64s BX_CPU_C::VMX_TSC_Offset(void)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_TSC_OFFSET))
|
||||
return (Bit64s) BX_CPU_THIS_PTR vmcs.tsc_offset;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDTSC(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDTSC_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: RDTSC"));
|
||||
VMexit(i, (i->getIaOpcode() == BX_IA_RDTSC) ? VMX_VMEXIT_RDTSC : VMX_VMEXIT_RDTSCP, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_RDPMC(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_RDPMC_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: RDPMC"));
|
||||
VMexit(i, VMX_VMEXIT_RDPMC, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_MONITOR_MWAIT
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MONITOR(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_MONITOR_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: MONITOR"));
|
||||
VMexit(i, VMX_VMEXIT_MONITOR, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_MWAIT(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_MWAIT_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: MWAIT"));
|
||||
VMexit(i, VMX_VMEXIT_MWAIT, BX_CPU_THIS_PTR monitor.armed);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void BX_CPU_C::VMexit_ExtInterrupt(void)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT)) {
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
if (! (vm->vmexit_ctrls & VMX_VMEXIT_CTRL1_INTA_ON_VMEXIT)) {
|
||||
// interrupt wasn't acknowledged and still pending, interruption info is invalid
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, 0);
|
||||
VMexit(0, VMX_VMEXIT_EXTERNAL_INTERRUPT, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPU_C::VMexit_Event(bxInstruction_c *i, unsigned type, unsigned vector, Bit16u errcode, bx_bool errcode_valid, Bit64u qualification)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
bx_bool vmexit = 0;
|
||||
VMX_vmexit_reason reason = VMX_VMEXIT_EXCEPTION_NMI;
|
||||
|
||||
switch(type) {
|
||||
case BX_EXTERNAL_INTERRUPT:
|
||||
reason = VMX_VMEXIT_EXTERNAL_INTERRUPT;
|
||||
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_EXTERNAL_INTERRUPT_VMEXIT))
|
||||
vmexit = 1;
|
||||
break;
|
||||
|
||||
case BX_NMI:
|
||||
if (PIN_VMEXIT(VMX_VM_EXEC_CTRL1_NMI_VMEXIT))
|
||||
vmexit = 1;
|
||||
break;
|
||||
|
||||
case BX_PRIVILEGED_SOFTWARE_INTERRUPT:
|
||||
case BX_SOFTWARE_EXCEPTION:
|
||||
case BX_HARDWARE_EXCEPTION:
|
||||
BX_ASSERT((vector < BX_CPU_HANDLED_EXCEPTIONS));
|
||||
if (vector == BX_PF_EXCEPTION) {
|
||||
// page faults are specially treated
|
||||
bx_bool err_match = ((errcode & vm->vm_pf_mask) == vm->vm_pf_match);
|
||||
bx_bool bitmap = (vm->vm_exceptions_bitmap >> BX_PF_EXCEPTION) & 1;
|
||||
vmexit = (err_match == bitmap);
|
||||
}
|
||||
else {
|
||||
vmexit = (vm->vm_exceptions_bitmap >> vector) & 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case BX_SOFTWARE_INTERRUPT:
|
||||
break; // no VMEXIT on software interrupt
|
||||
|
||||
default:
|
||||
BX_ERROR(("VMexit_Event: unknown event type %d", type));
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// VMExit interruption info
|
||||
// ----------------------------------------------------
|
||||
// [.7:.0] | Interrupt/Exception vector
|
||||
// [10:.8] | Interrupt/Exception type
|
||||
// [11:11] | error code pushed to the stack
|
||||
// [12:12] | NMI unblocking due to IRET
|
||||
// [30:13] | reserved
|
||||
// [31:31] | interruption info valid
|
||||
//
|
||||
|
||||
if (i) {
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_LENGTH, i->ilen());
|
||||
}
|
||||
|
||||
if (! vmexit) {
|
||||
// record IDT vectoring information
|
||||
vm->idt_vector_error_code = errcode;
|
||||
vm->idt_vector_info = vector | (type << 8);
|
||||
if (errcode_valid)
|
||||
vm->idt_vector_info |= (1 << 11); // error code delivered
|
||||
return;
|
||||
}
|
||||
|
||||
BX_ERROR(("VMEXIT: event vector 0x%02x type %d error code=0x%04x", vector, type, errcode));
|
||||
|
||||
// VMEXIT is not considered to occur during event delivery if it results
|
||||
// in a double fault exception that causes VMEXIT directly
|
||||
if (vector == BX_DF_EXCEPTION)
|
||||
BX_CPU_THIS_PTR in_event = 0; // clear in_event indication on #DF
|
||||
|
||||
if (vector == BX_DB_EXCEPTION) {
|
||||
// qualifcation for debug exceptions similar to debug_trap field
|
||||
qualification = BX_CPU_THIS_PTR debug_trap & 0x0000600f;
|
||||
}
|
||||
|
||||
// clear debug_trap field
|
||||
BX_CPU_THIS_PTR debug_trap = 0;
|
||||
BX_CPU_THIS_PTR inhibit_mask = 0;
|
||||
|
||||
Bit32u interruption_info = vector | (type << 8);
|
||||
if (errcode_valid)
|
||||
interruption_info |= (1 << 11); // error code delivered
|
||||
interruption_info |= (1 << 31); // valid
|
||||
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_INFO, interruption_info);
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INTERRUPTION_ERR_CODE, errcode);
|
||||
|
||||
VMexit(0, reason, qualification);
|
||||
}
|
||||
|
||||
void BX_CPU_C::VMexit_TripleFault(void)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
BX_ERROR(("VMEXIT: triple fault"));
|
||||
|
||||
// VMEXIT is not considered to occur during event delivery if it results
|
||||
// in a triple fault exception (that causes VMEXIT directly)
|
||||
BX_CPU_THIS_PTR in_event = 0;
|
||||
|
||||
VMexit(0, VMX_VMEXIT_TRIPLE_FAULT, 0);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_TaskSwitch(bxInstruction_c *i, Bit16u tss_selector, unsigned source)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
BX_ERROR(("VMEXIT: task switch"));
|
||||
|
||||
VMexit(i, VMX_VMEXIT_TASK_SWITCH, tss_selector | (source << 30));
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_SoftwareInterrupt(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_MSR(bxInstruction_c *i, unsigned op, Bit32u msr)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
bx_bool vmexit = 0;
|
||||
if (! VMEXIT(VMX_VM_EXEC_CTRL2_MSR_BITMAPS)) vmexit = 1;
|
||||
else {
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
Bit8u field;
|
||||
|
||||
if (msr & 0xC0000000) {
|
||||
if (msr > 0xC0001FFF) vmexit = 1;
|
||||
else {
|
||||
// check MSR-HI bitmaps
|
||||
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + 1024 + ((op == VMX_VMEXIT_RDMSR) ? 0 : 2048);
|
||||
access_read_physical(pAddr, 1, &field);
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMX_MSR_BITMAP_ACCESS | BX_READ, &field);
|
||||
if (field & (1 << (msr & 7)))
|
||||
vmexit = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (msr > 0x00001FFF) vmexit = 1;
|
||||
else {
|
||||
// check MSR-LO bitmaps
|
||||
bx_phy_address pAddr = vm->msr_bitmap_addr + (msr >> 3) + ((op == VMX_VMEXIT_RDMSR) ? 0 : 2048);
|
||||
access_read_physical(pAddr, 1, &field);
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 1, BX_VMX_MSR_BITMAP_ACCESS | BX_READ, &field);
|
||||
if (field & (1 << (msr & 7)))
|
||||
vmexit = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (vmexit) {
|
||||
BX_ERROR(("VMEXIT: %sMSR 0x%08x", (op == VMX_VMEXIT_RDMSR) ? "RD" : "WR", msr));
|
||||
VMexit(i, op, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#define VMX_VMEXIT_IO_PORTIN (1 << 3)
|
||||
#define VMX_VMEXIT_IO_INSTR_STRING (1 << 4)
|
||||
#define VMX_VMEXIT_IO_INSTR_REP (1 << 5)
|
||||
#define VMX_VMEXIT_IO_INSTR_IMM (1 << 6)
|
||||
|
||||
void BX_CPP_AttrRegparmN(3) BX_CPU_C::VMexit_IO(bxInstruction_c *i, unsigned port, unsigned len)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
BX_ASSERT((port <= 0xFFFF));
|
||||
|
||||
bool vmexit = 0;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_BITMAPS)) {
|
||||
// always VMEXIT on port "wrap around" case
|
||||
if ((port + len) > 0x10000) vmexit = 1;
|
||||
else {
|
||||
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.io_bitmap_addr[(port >> 15) & 1] + ((port & 0x7fff) >> 3);
|
||||
Bit16u bitmap;
|
||||
access_read_physical(pAddr, 2, (Bit8u*) &bitmap);
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 2, BX_VMX_IO_BITMAP_ACCESS | BX_READ, (Bit8u*) &bitmap);
|
||||
|
||||
unsigned mask = ((1 << len) - 1) << (port & 7);
|
||||
if (bitmap & mask) vmexit = 1;
|
||||
}
|
||||
}
|
||||
else if (VMEXIT(VMX_VM_EXEC_CTRL2_IO_VMEXIT)) vmexit = 1;
|
||||
|
||||
if (vmexit) {
|
||||
BX_ERROR(("VMEXIT: I/O port 0x%04x", port));
|
||||
|
||||
Bit32u qualification = 0;
|
||||
|
||||
switch(i->getIaOpcode()) {
|
||||
case BX_IA_IN_ALIb:
|
||||
case BX_IA_IN_AXIb:
|
||||
case BX_IA_IN_EAXIb:
|
||||
qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_IMM;
|
||||
break;
|
||||
|
||||
case BX_IA_OUT_IbAL:
|
||||
case BX_IA_OUT_IbAX:
|
||||
case BX_IA_OUT_IbEAX:
|
||||
qualification = VMX_VMEXIT_IO_INSTR_IMM;
|
||||
break;
|
||||
|
||||
case BX_IA_IN_ALDX:
|
||||
case BX_IA_IN_AXDX:
|
||||
case BX_IA_IN_EAXDX:
|
||||
qualification = VMX_VMEXIT_IO_PORTIN; // no immediate
|
||||
break;
|
||||
|
||||
case BX_IA_OUT_DXAL:
|
||||
case BX_IA_OUT_DXAX:
|
||||
case BX_IA_OUT_DXEAX:
|
||||
qualification = 0; // PORTOUT, no immediate
|
||||
break;
|
||||
|
||||
case BX_IA_REP_INSB_YbDX:
|
||||
case BX_IA_REP_INSW_YwDX:
|
||||
case BX_IA_REP_INSD_YdDX:
|
||||
qualification = VMX_VMEXIT_IO_PORTIN | VMX_VMEXIT_IO_INSTR_STRING;
|
||||
if (i->repUsedL())
|
||||
qualification |= VMX_VMEXIT_IO_INSTR_REP;
|
||||
break;
|
||||
|
||||
case BX_IA_REP_OUTSB_DXXb:
|
||||
case BX_IA_REP_OUTSW_DXXw:
|
||||
case BX_IA_REP_OUTSD_DXXd:
|
||||
qualification = VMX_VMEXIT_IO_INSTR_STRING; // PORTOUT
|
||||
if (i->repUsedL())
|
||||
qualification |= VMX_VMEXIT_IO_INSTR_REP;
|
||||
break;
|
||||
|
||||
default:
|
||||
BX_PANIC(("VMexit_IO: I/O instruction %s unknown", get_bx_opcode_name(i->getIaOpcode())));
|
||||
}
|
||||
|
||||
if (qualification & VMX_VMEXIT_IO_INSTR_STRING) {
|
||||
bx_address asize_mask = BX_CONST64(0xffffffffffffffff), laddr;
|
||||
if (! i->as64L()) {
|
||||
if (i->as32L()) asize_mask = 0xffffffff;
|
||||
else asize_mask = 0xffff;
|
||||
}
|
||||
|
||||
if (qualification & VMX_VMEXIT_IO_PORTIN)
|
||||
laddr = BX_CPU_THIS_PTR get_laddr(BX_SEG_REG_ES, RDI & asize_mask);
|
||||
else // PORTOUT
|
||||
laddr = BX_CPU_THIS_PTR get_laddr(i->seg(), RSI & asize_mask);
|
||||
|
||||
VMwrite64(VMCS_GUEST_LINEAR_ADDR, laddr);
|
||||
|
||||
Bit32u instruction_info = i->seg() << 15;
|
||||
if (i->as64L())
|
||||
instruction_info |= (1 << 8);
|
||||
else if (i->as32L())
|
||||
instruction_info |= (1 << 7);
|
||||
|
||||
VMwrite32(VMCS_32BIT_VMEXIT_INSTRUCTION_INFO, instruction_info);
|
||||
}
|
||||
|
||||
VMexit(i, VMX_VMEXIT_IO_INSTRUCTION, qualification | (len-1) | (port << 16));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
// Exit qualification for CR access
|
||||
// ----------------------------------------------------------------
|
||||
// [.3:.0] | Number of CR register (CR0, CR3, CR4, CR8)
|
||||
// [.5:.4] | CR access type (0 - MOV to CR, 1 - MOV from CR, 2 - CLTS, 3 - LMSW)
|
||||
// [.6:.6] | LMSW operand reg/mem (cleared for CR access and CLTS)
|
||||
// [.7:.7] | reserved
|
||||
// [11:.8] | Source Operand Register for CR access (cleared for CLTS and LMSW)
|
||||
// [15:12] | reserved
|
||||
// [31:16] | LMSW source data (cleared for CR access and CLTS)
|
||||
// [63:32] | reserved
|
||||
//
|
||||
|
||||
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CLTS(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return 0;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
if (vm->vm_cr0_mask & vm->vm_cr0_read_shadow & 0x8)
|
||||
{
|
||||
BX_ERROR(("VMEXIT: CLTS"));
|
||||
|
||||
// all rest of the fields cleared to zero
|
||||
Bit64u qualification = VMX_VMEXIT_CR_ACCESS_CLTS << 4;
|
||||
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
|
||||
if ((vm->vm_cr0_mask & 0x8) != 0 && (vm->vm_cr0_read_shadow & 0x8) == 0)
|
||||
return 1; /* do not clear CR0.TS */
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
Bit32u BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_LMSW(bxInstruction_c *i, Bit32u msw)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return msw;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
Bit32u mask = vm->vm_cr0_mask & 0xF; /* LMSW affects only low 4 bits */
|
||||
bx_bool vmexit = 0;
|
||||
|
||||
if ((mask & msw & 0x1) != 0 && (vm->vm_cr0_read_shadow & 0x1) == 0)
|
||||
vmexit = 1;
|
||||
|
||||
if ((mask & vm->vm_cr0_read_shadow & 0xE) != (mask & msw & 0xE))
|
||||
vmexit = 1;
|
||||
|
||||
if (vmexit) {
|
||||
BX_ERROR(("VMEXIT: CR0 write by LMSW of value 0x%04x", msw));
|
||||
|
||||
Bit64u qualification = VMX_VMEXIT_CR_ACCESS_LMSW << 4;
|
||||
qualification |= msw << 16;
|
||||
if (! i->modC0()) {
|
||||
qualification |= (1 << 6); // memory operand
|
||||
VMwrite64(VMCS_GUEST_LINEAR_ADDR, BX_CPU_THIS_PTR get_laddr(i->seg(), RMAddr(i)));
|
||||
}
|
||||
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
|
||||
// keep untouched all the bits set in CR0 mask
|
||||
return (BX_CPU_THIS_PTR cr0.get32() & mask) | (msw & ~mask);
|
||||
}
|
||||
|
||||
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR0_Write(bxInstruction_c *i, bx_address val)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
if ((vm->vm_cr0_mask & vm->vm_cr0_read_shadow) != (vm->vm_cr0_mask & val))
|
||||
{
|
||||
BX_ERROR(("VMEXIT: CR0 write"));
|
||||
Bit64u qualification = i->rm() << 8;
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
|
||||
// keep untouched all the bits set in CR0 mask
|
||||
return (BX_CPU_THIS_PTR cr0.get32() & vm->vm_cr0_mask) | (val & ~vm->vm_cr0_mask);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR3_Read(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_READ_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: CR3 read"));
|
||||
|
||||
Bit64u qualification = 3 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
|
||||
qualification |= (i->rm() << 8);
|
||||
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR3_Write(bxInstruction_c *i, bx_address val)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR3_WRITE_VMEXIT)) {
|
||||
for (unsigned n=0; n < vm->vm_cr3_target_cnt; n++) {
|
||||
if (vm->vm_cr3_target_value[n] == val) return;
|
||||
}
|
||||
|
||||
BX_ERROR(("VMEXIT: CR3 write"));
|
||||
Bit64u qualification = 3 | (i->rm() << 8);
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
}
|
||||
|
||||
bx_address BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_CR4_Write(bxInstruction_c *i, bx_address val)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return val;
|
||||
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
|
||||
if ((vm->vm_cr4_mask & vm->vm_cr4_read_shadow) != (vm->vm_cr4_mask & val))
|
||||
{
|
||||
BX_ERROR(("VMEXIT: CR4 write"));
|
||||
Bit64u qualification = 4 | (i->rm() << 8);
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
|
||||
// keep untouched all the bits set in CR4 mask
|
||||
return (BX_CPU_THIS_PTR cr4.get32() & vm->vm_cr4_mask) | (val & ~vm->vm_cr4_mask);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Read(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_READ_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: CR8 read"));
|
||||
|
||||
Bit64u qualification = 8 | (VMX_VMEXIT_CR_ACCESS_CR_READ << 4);
|
||||
qualification |= (i->rm() << 8);
|
||||
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_CR8_Write(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_CR8_WRITE_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: CR8 write"));
|
||||
Bit64u qualification = 8 | (i->rm() << 8);
|
||||
VMexit(i, VMX_VMEXIT_CR_ACCESS, qualification);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ----------------------------------------------------------------
|
||||
// Exit qualification for DR access
|
||||
// ----------------------------------------------------------------
|
||||
// [.3:.0] | Number of DR register
|
||||
// [.4:.4] | DR access type (0 - MOV to DR, 1 - MOV from DR)
|
||||
// [.7:.5] | reserved
|
||||
// [11:.8] | Source Operand Register
|
||||
// [63:12] | reserved
|
||||
//
|
||||
|
||||
void BX_CPP_AttrRegparmN(2) BX_CPU_C::VMexit_DR_Access(bxInstruction_c *i, unsigned read)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_DRx_ACCESS_VMEXIT))
|
||||
{
|
||||
BX_ERROR(("VMEXIT: DR%d %s access", i->nnn(), read ? "READ" : "WRITE"));
|
||||
|
||||
Bit64u qualification = i->nnn() | (i->rm() << 8);
|
||||
if (read)
|
||||
qualification |= (1 << 4);
|
||||
|
||||
VMexit(i, VMX_VMEXIT_DR_ACCESS, qualification);
|
||||
}
|
||||
}
|
||||
|
||||
Bit32u BX_CPU_C::VMX_Read_VTPR(void)
|
||||
{
|
||||
bx_phy_address pAddr = BX_CPU_THIS_PTR vmcs.virtual_apic_page_addr + 0x80;
|
||||
Bit32u vtpr;
|
||||
access_read_physical(pAddr, 4, (Bit8u*)(&vtpr));
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMX_VTPR_ACCESS | BX_READ, (Bit8u*)(&vtpr));
|
||||
return vtpr;
|
||||
}
|
||||
|
||||
void BX_CPU_C::VMX_Write_VTPR(Bit8u vtpr)
|
||||
{
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
bx_phy_address pAddr = vm->virtual_apic_page_addr + 0x80;
|
||||
Bit32u field32 = vtpr;
|
||||
|
||||
access_write_physical(pAddr, 4, (Bit8u*)(&field32));
|
||||
BX_DBG_PHY_MEMORY_ACCESS(BX_CPU_ID, pAddr, 4, BX_VMX_VTPR_ACCESS | BX_WRITE, (Bit8u*)(&field32));
|
||||
|
||||
Bit8u tpr_shadow = vtpr >> 4;
|
||||
if (tpr_shadow < vm->vm_tpr_threshold) {
|
||||
// commit current instruction to produce trap-like VMexit
|
||||
BX_CPU_THIS_PTR prev_rip = RIP; // commit new RIP
|
||||
VMexit(0, VMX_VMEXIT_TPR_THRESHOLD, 0);
|
||||
}
|
||||
}
|
||||
|
||||
#if BX_SUPPORT_VMX >= 2
|
||||
bx_bool BX_CPP_AttrRegparmN(1) BX_CPU_C::is_virtual_apic_page(bx_phy_address paddr)
|
||||
{
|
||||
VMCS_CACHE *vm = &BX_CPU_THIS_PTR vmcs;
|
||||
if (BX_CPU_THIS_PTR in_vmx_guest) {
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES))
|
||||
if (PPFOf(paddr) == PPFOf(vm->apic_access_page)) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BX_CPU_C::VMX_Virtual_Apic_Read(bx_phy_address paddr, unsigned len, void *data)
|
||||
{
|
||||
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
|
||||
|
||||
Bit32u offset = PAGE_OFFSET(paddr);
|
||||
|
||||
// access is not instruction fetch because cpu::prefetch will crash them
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
|
||||
// VTPR access
|
||||
Bit32u vtpr = VMX_Read_VTPR();
|
||||
if (len == 1)
|
||||
*((Bit8u *) data) = vtpr & 0xff;
|
||||
else if (len == 2)
|
||||
*((Bit16u *) data) = vtpr & 0xffff;
|
||||
else if (len == 4)
|
||||
*((Bit32u *) data) = vtpr;
|
||||
else
|
||||
BX_PANIC(("PANIC: Unsupported Virtual APIC access len = 3 !"));
|
||||
return;
|
||||
}
|
||||
|
||||
Bit32u qualification = offset |
|
||||
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_READ_INSTRUCTION_EXECUTION;
|
||||
VMexit(0, VMX_VMEXIT_APIC_ACCESS, qualification);
|
||||
}
|
||||
|
||||
void BX_CPU_C::VMX_Virtual_Apic_Write(bx_phy_address paddr, unsigned len, void *data)
|
||||
{
|
||||
BX_ASSERT(SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VIRTUALIZE_APIC_ACCESSES));
|
||||
|
||||
Bit32u offset = PAGE_OFFSET(paddr);
|
||||
|
||||
if (VMEXIT(VMX_VM_EXEC_CTRL2_TPR_SHADOW) && offset == 0x80 && len <= 4) {
|
||||
// VTPR access
|
||||
VMX_Write_VTPR(*((Bit8u *) data));
|
||||
return;
|
||||
}
|
||||
|
||||
Bit32u qualification = offset |
|
||||
(BX_CPU_THIS_PTR in_event) ? VMX_APIC_ACCESS_DURING_EVENT_DELIVERY : VMX_APIC_WRITE_INSTRUCTION_EXECUTION;
|
||||
VMexit(0, VMX_VMEXIT_APIC_ACCESS, qualification);
|
||||
}
|
||||
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::VMexit_WBINVD(bxInstruction_c *i)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest) return;
|
||||
|
||||
if (SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_WBINVD_VMEXIT)) {
|
||||
BX_ERROR(("VMEXIT: WBINVD in VMX non-root operation"));
|
||||
VMexit(i, VMX_VMEXIT_WBINVD, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Bit16u BX_CPU_C::VMX_Get_Current_VPID(void)
|
||||
{
|
||||
if (! BX_CPU_THIS_PTR in_vmx_guest || !SECONDARY_VMEXEC_CONTROL(VMX_VM_EXEC_CTRL3_VPID_ENABLE))
|
||||
return 0;
|
||||
|
||||
return BX_CPU_THIS_PTR vmcs.vpid;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // BX_SUPPORT_VMX
|
||||
3050
simulators/bochs/cpu/vmx.cc
Executable file
3050
simulators/bochs/cpu/vmx.cc
Executable file
File diff suppressed because it is too large
Load Diff
1038
simulators/bochs/cpu/vmx.h
Executable file
1038
simulators/bochs/cpu/vmx.h
Executable file
File diff suppressed because it is too large
Load Diff
267
simulators/bochs/cpu/xmm.h
Normal file
267
simulators/bochs/cpu/xmm.h
Normal file
@ -0,0 +1,267 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2003-2010 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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BX_SSE_EXTENSIONS_H
|
||||
#define BX_SSE_EXTENSIONS_H
|
||||
|
||||
/* XMM REGISTER */
|
||||
|
||||
typedef union bx_xmm_reg_t {
|
||||
Bit8s xmm_sbyte[16];
|
||||
Bit16s xmm_s16[8];
|
||||
Bit32s xmm_s32[4];
|
||||
Bit64s xmm_s64[2];
|
||||
Bit8u xmm_ubyte[16];
|
||||
Bit16u xmm_u16[8];
|
||||
Bit32u xmm_u32[4];
|
||||
Bit64u xmm_u64[2];
|
||||
} BxPackedXmmRegister;
|
||||
|
||||
#ifdef BX_BIG_ENDIAN
|
||||
#define xmm64s(i) xmm_s64[1 - (i)]
|
||||
#define xmm32s(i) xmm_s32[3 - (i)]
|
||||
#define xmm16s(i) xmm_s16[7 - (i)]
|
||||
#define xmmsbyte(i) xmm_sbyte[15 - (i)]
|
||||
#define xmmubyte(i) xmm_ubyte[15 - (i)]
|
||||
#define xmm16u(i) xmm_u16[7 - (i)]
|
||||
#define xmm32u(i) xmm_u32[3 - (i)]
|
||||
#define xmm64u(i) xmm_u64[1 - (i)]
|
||||
#else
|
||||
#define xmm64s(i) xmm_s64[(i)]
|
||||
#define xmm32s(i) xmm_s32[(i)]
|
||||
#define xmm16s(i) xmm_s16[(i)]
|
||||
#define xmmsbyte(i) xmm_sbyte[(i)]
|
||||
#define xmmubyte(i) xmm_ubyte[(i)]
|
||||
#define xmm16u(i) xmm_u16[(i)]
|
||||
#define xmm32u(i) xmm_u32[(i)]
|
||||
#define xmm64u(i) xmm_u64[(i)]
|
||||
#endif
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
# define BX_XMM_REGISTERS 16
|
||||
#else
|
||||
# define BX_XMM_REGISTERS 8
|
||||
#endif
|
||||
|
||||
/* read XMM register */
|
||||
#define BX_READ_XMM_REG(index) (BX_CPU_THIS_PTR xmm[index])
|
||||
|
||||
/* read only high 64 bit of the register */
|
||||
#define BX_READ_XMM_REG_HI_QWORD(index) \
|
||||
((BX_CPU_THIS_PTR xmm[index]).xmm64u(1))
|
||||
|
||||
/* read only low 64 bit of the register */
|
||||
#define BX_READ_XMM_REG_LO_QWORD(index) \
|
||||
((BX_CPU_THIS_PTR xmm[index]).xmm64u(0))
|
||||
|
||||
/* read only low 32 bit of the register */
|
||||
#define BX_READ_XMM_REG_LO_DWORD(index) \
|
||||
((BX_CPU_THIS_PTR xmm[index]).xmm32u(0))
|
||||
|
||||
/* read only low 16 bit of the register */
|
||||
#define BX_READ_XMM_REG_LO_WORD(index) \
|
||||
((BX_CPU_THIS_PTR xmm[index]).xmm16u(0))
|
||||
|
||||
/* short names for above macroses */
|
||||
#define BX_XMM_REG_HI_QWORD BX_READ_XMM_REG_HI_QWORD
|
||||
#define BX_XMM_REG_LO_QWORD BX_READ_XMM_REG_LO_QWORD
|
||||
#define BX_XMM_REG_LO_DWORD BX_READ_XMM_REG_LO_DWORD
|
||||
|
||||
#define BX_XMM_REG BX_READ_XMM_REG
|
||||
|
||||
/* store XMM register */
|
||||
#define BX_WRITE_XMM_REG(index, reg) \
|
||||
{ BX_CPU_THIS_PTR xmm[index] = (reg); }
|
||||
|
||||
/* store only high 64 bit of the register, rest of the register unchanged */
|
||||
#define BX_WRITE_XMM_REG_HI_QWORD(index, reg64) \
|
||||
{ (BX_CPU_THIS_PTR xmm[index]).xmm64u(1) = (reg64); }
|
||||
|
||||
/* store only low 64 bit of the register, rest of the register unchanged */
|
||||
#define BX_WRITE_XMM_REG_LO_QWORD(index, reg64) \
|
||||
{ (BX_CPU_THIS_PTR xmm[index]).xmm64u(0) = (reg64); }
|
||||
|
||||
/* store only low 32 bit of the register, rest of the register unchanged */
|
||||
#define BX_WRITE_XMM_REG_LO_DWORD(index, reg32) \
|
||||
{ (BX_CPU_THIS_PTR xmm[index]).xmm32u(0) = (reg32); }
|
||||
|
||||
/* store only low 16 bit of the register, rest of the register unchanged */
|
||||
#define BX_WRITE_XMM_REG_LO_WORD(index, reg16) \
|
||||
{ (BX_CPU_THIS_PTR xmm[index]).xmm16u(0) = (reg16); }
|
||||
|
||||
|
||||
/* MXCSR REGISTER */
|
||||
|
||||
/* 31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16
|
||||
* ==|==|=====|==|==|==|==|==|==|==|==|==|==|==|== (reserved)
|
||||
* 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0| 0|MM| 0
|
||||
*
|
||||
* 15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0
|
||||
* ==|==|=====|==|==|==|==|==|==|==|==|==|==|==|==
|
||||
* FZ| R C |PM|UM|OM|ZM|DM|IM|DZ|PE|UE|OE|ZE|DE|IE
|
||||
*/
|
||||
|
||||
/* MXCSR REGISTER FIELDS DESCRIPTION */
|
||||
|
||||
/*
|
||||
* IE 0 Invalid-Operation Exception 0
|
||||
* DE 1 Denormalized-Operand Exception 0
|
||||
* ZE 2 Zero-Divide Exception 0
|
||||
* OE 3 Overflow Exception 0
|
||||
* UE 4 Underflow Exception 0
|
||||
* PE 5 Precision Exception 0
|
||||
* DZ 6 Denormals are Zeros 0
|
||||
* IM 7 Invalid-Operation Exception Mask 1
|
||||
* DM 8 Denormalized-Operand Exception Mask 1
|
||||
* ZM 9 Zero-Divide Exception Mask 1
|
||||
* OM 10 Overflow Exception Mask 1
|
||||
* UM 11 Underflow Exception Mask 1
|
||||
* PM 12 Precision Exception Mask 1
|
||||
* RC 13-14 Floating-Point Rounding Control 00
|
||||
* FZ 15 Flush-to-Zero for Masked Underflow 0
|
||||
* RZ 16 Reserved 0
|
||||
* MM 17 Misaligned Exception Mask 0
|
||||
*/
|
||||
|
||||
#define MXCSR_EXCEPTIONS 0x0000003F
|
||||
#define MXCSR_DAZ 0x00000040
|
||||
#define MXCSR_MASKED_EXCEPTIONS 0x00001F80
|
||||
#define MXCSR_ROUNDING_CONTROL 0x00006000
|
||||
#define MXCSR_FLUSH_MASKED_UNDERFLOW 0x00008000
|
||||
#define MXCSR_MISALIGNED_EXCEPTION_MASK 0x00020000
|
||||
|
||||
#define MXCSR_IE 0x00000001
|
||||
#define MXCSR_DE 0x00000002
|
||||
#define MXCSR_ZE 0x00000004
|
||||
#define MXCSR_OE 0x00000008
|
||||
#define MXCSR_UE 0x00000010
|
||||
#define MXCSR_PE 0x00000020
|
||||
|
||||
#define MXCSR_IM 0x00000080
|
||||
#define MXCSR_DM 0x00000100
|
||||
#define MXCSR_ZM 0x00000200
|
||||
#define MXCSR_OM 0x00000400
|
||||
#define MXCSR_UM 0x00000800
|
||||
#define MXCSR_PM 0x00001000
|
||||
|
||||
#define MXCSR_RESET 0x00001F80 /* reset value of the MXCSR register */
|
||||
|
||||
struct BOCHSAPI bx_mxcsr_t
|
||||
{
|
||||
Bit32u mxcsr;
|
||||
|
||||
bx_mxcsr_t (Bit32u val = MXCSR_RESET)
|
||||
: mxcsr(val) {}
|
||||
|
||||
#define IMPLEMENT_MXCSR_ACCESSOR(name, bitmask, bitnum) \
|
||||
int get_##name () const { \
|
||||
return (mxcsr & (bitmask)) >> (bitnum); \
|
||||
}
|
||||
|
||||
IMPLEMENT_MXCSR_ACCESSOR(exceptions_masks, MXCSR_MASKED_EXCEPTIONS, 7);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(DAZ, MXCSR_DAZ, 6);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(rounding_mode, MXCSR_ROUNDING_CONTROL, 13);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(flush_masked_underflow, MXCSR_FLUSH_MASKED_UNDERFLOW, 15);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(MM, MXCSR_MISALIGNED_EXCEPTION_MASK, 17);
|
||||
|
||||
IMPLEMENT_MXCSR_ACCESSOR(IE, MXCSR_IE, 0);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(DE, MXCSR_DE, 1);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(ZE, MXCSR_ZE, 2);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(OE, MXCSR_OE, 3);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(UE, MXCSR_UE, 4);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(PE, MXCSR_PE, 5);
|
||||
|
||||
IMPLEMENT_MXCSR_ACCESSOR(IM, MXCSR_IM, 7);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(DM, MXCSR_DM, 8);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(ZM, MXCSR_ZM, 9);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(OM, MXCSR_OM, 10);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(UM, MXCSR_UM, 11);
|
||||
IMPLEMENT_MXCSR_ACCESSOR(PM, MXCSR_PM, 12);
|
||||
|
||||
void set_exceptions(int status) {
|
||||
mxcsr |= (status & MXCSR_EXCEPTIONS);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#if defined(NEED_CPU_REG_SHORTCUTS)
|
||||
#define MXCSR (BX_CPU_THIS_PTR mxcsr)
|
||||
#define BX_MXCSR_REGISTER (BX_CPU_THIS_PTR mxcsr.mxcsr)
|
||||
#define MXCSR_MASK (BX_CPU_THIS_PTR mxcsr_mask)
|
||||
#endif
|
||||
|
||||
/* INTEGER SATURATION */
|
||||
|
||||
/*
|
||||
* SaturateWordSToByteS converts a signed 16-bit value to a signed
|
||||
* 8-bit value. If the signed 16-bit value is less than -128, it is
|
||||
* represented by the saturated value -128 (0x80). If it is greater
|
||||
* than 127, it is represented by the saturated value 127 (0x7F).
|
||||
*/
|
||||
BX_CPP_INLINE Bit8s BX_CPP_AttrRegparmN(1) SaturateWordSToByteS(Bit16s value)
|
||||
{
|
||||
if(value < -128) return -128;
|
||||
if(value > 127) return 127;
|
||||
return (Bit8s) value;
|
||||
}
|
||||
|
||||
/*
|
||||
* SaturateDwordSToWordS converts a signed 32-bit value to a signed
|
||||
* 16-bit value. If the signed 32-bit value is less than -32768, it is
|
||||
* represented by the saturated value -32768 (0x8000). If it is greater
|
||||
* than 32767, it is represented by the saturated value 32767 (0x7FFF).
|
||||
*/
|
||||
BX_CPP_INLINE Bit16s BX_CPP_AttrRegparmN(1) SaturateDwordSToWordS(Bit32s value)
|
||||
{
|
||||
if(value < -32768) return -32768;
|
||||
if(value > 32767) return 32767;
|
||||
return (Bit16s) value;
|
||||
}
|
||||
|
||||
/*
|
||||
* SaturateWordSToByteU converts a signed 16-bit value to an unsigned
|
||||
* 8-bit value. If the signed 16-bit value is less than zero it is
|
||||
* represented by the saturated value zero (0x00).If it is greater than
|
||||
* 255 it is represented by the saturated value 255 (0xFF).
|
||||
*/
|
||||
BX_CPP_INLINE Bit8u BX_CPP_AttrRegparmN(1) SaturateWordSToByteU(Bit16s value)
|
||||
{
|
||||
if(value < 0) return 0;
|
||||
if(value > 255) return 255;
|
||||
return (Bit8u) value;
|
||||
}
|
||||
|
||||
/*
|
||||
* SaturateDwordSToWordU converts a signed 32-bit value to an unsigned
|
||||
* 16-bit value. If the signed 32-bit value is less than zero, it is
|
||||
* represented by the saturated value zero (0x0000). If it is greater
|
||||
* than 65535, it is represented by the saturated value 65535 (0xFFFF).
|
||||
*/
|
||||
BX_CPP_INLINE Bit16u BX_CPP_AttrRegparmN(1) SaturateDwordSToWordU(Bit32s value)
|
||||
{
|
||||
if(value < 0) return 0;
|
||||
if(value > 65535) return 65535;
|
||||
return (Bit16u) value;
|
||||
}
|
||||
|
||||
#endif
|
||||
359
simulators/bochs/cpu/xsave.cc
Executable file
359
simulators/bochs/cpu/xsave.cc
Executable file
@ -0,0 +1,359 @@
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// $Id$
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2008-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 B 02110-1301 USA
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define NEED_CPU_REG_SHORTCUTS 1
|
||||
#include "bochs.h"
|
||||
#include "cpu.h"
|
||||
#define LOG_THIS BX_CPU_THIS_PTR
|
||||
|
||||
// Make code more tidy with a few macros.
|
||||
#if BX_SUPPORT_X86_64==0
|
||||
#define RAX EAX
|
||||
#define RDX EDX
|
||||
#endif
|
||||
|
||||
/* 0F AE /4 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSAVE(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
unsigned index;
|
||||
BxPackedXmmRegister xmm;
|
||||
|
||||
BX_CPU_THIS_PTR prepareXSAVE();
|
||||
|
||||
BX_DEBUG(("XSAVE: save processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0.get32()));
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
bx_address laddr = get_laddr(i->seg(), eaddr);
|
||||
|
||||
if (laddr & 0x3f) {
|
||||
BX_ERROR(("XSAVE: access not aligned to 64-byte"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
bx_address asize_mask = i->asize_mask();
|
||||
|
||||
//
|
||||
// We will go feature-by-feature and not run over all XCR0 bits
|
||||
//
|
||||
|
||||
Bit64u header1 = read_virtual_qword(i->seg(), (eaddr + 512) & asize_mask);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
if (BX_CPU_THIS_PTR xcr0.get_FPU() && (EAX & BX_XCR0_FPU_MASK) != 0)
|
||||
{
|
||||
xmm.xmm16u(0) = BX_CPU_THIS_PTR the_i387.get_control_word();
|
||||
xmm.xmm16u(1) = BX_CPU_THIS_PTR the_i387.get_status_word();
|
||||
xmm.xmm16u(2) = pack_FPU_TW(BX_CPU_THIS_PTR the_i387.get_tag_word());
|
||||
|
||||
/* x87 FPU Opcode (16 bits) */
|
||||
/* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
|
||||
xmm.xmm16u(3) = BX_CPU_THIS_PTR the_i387.foo;
|
||||
|
||||
/*
|
||||
* x87 FPU IP Offset (32/64 bits)
|
||||
* The contents of this field differ depending on the current
|
||||
* addressing mode (16/32/64 bit) when the FXSAVE instruction was executed:
|
||||
* + 64-bit mode - 64-bit IP offset
|
||||
* + 32-bit mode - 32-bit IP offset
|
||||
* + 16-bit mode - low 16 bits are IP offset; high 16 bits are reserved.
|
||||
* x87 CS FPU IP Selector
|
||||
* + 16 bit, in 16/32 bit mode only
|
||||
*/
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
xmm.xmm64u(1) = (BX_CPU_THIS_PTR the_i387.fip);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
xmm.xmm32u(2) = (Bit32u)(BX_CPU_THIS_PTR the_i387.fip);
|
||||
xmm.xmm32u(3) = (BX_CPU_THIS_PTR the_i387.fcs);
|
||||
}
|
||||
|
||||
write_virtual_dqword(i->seg(), eaddr, (Bit8u *) &xmm);
|
||||
|
||||
/*
|
||||
* x87 FPU Instruction Operand (Data) Pointer Offset (32/64 bits)
|
||||
* The contents of this field differ depending on the current
|
||||
* addressing mode (16/32 bit) when the FXSAVE instruction was executed:
|
||||
* + 64-bit mode - 64-bit offset
|
||||
* + 32-bit mode - 32-bit offset
|
||||
* + 16-bit mode - low 16 bits are offset; high 16 bits are reserved.
|
||||
* x87 DS FPU Instruction Operand (Data) Pointer Selector
|
||||
* + 16 bit, in 16/32 bit mode only
|
||||
*/
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
write_virtual_qword(i->seg(), (eaddr + 16) & asize_mask, BX_CPU_THIS_PTR the_i387.fdp);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
write_virtual_dword(i->seg(), (eaddr + 16) & asize_mask, (Bit32u) BX_CPU_THIS_PTR the_i387.fdp);
|
||||
write_virtual_dword(i->seg(), (eaddr + 20) & asize_mask, (Bit32u) BX_CPU_THIS_PTR the_i387.fds);
|
||||
}
|
||||
/* do not touch MXCSR state */
|
||||
|
||||
/* store i387 register file */
|
||||
for(index=0; index < 8; index++)
|
||||
{
|
||||
const floatx80 &fp = BX_READ_FPU_REG(index);
|
||||
|
||||
xmm.xmm64u(0) = fp.fraction;
|
||||
xmm.xmm64u(1) = 0;
|
||||
xmm.xmm16u(4) = fp.exp;
|
||||
|
||||
write_virtual_dqword(i->seg(), (eaddr+index*16+32) & asize_mask, (Bit8u *) &xmm);
|
||||
}
|
||||
|
||||
header1 |= BX_XCR0_FPU_MASK;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
|
||||
{
|
||||
write_virtual_dword(i->seg(), (eaddr + 24) & asize_mask, BX_MXCSR_REGISTER);
|
||||
write_virtual_dword(i->seg(), (eaddr + 28) & asize_mask, MXCSR_MASK);
|
||||
|
||||
/* store XMM register file */
|
||||
for(index=0; index < BX_XMM_REGISTERS; index++)
|
||||
{
|
||||
// save XMM8-XMM15 only in 64-bit mode
|
||||
if (index < 8 || long64_mode()) {
|
||||
write_virtual_dqword(i->seg(),
|
||||
(eaddr+index*16+160) & asize_mask, (Bit8u *)(&BX_READ_XMM_REG(index)));
|
||||
}
|
||||
}
|
||||
|
||||
header1 |= BX_XCR0_SSE_MASK;
|
||||
}
|
||||
|
||||
// always update header to 'dirty' state
|
||||
write_virtual_qword(i->seg(), (eaddr + 512) & asize_mask, header1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 0F AE /5 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XRSTOR(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
unsigned index;
|
||||
BxPackedXmmRegister xmm;
|
||||
|
||||
BX_CPU_THIS_PTR prepareXSAVE();
|
||||
|
||||
BX_DEBUG(("XRSTOR: restore processor state XCR0=0x%08x", BX_CPU_THIS_PTR xcr0.get32()));
|
||||
|
||||
bx_address eaddr = BX_CPU_CALL_METHODR(i->ResolveModrm, (i));
|
||||
bx_address laddr = get_laddr(i->seg(), eaddr);
|
||||
|
||||
if (laddr & 0x3f) {
|
||||
BX_ERROR(("XRSTOR: access not aligned to 64-byte"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
bx_address asize_mask = i->asize_mask();
|
||||
|
||||
Bit64u header1 = read_virtual_qword(i->seg(), (eaddr + 512) & asize_mask);
|
||||
Bit64u header2 = read_virtual_qword(i->seg(), (eaddr + 520) & asize_mask);
|
||||
Bit64u header3 = read_virtual_qword(i->seg(), (eaddr + 528) & asize_mask);
|
||||
|
||||
if ((~BX_CPU_THIS_PTR xcr0.get32() & header1) != 0) {
|
||||
BX_ERROR(("XRSTOR: Broken header state"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (header2 != 0 || header3 != 0) {
|
||||
BX_ERROR(("XRSTOR: Reserved header state is not '0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
//
|
||||
// We will go feature-by-feature and not run over all XCR0 bits
|
||||
//
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
if (BX_CPU_THIS_PTR xcr0.get_FPU() && (EAX & BX_XCR0_FPU_MASK) != 0)
|
||||
{
|
||||
if (header1 & BX_XCR0_FPU_MASK) {
|
||||
// load FPU state from XSAVE area
|
||||
read_virtual_dqword(i->seg(), eaddr, (Bit8u *) &xmm);
|
||||
|
||||
BX_CPU_THIS_PTR the_i387.cwd = xmm.xmm16u(0);
|
||||
BX_CPU_THIS_PTR the_i387.swd = xmm.xmm16u(1);
|
||||
BX_CPU_THIS_PTR the_i387.tos = (xmm.xmm16u(1) >> 11) & 0x07;
|
||||
|
||||
/* Restore x87 FPU Opcode */
|
||||
/* The lower 11 bits contain the FPU opcode, upper 5 bits are reserved */
|
||||
BX_CPU_THIS_PTR the_i387.foo = xmm.xmm16u(3) & 0x7FF;
|
||||
|
||||
/* Restore x87 FPU IP */
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
BX_CPU_THIS_PTR the_i387.fip = xmm.xmm64u(1);
|
||||
BX_CPU_THIS_PTR the_i387.fcs = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
BX_CPU_THIS_PTR the_i387.fip = xmm.xmm32u(2);
|
||||
BX_CPU_THIS_PTR the_i387.fcs = xmm.xmm16u(6);
|
||||
}
|
||||
|
||||
Bit32u tag_byte = xmm.xmmubyte(4);
|
||||
|
||||
/* Restore x87 FPU DP */
|
||||
read_virtual_dqword(i->seg(), (eaddr + 16) & asize_mask, (Bit8u *) &xmm);
|
||||
|
||||
#if BX_SUPPORT_X86_64
|
||||
if (i->os64L()) {
|
||||
BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm64u(0);
|
||||
BX_CPU_THIS_PTR the_i387.fds = 0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
BX_CPU_THIS_PTR the_i387.fdp = xmm.xmm32u(0);
|
||||
BX_CPU_THIS_PTR the_i387.fds = xmm.xmm16u(2);
|
||||
}
|
||||
|
||||
/* load i387 register file */
|
||||
for(index=0; index < 8; index++)
|
||||
{
|
||||
floatx80 reg;
|
||||
reg.fraction = read_virtual_qword(i->seg(), (eaddr+index*16+32) & asize_mask);
|
||||
reg.exp = read_virtual_word (i->seg(), (eaddr+index*16+40) & asize_mask);
|
||||
|
||||
// update tag only if it is not empty
|
||||
BX_WRITE_FPU_REGISTER_AND_TAG(reg,
|
||||
IS_TAG_EMPTY(index) ? FPU_Tag_Empty : FPU_tagof(reg), index);
|
||||
}
|
||||
|
||||
/* Restore floating point tag word - see desription for FXRSTOR instruction */
|
||||
BX_CPU_THIS_PTR the_i387.twd = unpack_FPU_TW(tag_byte);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// initialize FPU with reset values
|
||||
BX_CPU_THIS_PTR the_i387.init();
|
||||
|
||||
for (index=0;index<8;index++) {
|
||||
floatx80 reg = { 0, 0 };
|
||||
BX_FPU_REG(index) = reg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
if (BX_CPU_THIS_PTR xcr0.get_SSE() && (EAX & BX_XCR0_SSE_MASK) != 0)
|
||||
{
|
||||
Bit32u new_mxcsr = read_virtual_dword(i->seg(), (eaddr + 24) & asize_mask);
|
||||
if(new_mxcsr & ~MXCSR_MASK)
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
BX_MXCSR_REGISTER = new_mxcsr;
|
||||
|
||||
if (header1 & BX_XCR0_SSE_MASK) {
|
||||
// load SSE state from XSAVE area
|
||||
for(index=0; index < BX_XMM_REGISTERS; index++)
|
||||
{
|
||||
// restore XMM8-XMM15 only in 64-bit mode
|
||||
if (index < 8 || long64_mode()) {
|
||||
read_virtual_dqword(i->seg(),
|
||||
(eaddr+index*16+160) & asize_mask, (Bit8u *)(&BX_READ_XMM_REG(index)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// initialize SSE with reset values
|
||||
for(index=0; index < BX_XMM_REGISTERS; index++) {
|
||||
// set XMM8-XMM15 only in 64-bit mode
|
||||
if (index < 8 || long64_mode()) {
|
||||
BX_CPU_THIS_PTR xmm[index].xmm64u(0) = 0;
|
||||
BX_CPU_THIS_PTR xmm[index].xmm64u(1) = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 0F 01 D0 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XGETBV(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
if(! BX_CPU_THIS_PTR cr4.get_OSXSAVE()) {
|
||||
BX_ERROR(("XGETBV: OSXSAVE feature is not enabled in CR4!"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// For now hardcoded handle only XCR0 register, it should take a few
|
||||
// years until extension will be required
|
||||
if (ECX != 0) {
|
||||
BX_ERROR(("XGETBV: Invalid XCR register %d", ECX));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
RDX = 0;
|
||||
RAX = BX_CPU_THIS_PTR xcr0.get32();
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 0F 01 D1 */
|
||||
void BX_CPP_AttrRegparmN(1) BX_CPU_C::XSETBV(bxInstruction_c *i)
|
||||
{
|
||||
#if BX_CPU_LEVEL >= 6
|
||||
if(! BX_CPU_THIS_PTR cr4.get_OSXSAVE()) {
|
||||
BX_ERROR(("XSETBV: OSXSAVE feature is not enabled in CR4!"));
|
||||
exception(BX_UD_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (v8086_mode() || CPL != 0) {
|
||||
BX_ERROR(("XSETBV: The current priveledge level is not 0"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
// For now hardcoded handle only XCR0 register, it should take a few
|
||||
// years until extension will be required
|
||||
if (ECX != 0) {
|
||||
BX_ERROR(("XSETBV: Invalid XCR register %d", ECX));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
if (EDX != 0 || (EAX & ~BX_XCR0_SUPPORTED_BITS) != 0 || (EAX & 1) == 0) {
|
||||
BX_ERROR(("XSETBV: Attempting to change reserved bits!"));
|
||||
exception(BX_GP_EXCEPTION, 0);
|
||||
}
|
||||
|
||||
BX_CPU_THIS_PTR xcr0.set32(EAX);
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user