Bochs/bochs/cpu/proc_ctrl.cc

2014 lines
64 KiB
C++
Raw Normal View History

/////////////////////////////////////////////////////////////////////////
// $Id: proc_ctrl.cc,v 1.76 2003-10-24 18:34:15 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2001 MandrakeSoft S.A.
//
// MandrakeSoft S.A.
// 43, rue d'Aboukir
// 75002 Paris - France
// http://www.linux-mandrake.com/
// http://www.mandrakesoft.com/
//
// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define NEED_CPU_REG_SHORTCUTS 1
#include "bochs.h"
#define LOG_THIS BX_CPU_THIS_PTR
#if BX_USE_CPU_SMF
#define this (BX_CPU(0))
#endif
#if BX_SUPPORT_X86_64==0
// Make life easier for merging code.
#define RAX EAX
#define RBX EBX
#define RCX ECX
#define RDX EDX
#endif
void
BX_CPU_C::UndefinedOpcode(bxInstruction_c *i)
{
2002-10-16 21:37:35 +04:00
BX_DEBUG(("UndefinedOpcode: %02x causes exception 6", (unsigned) i->b1()));
exception(BX_UD_EXCEPTION, 0, 0);
}
void
BX_CPU_C::NOP(bxInstruction_c *i)
{
2002-10-16 21:37:35 +04:00
}
void BX_CPU_C::PREFETCH(bxInstruction_c *i)
{
2003-05-15 20:41:17 +04:00
#if BX_SUPPORT_3DNOW || BX_SUPPORT_SSE >= 1
BX_INSTR_PREFETCH_HINT(BX_CPU_ID, i->nnn(), i->seg(), RMAddr(i));
2002-10-16 21:37:35 +04:00
#else
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::HLT(bxInstruction_c *i)
{
// hack to panic if HLT comes from BIOS
if ( BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value == 0xf000 )
BX_PANIC(("HALT instruction encountered in the BIOS ROM"));
if (CPL!=0) {
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
if ( ! BX_CPU_THIS_PTR get_IF () ) {
BX_INFO(("WARNING: HLT instruction with IF=0!"));
}
// stops instruction execution and places the processor in a
// HALT state. An enabled interrupt, NMI, or reset will resume
// execution. If interrupt (including NMI) is used to resume
// execution after HLT, the saved CS:eIP points to instruction
// following HLT.
// artificial trap bit, why use another variable.
BX_CPU_THIS_PTR debug_trap |= 0x80000000; // artificial trap
BX_CPU_THIS_PTR async_event = 1; // so processor knows to check
// Execution of this instruction completes. The processor
// will remain in a halt state until one of the above conditions
// is met.
#if BX_USE_IDLE_HACK
bx_gui->sim_is_idle ();
#endif /* BX_USE_IDLE_HACK */
}
void
BX_CPU_C::CLTS(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
BX_PANIC(("CLTS: not implemented for < 286"));
#else
if (v8086_mode()) BX_PANIC(("clts: v8086 mode unsupported"));
/* read errata file */
// does CLTS also clear NT flag???
// #GP(0) if CPL is not 0
if (CPL!=0) {
BX_INFO(("CLTS(): CPL!=0"));
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
BX_CPU_THIS_PTR cr0.ts = 0;
BX_CPU_THIS_PTR cr0.val32 &= ~0x08;
#endif
}
void
BX_CPU_C::INVD(bxInstruction_c *i)
{
BX_INFO(("---------------"));
BX_INFO(("- INVD called -"));
BX_INFO(("---------------"));
#if BX_CPU_LEVEL >= 4
invalidate_prefetch_q();
if (BX_CPU_THIS_PTR cr0.pe) {
if (CPL!=0) {
BX_INFO(("INVD: CPL!=0"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_INVD);
#else
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::WBINVD(bxInstruction_c *i)
{
BX_INFO(("WBINVD: (ignoring)"));
#if BX_CPU_LEVEL >= 4
invalidate_prefetch_q();
if (BX_CPU_THIS_PTR cr0.pe) {
if (CPL!=0) {
BX_INFO(("WBINVD: CPL!=0"));
exception(BX_GP_EXCEPTION, 0, 0);
}
}
BX_INSTR_CACHE_CNTRL(BX_CPU_ID, BX_INSTR_WBINVD);
#else
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::MOV_DdRd(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_DdRd: not supported on < 386"));
#else
Bit32u val_32;
if (v8086_mode()) {
exception(BX_GP_EXCEPTION, 0, 0);
}
/* NOTES:
* 32bit operands always used
* r/m field specifies general register
* mod field should always be 11 binary
* reg field specifies which special register
*/
if (!i->modC0()) {
BX_PANIC(("MOV_DdRd(): rm field not a register!"));
}
invalidate_prefetch_q();
if (protected_mode() && CPL!=0) {
BX_PANIC(("MOV_DdRd: CPL!=0"));
/* #GP(0) if CPL is not 0 */
exception(BX_GP_EXCEPTION, 0, 0);
}
val_32 = BX_READ_32BIT_REG(i->rm());
if (bx_dbg.dreg)
BX_INFO(("MOV_DdRd: DR[%u]=%08xh unhandled",
(unsigned) i->nnn(), (unsigned) val_32));
switch (i->nnn()) {
case 0: // DR0
BX_CPU_THIS_PTR dr0 = val_32;
break;
case 1: // DR1
BX_CPU_THIS_PTR dr1 = val_32;
break;
case 2: // DR2
BX_CPU_THIS_PTR dr2 = val_32;
break;
case 3: // DR3
BX_CPU_THIS_PTR dr3 = val_32;
break;
case 4: // DR4
case 6: // DR6
// DR4 aliased to DR6 by default. With Debug Extensions on,
// access to DR4 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions on
BX_INFO(("MOV_DdRd: access to DR4 causes #UD"));
UndefinedOpcode(i);
}
#endif
#if BX_CPU_LEVEL <= 4
// On 386/486 bit12 is settable
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(val_32 & 0x0000f00f);
#else
// On Pentium+, bit12 is always zero
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(val_32 & 0x0000e00f);
#endif
break;
case 5: // DR5
case 7: // DR7
// Note: 486+ ignore GE and LE flags. On the 386, exact
// data breakpoint matching does not occur unless it is enabled
// by setting the LE and/or GE flags.
// DR5 aliased to DR7 by default. With Debug Extensions on,
// access to DR5 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions (CR4.DE) on
BX_INFO(("MOV_DdRd: access to DR5 causes #UD"));
UndefinedOpcode(i);
}
#endif
// Some sanity checks...
if ( val_32 & 0x00002000 ) {
BX_PANIC(("MOV_DdRd: GD bit not supported yet"));
// Note: processor clears GD upon entering debug exception
// handler, to allow access to the debug registers
}
if ( (((val_32>>16) & 3)==2) ||
(((val_32>>20) & 3)==2) ||
(((val_32>>24) & 3)==2) ||
(((val_32>>28) & 3)==2) ) {
// IO breakpoints (10b) are not yet supported.
BX_PANIC(("MOV_DdRd: write of %08x contains IO breakpoint",
val_32));
}
if ( (((val_32>>18) & 3)==2) ||
(((val_32>>22) & 3)==2) ||
(((val_32>>26) & 3)==2) ||
(((val_32>>30) & 3)==2) ) {
// LEN0..3 contains undefined length specifier (10b)
BX_PANIC(("MOV_DdRd: write of %08x contains undefined LENx",
val_32));
}
if ( ((((val_32>>16) & 3)==0) && (((val_32>>18) & 3)!=0)) ||
((((val_32>>20) & 3)==0) && (((val_32>>22) & 3)!=0)) ||
((((val_32>>24) & 3)==0) && (((val_32>>26) & 3)!=0)) ||
((((val_32>>28) & 3)==0) && (((val_32>>30) & 3)!=0)) ) {
// Instruction breakpoint with LENx not 00b (1-byte length)
BX_PANIC(("MOV_DdRd: write of %08x, R/W=00b LEN!=00b",
val_32));
}
#if BX_CPU_LEVEL <= 4
// 386/486: you can play with all the bits except b10 is always 1
BX_CPU_THIS_PTR dr7 = val_32 | 0x00000400;
#else
// Pentium+: bits15,14,12 are hardwired to 0, rest are settable.
// Even bits 11,10 are changeable though reserved.
BX_CPU_THIS_PTR dr7 = (val_32 & 0xffff2fff) | 0x00000400;
#endif
// if we have breakpoints enabled then we must check
// breakpoints condition in cpu loop
if(BX_CPU_THIS_PTR dr7 & 0xff)
BX_CPU_THIS_PTR async_event = 1;
break;
default:
BX_PANIC(("MOV_DdRd: control register index out of range"));
break;
}
#endif
}
void
BX_CPU_C::MOV_RdDd(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_RdDd: not supported on < 386"));
#else
Bit32u val_32;
if (v8086_mode()) {
BX_INFO(("MOV_RdDd: v8086 mode causes #GP"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (!i->modC0()) {
BX_PANIC(("MOV_RdDd(): rm field not a register!"));
UndefinedOpcode(i);
}
if (protected_mode() && (CPL!=0)) {
BX_INFO(("MOV_RdDd: CPL!=0 causes #GP"));
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
if (bx_dbg.dreg)
BX_INFO(("MOV_RdDd: DR%u not implemented yet", i->nnn()));
switch (i->nnn()) {
case 0: // DR0
val_32 = BX_CPU_THIS_PTR dr0;
break;
case 1: // DR1
val_32 = BX_CPU_THIS_PTR dr1;
break;
case 2: // DR2
val_32 = BX_CPU_THIS_PTR dr2;
break;
case 3: // DR3
val_32 = BX_CPU_THIS_PTR dr3;
break;
case 4: // DR4
case 6: // DR6
// DR4 aliased to DR6 by default. With Debug Extensions on,
// access to DR4 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions on
BX_INFO(("MOV_RdDd: access to DR4 causes #UD"));
UndefinedOpcode(i);
}
#endif
val_32 = BX_CPU_THIS_PTR dr6;
break;
case 5: // DR5
case 7: // DR7
// DR5 aliased to DR7 by default. With Debug Extensions on,
// access to DR5 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions on
BX_INFO(("MOV_RdDd: access to DR5 causes #UD"));
UndefinedOpcode(i);
}
#endif
val_32 = BX_CPU_THIS_PTR dr7;
break;
default:
BX_PANIC(("MOV_RdDd: control register index out of range"));
val_32 = 0;
}
BX_WRITE_32BIT_REGZ(i->rm(), val_32);
#endif
}
#if BX_SUPPORT_X86_64
void
BX_CPU_C::MOV_DqRq(bxInstruction_c *i)
{
Bit64u val_64;
if (v8086_mode()) BX_PANIC(("MOV_DqRq: v8086 mode unsupported"));
/* NOTES:
* 64bit operands always used
* r/m field specifies general register
* mod field should always be 11 binary
* reg field specifies which special register
*/
if (!i->modC0()) {
BX_PANIC(("MOV_DqRq(): rm field not a register!"));
}
invalidate_prefetch_q();
if (protected_mode() && CPL!=0) {
BX_PANIC(("MOV_DqRq: CPL!=0"));
/* #GP(0) if CPL is not 0 */
exception(BX_GP_EXCEPTION, 0, 0);
}
val_64 = BX_READ_64BIT_REG(i->rm());
if (bx_dbg.dreg)
BX_INFO(("MOV_DqRq: DR[%u]=%08xh unhandled",
(unsigned) i->nnn(), (unsigned) val_64));
switch (i->nnn()) {
case 0: // DR0
BX_CPU_THIS_PTR dr0 = val_64;
break;
case 1: // DR1
BX_CPU_THIS_PTR dr1 = val_64;
break;
case 2: // DR2
BX_CPU_THIS_PTR dr2 = val_64;
break;
case 3: // DR3
BX_CPU_THIS_PTR dr3 = val_64;
break;
case 4: // DR4
case 6: // DR6
// DR4 aliased to DR6 by default. With Debug Extensions on,
// access to DR4 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions on
BX_INFO(("MOV_DqRq: access to DR4 causes #UD"));
UndefinedOpcode(i);
}
#endif
#if BX_CPU_LEVEL <= 4
// On 386/486 bit12 is settable
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(val_64 & 0x0000f00f);
#else
// On Pentium+, bit12 is always zero
BX_CPU_THIS_PTR dr6 = (BX_CPU_THIS_PTR dr6 & 0xffff0ff0) |
(val_64 & 0x0000e00f);
#endif
break;
case 5: // DR5
case 7: // DR7
// Note: 486+ ignore GE and LE flags. On the 386, exact
// data breakpoint matching does not occur unless it is enabled
// by setting the LE and/or GE flags.
// DR5 aliased to DR7 by default. With Debug Extensions on,
// access to DR5 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions (CR4.DE) on
BX_INFO(("MOV_DqRq: access to DR5 causes #UD"));
UndefinedOpcode(i);
}
#endif
// Some sanity checks...
if ( val_64 & 0x00002000 ) {
BX_PANIC(("MOV_DqRq: GD bit not supported yet"));
// Note: processor clears GD upon entering debug exception
// handler, to allow access to the debug registers
}
if ( (((val_64>>16) & 3)==2) ||
(((val_64>>20) & 3)==2) ||
(((val_64>>24) & 3)==2) ||
(((val_64>>28) & 3)==2) ) {
// IO breakpoints (10b) are not yet supported.
BX_PANIC(("MOV_DqRq: write of %08x contains IO breakpoint",
val_64));
}
if ( (((val_64>>18) & 3)==2) ||
(((val_64>>22) & 3)==2) ||
(((val_64>>26) & 3)==2) ||
(((val_64>>30) & 3)==2) ) {
// LEN0..3 contains undefined length specifier (10b)
BX_PANIC(("MOV_DqRq: write of %08x contains undefined LENx",
val_64));
}
if ( ((((val_64>>16) & 3)==0) && (((val_64>>18) & 3)!=0)) ||
((((val_64>>20) & 3)==0) && (((val_64>>22) & 3)!=0)) ||
((((val_64>>24) & 3)==0) && (((val_64>>26) & 3)!=0)) ||
((((val_64>>28) & 3)==0) && (((val_64>>30) & 3)!=0)) ) {
// Instruction breakpoint with LENx not 00b (1-byte length)
BX_PANIC(("MOV_DqRq: write of %08x, R/W=00b LEN!=00b",
val_64));
}
#if BX_CPU_LEVEL <= 4
// 386/486: you can play with all the bits except b10 is always 1
BX_CPU_THIS_PTR dr7 = val_64 | 0x00000400;
#else
// Pentium+: bits15,14,12 are hardwired to 0, rest are settable.
// Even bits 11,10 are changeable though reserved.
BX_CPU_THIS_PTR dr7 = (val_64 & 0xffff2fff) | 0x00000400;
#endif
break;
default:
BX_PANIC(("MOV_DqRq: control register index out of range"));
break;
}
}
#endif // #if BX_SUPPORT_X86_64
#if BX_SUPPORT_X86_64
void
BX_CPU_C::MOV_RqDq(bxInstruction_c *i)
{
Bit64u val_64;
if (v8086_mode()) {
BX_INFO(("MOV_RqDq: v8086 mode causes #GP"));
exception(BX_GP_EXCEPTION, 0, 0);
}
if (!i->modC0()) {
BX_PANIC(("MOV_RqDq(): rm field not a register!"));
UndefinedOpcode(i);
}
if (protected_mode() && (CPL!=0)) {
BX_INFO(("MOV_RqDq: CPL!=0 causes #GP"));
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
if (bx_dbg.dreg)
BX_INFO(("MOV_RqDq: DR%u not implemented yet", i->nnn()));
switch (i->nnn()) {
case 0: // DR0
val_64 = BX_CPU_THIS_PTR dr0;
break;
case 1: // DR1
val_64 = BX_CPU_THIS_PTR dr1;
break;
case 2: // DR2
val_64 = BX_CPU_THIS_PTR dr2;
break;
case 3: // DR3
val_64 = BX_CPU_THIS_PTR dr3;
break;
case 4: // DR4
case 6: // DR6
// DR4 aliased to DR6 by default. With Debug Extensions on,
// access to DR4 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 4) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions on
BX_INFO(("MOV_RqDq: access to DR4 causes #UD"));
UndefinedOpcode(i);
}
#endif
val_64 = BX_CPU_THIS_PTR dr6;
break;
case 5: // DR5
case 7: // DR7
// DR5 aliased to DR7 by default. With Debug Extensions on,
// access to DR5 causes #UD
#if BX_CPU_LEVEL >= 4
if ( (i->nnn() == 5) && (BX_CPU_THIS_PTR cr4.get_DE()) ) {
// Debug extensions on
BX_INFO(("MOV_RqDq: access to DR5 causes #UD"));
UndefinedOpcode(i);
}
#endif
val_64 = BX_CPU_THIS_PTR dr7;
break;
default:
BX_PANIC(("MOV_RqDq: control register index out of range"));
val_64 = 0;
}
BX_WRITE_64BIT_REG(i->rm(), val_64);
}
#endif // #if BX_SUPPORT_X86_64
void
BX_CPU_C::LMSW_Ew(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
BX_PANIC(("LMSW_Ew(): not supported on 8086!"));
#else
Bit16u msw;
Bit32u cr0;
invalidate_prefetch_q();
if (v8086_mode()) BX_PANIC(("proc_ctrl: LMSW in v8086 mode unsupported"));
if ( protected_mode() ) {
if ( CPL != 0 ) {
BX_INFO(("LMSW: CPL != 0, CPL=%u", (unsigned) CPL));
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
}
if (i->modC0()) {
msw = BX_READ_16BIT_REG(i->rm());
}
else {
read_virtual_word(i->seg(), RMAddr(i), &msw);
}
// LMSW does not affect PG,CD,NW,AM,WP,NE,ET bits, and cannot clear PE
// LMSW cannot clear PE
if ( ((msw & 0x0001)==0) && BX_CPU_THIS_PTR cr0.pe ) {
msw |= 0x0001; // adjust PE bit to current value of 1
}
msw &= 0x000f; // LMSW only affects last 4 flags
cr0 = (BX_CPU_THIS_PTR cr0.val32 & 0xfffffff0) | msw;
SetCR0(cr0);
#endif /* BX_CPU_LEVEL < 2 */
}
void
BX_CPU_C::SMSW_Ew(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
BX_PANIC(("SMSW_Ew: not supported yet!"));
#else
Bit16u msw;
#if BX_CPU_LEVEL == 2
msw = 0xfff0; /* 80286 init value */
msw |= (BX_CPU_THIS_PTR cr0.ts << 3) |
(BX_CPU_THIS_PTR cr0.em << 2) |
(BX_CPU_THIS_PTR cr0.mp << 1) |
BX_CPU_THIS_PTR cr0.pe;
#else /* 386+ */
/* reserved bits 0 ??? */
/* should NE bit be included here ??? */
// should ET bit be included here (AW)
msw = (BX_CPU_THIS_PTR cr0.ts << 3) |
(BX_CPU_THIS_PTR cr0.em << 2) |
(BX_CPU_THIS_PTR cr0.mp << 1) |
BX_CPU_THIS_PTR cr0.pe;
#endif
if (i->modC0()) {
if (i->os32L()) {
BX_WRITE_32BIT_REGZ(i->rm(), msw); // zeros out high 16bits
}
else {
BX_WRITE_16BIT_REG(i->rm(), msw);
}
}
else {
write_virtual_word(i->seg(), RMAddr(i), &msw);
}
#endif
}
void
BX_CPU_C::MOV_CdRd(bxInstruction_c *i)
{
// mov general register data to control register
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_CdRd: not supported on < 386"));
#else
Bit32u val_32;
/* if (v8086_mode()) BX_PANIC(("proc_ctrl: MOV_CdRd in v8086 mode unsupported"));*/
/* NOTES:
* 32bit operands always used
* r/m field specifies general register
* mod field should always be 11 binary
* reg field specifies which special register
*/
if (!i->modC0()) {
BX_PANIC(("MOV_CdRd(): rm field not a register!"));
}
invalidate_prefetch_q();
if ((protected_mode() || v8086_mode()) && CPL!=0) {
BX_PANIC(("MOV_CdRd: CPL!=0"));
/* #GP(0) if CPL is not 0 */
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
val_32 = BX_READ_32BIT_REG(i->rm());
switch (i->nnn()) {
case 0: // CR0 (MSW)
// BX_INFO(("MOV_CdRd:CR0: R32 = %08x @CS:EIP %04x:%04x ",
// (unsigned) val_32,
// (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
// (unsigned) EIP));
SetCR0(val_32);
break;
case 1: /* CR1 */
BX_PANIC(("MOV_CdRd: CR1 not implemented yet"));
break;
case 2: /* CR2 */
2001-08-25 01:02:37 +04:00
BX_DEBUG(("MOV_CdRd: CR2 not implemented yet"));
BX_DEBUG(("MOV_CdRd: CR2 = reg"));
BX_CPU_THIS_PTR cr2 = val_32;
break;
case 3: // CR3
if (bx_dbg.creg)
BX_INFO(("MOV_CdRd:CR3 = %08x", (unsigned) val_32));
// Reserved bits take on value of MOV instruction
CR3_change(val_32);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_32);
// Reload of CR3 always serializes.
// invalidate_prefetch_q(); // Already done.
break;
case 4: // CR4
{
#if BX_CPU_LEVEL == 3
BX_PANIC(("MOV_CdRd: write to CR4 of 0x%08x on 386",
val_32));
UndefinedOpcode(i);
#else
// Protected mode: #GP(0) if attempt to write a 1 to
// any reserved bit of CR4
SetCR4(val_32);
#endif
}
break;
default:
BX_PANIC(("MOV_CdRd: control register index out of range"));
break;
}
#endif
}
void
BX_CPU_C::MOV_RdCd(bxInstruction_c *i)
{
// mov control register data to register
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_RdCd: not supported on < 386"));
#else
Bit32u val_32;
/* if (v8086_mode()) BX_PANIC(("proc_ctrl: MOV_RdCd in v8086 mode unsupported"));*/
/* NOTES:
* 32bit operands always used
* r/m field specifies general register
* mod field should always be 11 binary
* reg field specifies which special register
*/
if (!i->modC0()) {
BX_PANIC(("MOV_RdCd(): rm field not a register!"));
}
if ((protected_mode() || v8086_mode()) && CPL!=0) {
BX_INFO(("MOV_RdCd: CPL!=0"));
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
switch (i->nnn()) {
case 0: // CR0 (MSW)
val_32 = BX_CPU_THIS_PTR cr0.val32;
#if 0
BX_INFO(("MOV_RdCd:CR0: R32 = %08x @CS:EIP %04x:%04x",
(unsigned) val_32,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
(unsigned) EIP));
#endif
break;
case 1: /* CR1 */
BX_PANIC(("MOV_RdCd: CR1 not implemented yet"));
val_32 = 0;
break;
case 2: /* CR2 */
if (bx_dbg.creg)
BX_INFO(("MOV_RdCd: CR2"));
val_32 = BX_CPU_THIS_PTR cr2;
break;
case 3: // CR3
if (bx_dbg.creg)
BX_INFO(("MOV_RdCd: reading CR3"));
val_32 = BX_CPU_THIS_PTR cr3;
break;
case 4: // CR4
#if BX_CPU_LEVEL == 3
val_32 = 0;
BX_INFO(("MOV_RdCd: read of CR4 causes #UD"));
UndefinedOpcode(i);
#else
BX_INFO(("MOV_RdCd: read of CR4"));
val_32 = BX_CPU_THIS_PTR cr4.getRegister();
#endif
break;
default:
BX_PANIC(("MOV_RdCd: control register index out of range"));
val_32 = 0;
}
BX_WRITE_32BIT_REGZ(i->rm(), val_32);
#endif
}
#if BX_SUPPORT_X86_64
void
BX_CPU_C::MOV_CqRq(bxInstruction_c *i)
{
// mov general register data to control register
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_CqRq: not supported on < 386"));
#else
Bit64u val_64;
if (v8086_mode()) BX_PANIC(("proc_ctrl: v8086 mode unsupported"));
/* NOTES:
* 64bit operands always used
* r/m field specifies general register
* mod field should always be 11 binary
* reg field specifies which special register
*/
if (!i->modC0()) {
BX_PANIC(("MOV_CqRq(): rm field not a register!"));
}
invalidate_prefetch_q();
if (protected_mode() && CPL!=0) {
BX_PANIC(("MOV_CqRq: CPL!=0"));
/* #GP(0) if CPL is not 0 */
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
val_64 = BX_READ_64BIT_REG(i->rm());
switch (i->nnn()) {
case 0: // CR0 (MSW)
// BX_INFO(("MOV_CqRq:CR0: R64 = %08x @CS:EIP %04x:%04x ",
// (unsigned) val_64,
// (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
// (unsigned) EIP));
SetCR0(val_64);
break;
case 1: /* CR1 */
BX_PANIC(("MOV_CqRq: CR1 not implemented yet"));
break;
case 2: /* CR2 */
BX_DEBUG(("MOV_CqRq: CR2 not implemented yet"));
BX_DEBUG(("MOV_CqRq: CR2 = reg"));
BX_CPU_THIS_PTR cr2 = val_64;
break;
case 3: // CR3
if (bx_dbg.creg)
BX_INFO(("MOV_CqRq:CR3 = %08x", (unsigned) val_64));
// Reserved bits take on value of MOV instruction
CR3_change(val_64);
BX_INSTR_TLB_CNTRL(BX_CPU_ID, BX_INSTR_MOV_CR3, val_64);
break;
case 4: // CR4
#if BX_CPU_LEVEL == 3
BX_PANIC(("MOV_CqRq: write to CR4 of 0x%08x on 386",
val_64));
UndefinedOpcode(i);
#else
// Protected mode: #GP(0) if attempt to write a 1 to
// any reserved bit of CR4
BX_INFO(("MOV_CqRq: ignoring write to CR4 of 0x%08x", val_64));
if (val_64) {
BX_INFO(("MOV_CqRq: (CR4) write of 0x%08x not supported!", val_64));
}
// Only allow writes of 0 to CR4 for now.
// Writes to bits in CR4 should not be 1s as CPUID
// returns not-supported for all of these features.
SetCR4(val_64);
#endif
break;
default:
BX_PANIC(("MOV_CqRq: control register index out of range"));
break;
}
#endif
}
#endif // #if BX_SUPPORT_X86_64
#if BX_SUPPORT_X86_64
void
BX_CPU_C::MOV_RqCq(bxInstruction_c *i)
{
// mov control register data to register
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_RqCq: not supported on < 386"));
#else
Bit64u val_64;
if (v8086_mode()) BX_PANIC(("proc_ctrl: v8086 mode unsupported"));
/* NOTES:
* 64bit operands always used
* r/m field specifies general register
* mod field should always be 11 binary
* reg field specifies which special register
*/
if (!i->modC0()) {
BX_PANIC(("MOV_RqC(): rm field not a register!"));
}
if (protected_mode() && CPL!=0) {
BX_PANIC(("MOV_RqCq: CPL!=0"));
/* #GP(0) if CPL is not 0 */
exception(BX_GP_EXCEPTION, 0, 0);
return;
}
switch (i->nnn()) {
case 0: // CR0 (MSW)
val_64 = BX_CPU_THIS_PTR cr0.val32;
#if 0
BX_INFO(("MOV_RqCq:CR0: R64 = %08x @CS:EIP %04x:%04x",
(unsigned) val_64,
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value,
(unsigned) EIP));
#endif
break;
case 1: /* CR1 */
BX_PANIC(("MOV_RqCq: CR1 not implemented yet"));
val_64 = 0;
break;
case 2: /* CR2 */
if (bx_dbg.creg)
BX_INFO(("MOV_RqCq: CR2"));
val_64 = BX_CPU_THIS_PTR cr2;
break;
case 3: // CR3
if (bx_dbg.creg)
BX_INFO(("MOV_RqCq: reading CR3"));
val_64 = BX_CPU_THIS_PTR cr3;
break;
case 4: // CR4
#if BX_CPU_LEVEL == 3
val_64 = 0;
BX_INFO(("MOV_RqCq: read of CR4 causes #UD"));
UndefinedOpcode(i);
#else
BX_INFO(("MOV_RqCq: read of CR4"));
val_64 = BX_CPU_THIS_PTR cr4.getRegister();
#endif
break;
default:
BX_PANIC(("MOV_RqCq: control register index out of range"));
val_64 = 0;
}
BX_WRITE_64BIT_REG(i->rm(), val_64);
#endif
}
#endif // #if BX_SUPPORT_X86_64
void
BX_CPU_C::MOV_TdRd(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_TdRd:"));
#elif BX_CPU_LEVEL <= 4
BX_PANIC(("MOV_TdRd:"));
#else
// Pentium+ does not have TRx. They were redesigned using the MSRs.
BX_INFO(("MOV_TdRd: causes #UD"));
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::MOV_RdTd(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 3
BX_PANIC(("MOV_RdTd:"));
#elif BX_CPU_LEVEL <= 4
BX_PANIC(("MOV_RdTd:"));
#else
// Pentium+ does not have TRx. They were redesigned using the MSRs.
BX_INFO(("MOV_RdTd: causes #UD"));
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::LOADALL(bxInstruction_c *i)
{
#if BX_CPU_LEVEL < 2
BX_PANIC(("undocumented LOADALL instruction not supported on 8086"));
#else
Bit16u msw, tr, flags, ip, ldtr;
Bit16u ds_raw, ss_raw, cs_raw, es_raw;
Bit16u di, si, bp, sp, bx, dx, cx, ax;
Bit16u base_15_0, limit;
Bit8u base_23_16, access;
if (v8086_mode()) BX_PANIC(("proc_ctrl: LOADALL in v8086 mode unsupported"));
#if BX_CPU_LEVEL > 2
BX_PANIC(("loadall: not implemented for 386"));
/* ??? need to set G and other bits, and compute .limit_scaled also */
/* for all segments CS,DS,SS,... */
#endif
if (BX_CPU_THIS_PTR cr0.pe) {
BX_PANIC((
"LOADALL not yet supported for protected mode"));
}
BX_PANIC(("LOADALL: handle CR0.val32"));
/* MSW */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x806, 2, &msw);
BX_CPU_THIS_PTR cr0.pe = (msw & 0x01); msw >>= 1;
BX_CPU_THIS_PTR cr0.mp = (msw & 0x01); msw >>= 1;
BX_CPU_THIS_PTR cr0.em = (msw & 0x01); msw >>= 1;
BX_CPU_THIS_PTR cr0.ts = (msw & 0x01);
//BX_INFO(("LOADALL: pe=%u, mp=%u, em=%u, ts=%u",
// (unsigned) BX_CPU_THIS_PTR cr0.pe, (unsigned) BX_CPU_THIS_PTR cr0.mp,
// (unsigned) BX_CPU_THIS_PTR cr0.em, (unsigned) BX_CPU_THIS_PTR cr0.ts));
if (BX_CPU_THIS_PTR cr0.pe || BX_CPU_THIS_PTR cr0.mp || BX_CPU_THIS_PTR cr0.em || BX_CPU_THIS_PTR cr0.ts)
BX_PANIC(("LOADALL set PE, MP, EM or TS bits in MSW!"));
/* TR */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x816, 2, &tr);
BX_CPU_THIS_PTR tr.selector.value = tr;
BX_CPU_THIS_PTR tr.selector.rpl = (tr & 0x03); tr >>= 2;
BX_CPU_THIS_PTR tr.selector.ti = (tr & 0x01); tr >>= 1;
BX_CPU_THIS_PTR tr.selector.index = tr;
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x860, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x862, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x863, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x864, 2, &limit);
BX_CPU_THIS_PTR tr.cache.valid =
BX_CPU_THIS_PTR tr.cache.p = (access & 0x80) >> 7;
BX_CPU_THIS_PTR tr.cache.dpl = (access & 0x60) >> 5;
BX_CPU_THIS_PTR tr.cache.segment = (access & 0x10) >> 4;
// don't allow busy bit in tr.cache.type, so bit 2 is masked away too.
BX_CPU_THIS_PTR tr.cache.type = (access & 0x0d);
BX_CPU_THIS_PTR tr.cache.u.tss286.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR tr.cache.u.tss286.limit = limit;
if ( (BX_CPU_THIS_PTR tr.selector.value & 0xfffc) == 0 ) {
BX_CPU_THIS_PTR tr.cache.valid = 0;
}
if ( BX_CPU_THIS_PTR tr.cache.valid == 0 ) {
}
if ( BX_CPU_THIS_PTR tr.cache.u.tss286.limit < 43 ) {
BX_CPU_THIS_PTR tr.cache.valid = 0;
}
if ( BX_CPU_THIS_PTR tr.cache.type != 1 ) {
BX_CPU_THIS_PTR tr.cache.valid = 0;
}
if ( BX_CPU_THIS_PTR tr.cache.segment ) {
BX_CPU_THIS_PTR tr.cache.valid = 0;
}
if (BX_CPU_THIS_PTR tr.cache.valid==0) {
BX_CPU_THIS_PTR tr.cache.u.tss286.base = 0;
BX_CPU_THIS_PTR tr.cache.u.tss286.limit = 0;
BX_CPU_THIS_PTR tr.cache.p = 0;
BX_CPU_THIS_PTR tr.selector.value = 0;
BX_CPU_THIS_PTR tr.selector.index = 0;
BX_CPU_THIS_PTR tr.selector.ti = 0;
BX_CPU_THIS_PTR tr.selector.rpl = 0;
}
/* FLAGS */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x818, 2, &flags);
write_flags(flags, 1, 1);
/* IP */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x81a, 2, &ip);
IP = ip;
/* LDTR */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x81c, 2, &ldtr);
BX_CPU_THIS_PTR ldtr.selector.value = ldtr;
BX_CPU_THIS_PTR ldtr.selector.rpl = (ldtr & 0x03); ldtr >>= 2;
BX_CPU_THIS_PTR ldtr.selector.ti = (ldtr & 0x01); ldtr >>= 1;
BX_CPU_THIS_PTR ldtr.selector.index = ldtr;
if ( (BX_CPU_THIS_PTR ldtr.selector.value & 0xfffc) == 0 ) {
BX_CPU_THIS_PTR ldtr.cache.valid = 0;
BX_CPU_THIS_PTR ldtr.cache.p = 0;
BX_CPU_THIS_PTR ldtr.cache.segment = 0;
BX_CPU_THIS_PTR ldtr.cache.type = 0;
BX_CPU_THIS_PTR ldtr.cache.u.ldt.base = 0;
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit = 0;
BX_CPU_THIS_PTR ldtr.selector.value = 0;
BX_CPU_THIS_PTR ldtr.selector.index = 0;
BX_CPU_THIS_PTR ldtr.selector.ti = 0;
}
else {
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x854, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x856, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x857, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x858, 2, &limit);
BX_CPU_THIS_PTR ldtr.cache.valid =
BX_CPU_THIS_PTR ldtr.cache.p = access >> 7;
BX_CPU_THIS_PTR ldtr.cache.dpl = (access >> 5) & 0x03;
BX_CPU_THIS_PTR ldtr.cache.segment = (access >> 4) & 0x01;
BX_CPU_THIS_PTR ldtr.cache.type = (access & 0x0f);
BX_CPU_THIS_PTR ldtr.cache.u.ldt.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR ldtr.cache.u.ldt.limit = limit;
if (access == 0) {
BX_PANIC(("loadall: LDTR case access byte=0."));
}
if ( BX_CPU_THIS_PTR ldtr.cache.valid==0 ) {
BX_PANIC(("loadall: ldtr.valid=0"));
}
if (BX_CPU_THIS_PTR ldtr.cache.segment) { /* not a system segment */
BX_INFO((" AR byte = %02x", (unsigned) access));
BX_PANIC(("loadall: LDTR descriptor cache loaded with non system segment"));
}
if ( BX_CPU_THIS_PTR ldtr.cache.type != 2 ) {
BX_PANIC(("loadall: LDTR.type(%u) != 2", (unsigned) (access & 0x0f)));
}
}
/* DS */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x81e, 2, &ds_raw);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value = ds_raw;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl = (ds_raw & 0x03); ds_raw >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.ti = (ds_raw & 0x01); ds_raw >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.index = ds_raw;
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x848, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x84a, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x84b, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x84c, 2, &limit);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.limit = limit;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.a = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.r_w = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.u.segment.executable = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.dpl = (access & 0x03); access >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid =
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.p = (access & 0x01);
if ( (BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.value & 0xfffc) == 0 ) {
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid = 0;
}
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.valid==0 ||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].cache.segment==0) {
BX_PANIC(("loadall: DS invalid"));
}
/* SS */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x820, 2, &ss_raw);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = ss_raw;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = (ss_raw & 0x03); ss_raw >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = (ss_raw & 0x01); ss_raw >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = ss_raw;
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x842, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x844, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x845, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x846, 2, &limit);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = limit;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl = (access & 0x03); access >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.p = (access & 0x01);
if ( (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value & 0xfffc) == 0 ) {
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid = 0;
}
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.valid==0 ||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.segment==0) {
BX_PANIC(("loadall: SS invalid"));
}
/* CS */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x822, 2, &cs_raw);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = cs_raw;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = (cs_raw & 0x03); cs_raw >>= 2;
//BX_INFO(("LOADALL: setting cs.selector.rpl to %u",
// (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl));
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = (cs_raw & 0x01); cs_raw >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = cs_raw;
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x83c, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x83e, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x83f, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x840, 2, &limit);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = limit;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl = (access & 0x03); access >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.p = (access & 0x01);
if ( (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value & 0xfffc) == 0 ) {
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid = 0;
}
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.valid==0 ||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.segment==0) {
BX_PANIC(("loadall: CS invalid"));
}
/* ES */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x824, 2, &es_raw);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value = es_raw;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl = (es_raw & 0x03); es_raw >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.ti = (es_raw & 0x01); es_raw >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.index = es_raw;
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x836, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x838, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x839, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x83a, 2, &limit);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.limit = limit;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.a = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.r_w = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.c_ed = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.u.segment.executable = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.segment = (access & 0x01); access >>= 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.dpl = (access & 0x03); access >>= 2;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.p = (access & 0x01);
#if 0
BX_INFO(("cs.dpl = %02x", (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.dpl));
BX_INFO(("ss.dpl = %02x", (unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.dpl));
BX_INFO(("BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].dpl = %02x", (unsigned) BX_CPU_THIS_PTR ds.cache.dpl));
BX_INFO(("BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].dpl = %02x", (unsigned) BX_CPU_THIS_PTR es.cache.dpl));
BX_INFO(("LOADALL: setting cs.selector.rpl to %u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl));
BX_INFO(("LOADALL: setting ss.selector.rpl to %u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl));
BX_INFO(("LOADALL: setting ds.selector.rpl to %u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_DS].selector.rpl));
BX_INFO(("LOADALL: setting es.selector.rpl to %u",
(unsigned) BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.rpl));
#endif
if ( (BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].selector.value & 0xfffc) == 0 ) {
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid = 0;
}
if (BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.valid==0 ||
BX_CPU_THIS_PTR sregs[BX_SEG_REG_ES].cache.segment==0) {
BX_PANIC(("loadall: ES invalid"));
}
/* DI */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x826, 2, &di);
DI = di;
/* SI */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x828, 2, &si);
SI = si;
/* BP */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x82a, 2, &bp);
BP = bp;
/* SP */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x82c, 2, &sp);
SP = sp;
/* BX */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x82e, 2, &bx);
BX = bx;
/* DX */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x830, 2, &dx);
DX = dx;
/* CX */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x832, 2, &cx);
CX = cx;
/* AX */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x834, 2, &ax);
AX = ax;
/* GDTR */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x84e, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x850, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x851, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x852, 2, &limit);
BX_CPU_THIS_PTR gdtr.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR gdtr.limit = limit;
#if 0
if (access)
BX_INFO(("LOADALL: GDTR access bits not 0 (%02x).",
(unsigned) access));
#endif
/* IDTR */
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x85a, 2, &base_15_0);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x85c, 1, &base_23_16);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x85d, 1, &access);
BX_CPU_THIS_PTR mem->readPhysicalPage(this, 0x85e, 2, &limit);
BX_CPU_THIS_PTR idtr.base = (base_23_16 << 16) | base_15_0;
BX_CPU_THIS_PTR idtr.limit = limit;
#endif
}
void
BX_CPU_C::SetCR0(Bit32u val_32)
{
// from either MOV_CdRd() or debug functions
// protection checks made already or forcing from debug
- Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a "bx_bool" which is always defined as Bit32u on all platforms. In Carbon specific code, Boolean is still used because the Carbon header files define it to unsigned char. - this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95. The bug was that some code in Bochs depends on Boolean to be a 32 bit value. (This should be fixed, but I don't know all the places where it needs to be fixed yet.) Because Carbon defined Boolean as an unsigned char, Bochs just followed along and used the unsigned char definition to avoid compile problems. This exposed the dependency on 32 bit Boolean on MacOS X only and led to major simulation problems, that could only be reproduced and debugged on that platform. - On the mailing list we debated whether to make all Booleans into "bool" or our own type. I chose bx_bool for several reasons. 1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all platforms, which makes it much less likely to have more platform-specific simulation differences in the future. (I spent hours on a borrowed MacOSX machine chasing bug 618388 before discovering that different sized Booleans were the problem, and I don't want to repeat that.) 2. We still have at least one dependency on 32 bit Booleans which must be fixed some time, but I don't want to risk introducing new bugs into the simulation just before the 2.0 release. Modified Files: bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile docs-html/cosimulation.html fpu/wmFPUemu_glue.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h gui/x.cc instrument/example0/instrument.cc instrument/example0/instrument.h instrument/example1/instrument.cc instrument/example1/instrument.h instrument/stubs/instrument.cc instrument/stubs/instrument.h iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc iodev/eth_packetmaker.cc iodev/eth_packetmaker.h iodev/floppy.cc iodev/floppy.h iodev/guest2host.h iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 15:44:41 +04:00
bx_bool prev_pe, prev_pg;
Bit32u oldCR0 = BX_CPU_THIS_PTR cr0.val32, newCR0;
prev_pe = BX_CPU_THIS_PTR cr0.pe;
prev_pg = BX_CPU_THIS_PTR cr0.pg;
BX_CPU_THIS_PTR cr0.pe = val_32 & 0x01;
BX_CPU_THIS_PTR cr0.mp = (val_32 >> 1) & 0x01;
BX_CPU_THIS_PTR cr0.em = (val_32 >> 2) & 0x01;
BX_CPU_THIS_PTR cr0.ts = (val_32 >> 3) & 0x01;
// cr0.et is hardwired to 1
#if BX_CPU_LEVEL >= 4
BX_CPU_THIS_PTR cr0.ne = (val_32 >> 5) & 0x01;
BX_CPU_THIS_PTR cr0.wp = (val_32 >> 16) & 0x01;
BX_CPU_THIS_PTR cr0.am = (val_32 >> 18) & 0x01;
BX_CPU_THIS_PTR cr0.nw = (val_32 >> 29) & 0x01;
BX_CPU_THIS_PTR cr0.cd = (val_32 >> 30) & 0x01;
#endif
BX_CPU_THIS_PTR cr0.pg = (val_32 >> 31) & 0x01;
// handle reserved bits behaviour
#if BX_CPU_LEVEL == 3
newCR0 = val_32 | 0x7ffffff0;
#elif BX_CPU_LEVEL == 4
newCR0 = (val_32 | 0x00000010) & 0xe005003f;
#elif BX_CPU_LEVEL == 5
newCR0 = val_32 | 0x00000010;
#elif BX_CPU_LEVEL == 6
newCR0 = (val_32 | 0x00000010) & 0xe005003f;
#else
#error "MOV_CdRd: implement reserved bits behaviour for this CPU_LEVEL"
#endif
BX_CPU_THIS_PTR cr0.val32 = newCR0;
//if (BX_CPU_THIS_PTR cr0.ts)
// BX_INFO(("MOV_CdRd:CR0.TS set 0x%x", (unsigned) val_32));
if (prev_pe==0 && BX_CPU_THIS_PTR cr0.pe) {
enter_protected_mode();
if (BX_CPU_THIS_PTR get_VM()) BX_PANIC(("EFLAGS.VM=1, enter_PM"));
BX_CPU_THIS_PTR protectedMode = 1;
BX_CPU_THIS_PTR v8086Mode = 0;
BX_CPU_THIS_PTR realMode = 0;
}
else if (prev_pe==1 && BX_CPU_THIS_PTR cr0.pe==0) {
enter_real_mode();
BX_CPU_THIS_PTR protectedMode = 0;
BX_CPU_THIS_PTR v8086Mode = 0;
BX_CPU_THIS_PTR realMode = 1;
}
#if BX_SUPPORT_X86_64
if (prev_pg==0 && BX_CPU_THIS_PTR cr0.pg) {
if (BX_CPU_THIS_PTR msr.lme) {
if (!BX_CPU_THIS_PTR cr4.get_PAE()) {
BX_PANIC(("SetCR0: attempt to enter x86-64 LONG mode without enabling CR4.PAE !!!"));
exception(BX_GP_EXCEPTION, 0, 0);
}
BX_CPU_THIS_PTR msr.lma = 1;
BX_CPU_THIS_PTR cpu_mode = BX_MODE_LONG_COMPAT;
#if BX_EXTERNAL_DEBUGGER
//trap_debugger(0);
#endif
}
}
else if (prev_pg==1 && BX_CPU_THIS_PTR cr0.pg==0) {
if (BX_CPU_THIS_PTR msr.lma) {
if (BX_CPU_THIS_PTR dword.rip_upper != 0) {
BX_PANIC(("SetCR0: attempt to leave x86-64 LONG mode with RIP upper != 0 !!!"));
}
BX_CPU_THIS_PTR msr.lma = 0;
BX_CPU_THIS_PTR cpu_mode = BX_MODE_IA32;
#if BX_EXTERNAL_DEBUGGER
//trap_debugger(0);
#endif
}
}
#endif // #if BX_SUPPORT_X86_64
// Give the paging unit a chance to look for changes in bits
// it cares about, like {PG,PE}, so it can flush cache entries etc.
pagingCR0Changed(oldCR0, newCR0);
}
#if BX_CPU_LEVEL >= 4
void
BX_CPU_C::SetCR4(Bit32u val_32)
{
// CR4 bit definitions from AMD Hammer manual:
// [63-11] Reserved, Must be Zero
// [10] OSXMMEXCPT: Operating System Unmasked Exception Support R/W
// [9] OSFXSR: Operating System FXSAVE/FXRSTOR Support R/W
// [8] PCE: Performance-Monitoring Counter Enable R/W
// [7] PGE: Page-Global Enable R/W
// [6] MCE: Machine Check Enable R/W
// [5] PAE: Physical-Address Extension R/W
// [4] PSE: Page Size Extensions R/W
// [3] DE: Debugging Extensions R/W
// [2] TSD: Time Stamp Disable R/W
// [1] PVI: Protected-Mode Virtual Interrupts R/W
// [0] VME: Virtual-8086 Mode Extensions R/W
Bit32u allowMask = 0;
Bit32u oldCR4 = BX_CPU_THIS_PTR cr4.getRegister();
#if BX_SUPPORT_4MEG_PAGES
allowMask |= (1<<4);
#endif
#if BX_SupportGlobalPages
allowMask |= (1<<7);
#endif
#if BX_SupportPAE
allowMask |= (1<<5);
#endif
#if BX_CPU_LEVEL >= 6
allowMask |= (1<<9); /* OSFXSR */
#endif
#if BX_SUPPORT_SSE
2003-05-15 20:41:17 +04:00
allowMask |= (1<<10); /* OSXMMECPT */
#endif
#if BX_SUPPORT_X86_64
// need to GPF #0 if LME=1 and PAE=0
2003-05-15 20:41:17 +04:00
if ((BX_CPU_THIS_PTR msr.lme)
&& (!(val_32 >> 5) & 1)
2003-05-15 20:41:17 +04:00
&& (BX_CPU_THIS_PTR cr4.get_PAE()))
{
exception(BX_GP_EXCEPTION, 0, 0);
2003-05-15 20:41:17 +04:00
}
#endif
// Need to GPF if trying to set undefined bits.
if (val_32 & ~allowMask) {
2003-05-15 20:41:17 +04:00
BX_INFO(("#GP(0): SetCR4: Write of 0x%08x not supported (allowMask=0x%x)",
val_32, allowMask));
exception(BX_GP_EXCEPTION, 0, 0);
2003-05-15 20:41:17 +04:00
}
val_32 &= allowMask; // Screen out unsupported bits. (not needed, for good measure)
BX_CPU_THIS_PTR cr4.setRegister(val_32);
pagingCR4Changed(oldCR4, BX_CPU_THIS_PTR cr4.getRegister());
}
#endif
void
BX_CPU_C::RSM(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 4
invalidate_prefetch_q();
BX_PANIC(("RSM: System Management Mode not implemented yet"));
#else
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::RDPMC(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
BX_PANIC(("RDPMC: Performance Counters Support not implemented yet"));
#else
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::RDTSC(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
- Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a "bx_bool" which is always defined as Bit32u on all platforms. In Carbon specific code, Boolean is still used because the Carbon header files define it to unsigned char. - this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95. The bug was that some code in Bochs depends on Boolean to be a 32 bit value. (This should be fixed, but I don't know all the places where it needs to be fixed yet.) Because Carbon defined Boolean as an unsigned char, Bochs just followed along and used the unsigned char definition to avoid compile problems. This exposed the dependency on 32 bit Boolean on MacOS X only and led to major simulation problems, that could only be reproduced and debugged on that platform. - On the mailing list we debated whether to make all Booleans into "bool" or our own type. I chose bx_bool for several reasons. 1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all platforms, which makes it much less likely to have more platform-specific simulation differences in the future. (I spent hours on a borrowed MacOSX machine chasing bug 618388 before discovering that different sized Booleans were the problem, and I don't want to repeat that.) 2. We still have at least one dependency on 32 bit Booleans which must be fixed some time, but I don't want to risk introducing new bugs into the simulation just before the 2.0 release. Modified Files: bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile docs-html/cosimulation.html fpu/wmFPUemu_glue.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h gui/x.cc instrument/example0/instrument.cc instrument/example0/instrument.h instrument/example1/instrument.cc instrument/example1/instrument.h instrument/stubs/instrument.cc instrument/stubs/instrument.h iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc iodev/eth_packetmaker.cc iodev/eth_packetmaker.h iodev/floppy.cc iodev/floppy.h iodev/guest2host.h iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 15:44:41 +04:00
bx_bool tsd = BX_CPU_THIS_PTR cr4.get_TSD();
bx_bool cpl = CPL;
if ((tsd==0) || (tsd==1 && cpl==0)) {
// return ticks
Bit64u ticks = bx_pc_system.time_ticks ();
RAX = (Bit32u) (ticks & 0xffffffff);
RDX = (Bit32u) ((ticks >> 32) & 0xffffffff);
//BX_INFO(("RDTSC: returning EDX:EAX = %08x:%08x", EDX, EAX));
} else {
// not allowed to use RDTSC!
exception (BX_GP_EXCEPTION, 0, 0);
}
#else
UndefinedOpcode(i);
#endif
}
void
BX_CPU_C::RDMSR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
invalidate_prefetch_q();
if (v8086_mode()) {
BX_INFO(("RDMSR: Invalid whilst in virtual 8086 mode"));
goto do_exception;
}
if (CPL!= 0) {
BX_INFO(("RDMSR: CPL!= 0"));
goto do_exception;
}
/* We have the requested MSR register in ECX */
switch(ECX) {
#if BX_SUPPORT_SEP
case BX_MSR_SYSENTER_CS: { EAX = BX_CPU_THIS_PTR sysenter_cs_msr; EDX = 0; return; }
case BX_MSR_SYSENTER_ESP: { EAX = BX_CPU_THIS_PTR sysenter_esp_msr; EDX = 0; return; }
case BX_MSR_SYSENTER_EIP: { EAX = BX_CPU_THIS_PTR sysenter_eip_msr; EDX = 0; return; }
#endif
#if BX_CPU_LEVEL == 5
/* The following registers are defined for Pentium only */
case BX_MSR_P5_MC_ADDR:
case BX_MSR_MC_TYPE:
/* TODO */
return;
case BX_MSR_TSC:
RDTSC(i);
return;
case BX_MSR_CESR:
/* TODO */
return;
#else
/* These are noops on i686... */
case BX_MSR_P5_MC_ADDR:
case BX_MSR_MC_TYPE:
/* do nothing */
return;
case BX_MSR_TSC:
RDTSC(i);
return;
/* ... And these cause an exception on i686 */
case BX_MSR_CESR:
case BX_MSR_CTR0:
case BX_MSR_CTR1:
goto do_exception;
#endif /* BX_CPU_LEVEL == 5 */
/* MSR_APICBASE
0:7 Reserved
8 This is set if its the BSP
9:10 Reserved
11 APIC Global Enable bit (1=enabled 0=disabled)
12:35 APIC Base Address
36:63 Reserved
*/
case BX_MSR_APICBASE:
/* we return low 32 bits in EAX, and high in EDX */
RAX = Bit32u(BX_CPU_THIS_PTR msr.apicbase & 0xffffffff);
RDX = Bit32u(BX_CPU_THIS_PTR msr.apicbase >> 32);
BX_INFO(("RDMSR: Read %08x:%08x from MSR_APICBASE", EDX, EAX));
return;
#if BX_SUPPORT_X86_64
case BX_MSR_EFER:
RAX = (BX_CPU_THIS_PTR msr.sce << 0)
| (BX_CPU_THIS_PTR msr.lme << 8)
| (BX_CPU_THIS_PTR msr.lma << 10);
RDX = 0;
return;
case BX_MSR_STAR:
RAX = MSR_STAR;
RDX = MSR_STAR >> 32;
return;
case BX_MSR_LSTAR:
RAX = MSR_LSTAR;
RDX = MSR_LSTAR >> 32;
return;
case BX_MSR_CSTAR:
RAX = MSR_CSTAR;
RDX = MSR_CSTAR >> 32;
return;
case BX_MSR_FMASK:
RAX = MSR_FMASK;
RDX = MSR_FMASK >> 32;
return;
case BX_MSR_FSBASE:
RAX = MSR_FSBASE;
RDX = MSR_FSBASE >> 32;
return;
case BX_MSR_GSBASE:
RAX = MSR_GSBASE;
RDX = MSR_GSBASE >> 32;
return;
case BX_MSR_KERNELGSBASE:
RAX = MSR_KERNELGSBASE;
RDX = MSR_KERNELGSBASE >> 32;
return;
#endif // #if BX_SUPPORT_X86_64
default:
#if BX_IGNORE_BAD_MSR
BX_ERROR(("RDMSR: Unknown register %#x", ECX));
return;
#else
BX_PANIC(("RDMSR: Unknown register %#x", ECX));
#endif
goto do_exception;
}
#endif /* BX_CPU_LEVEL >= 5 */
do_exception:
exception(BX_GP_EXCEPTION, 0, 0);
}
void
BX_CPU_C::WRMSR(bxInstruction_c *i)
{
#if BX_CPU_LEVEL >= 5
invalidate_prefetch_q();
if (v8086_mode()) {
BX_INFO(("WRMSR: Invalid whilst in virtual 8086 mode"));
goto do_exception;
}
if (CPL!= 0) {
BX_INFO(("WDMSR: CPL!= 0"));
goto do_exception;
}
/* ECX has the MSR to write to */
switch(ECX) {
#if BX_SUPPORT_SEP
case BX_MSR_SYSENTER_CS: {
if (EAX & 3) BX_PANIC (("writing sysenter_cs_msr with non-kernel mode selector %X", EAX)); // not a bug according to book
BX_CPU_THIS_PTR sysenter_cs_msr = EAX; // ... but very stOOpid
return;
}
case BX_MSR_SYSENTER_ESP: { BX_CPU_THIS_PTR sysenter_esp_msr = EAX; return; }
case BX_MSR_SYSENTER_EIP: { BX_CPU_THIS_PTR sysenter_eip_msr = EAX; return; }
#endif
#if BX_CPU_LEVEL == 5
/* The following registers are defined for Pentium only */
case BX_MSR_P5_MC_ADDR:
case BX_MSR_MC_TYPE:
case BX_MSR_TSC:
case BX_MSR_CESR:
/* TODO */
return;
#else
/* These are noops on i686... */
case BX_MSR_P5_MC_ADDR:
case BX_MSR_MC_TYPE:
case BX_MSR_TSC:
/* do nothing */
return;
/* ... And these cause an exception on i686 */
case BX_MSR_CESR:
case BX_MSR_CTR0:
case BX_MSR_CTR1:
goto do_exception;
#endif /* BX_CPU_LEVEL == 5 */
/* MSR_APICBASE
0:7 Reserved
8 This is set if its the BSP
9:10 Reserved
11 APIC Global Enable bit (1=enabled 0=disabled)
12:35 APIC Base Address
36:63 Reserved
*/
case BX_MSR_APICBASE:
BX_CPU_THIS_PTR msr.apicbase = ((Bit64u) EDX << 32) + EAX;
BX_INFO(("WRMSR: wrote %08x:%08x to MSR_APICBASE", EDX, EAX));
return;
#if BX_SUPPORT_X86_64
case BX_MSR_EFER:
// GPF #0 if lme 0->1 and cr0.pg = 1
// GPF #0 if lme 1->0 and cr0.pg = 1
if ( (BX_CPU_THIS_PTR msr.lme != (EAX >> 8) & 1)
&& (BX_CPU_THIS_PTR cr0.pg == 1)) {
exception(BX_GP_EXCEPTION, 0, 0);
}
BX_CPU_THIS_PTR msr.sce = (EAX >> 0) & 1;
BX_CPU_THIS_PTR msr.lme = (EAX >> 8) & 1;
return;
case BX_MSR_STAR:
MSR_STAR = ((Bit64u) EDX << 32) + EAX;
return;
case BX_MSR_LSTAR:
MSR_LSTAR = ((Bit64u) EDX << 32) + EAX;
return;
case BX_MSR_CSTAR:
MSR_CSTAR = ((Bit64u) EDX << 32) + EAX;
return;
case BX_MSR_FMASK:
MSR_FMASK = ((Bit64u) EDX << 32) + EAX;
return;
case BX_MSR_FSBASE:
MSR_FSBASE = ((Bit64u) EDX << 32) + EAX;
return;
case BX_MSR_GSBASE:
MSR_GSBASE = ((Bit64u) EDX << 32) + EAX;
return;
case BX_MSR_KERNELGSBASE:
MSR_KERNELGSBASE = ((Bit64u) EDX << 32) + EAX;
return;
#endif // #if BX_SUPPORT_X86_64
default:
#if BX_IGNORE_BAD_MSR
BX_ERROR(("WRMSR: Unknown register %#x", ECX));
return;
#else
BX_PANIC(("WRMSR: Unknown register %#x", ECX));
#endif
goto do_exception;
}
#endif /* BX_CPU_LEVEL >= 5 */
do_exception:
exception(BX_GP_EXCEPTION, 0, 0);
}
void
BX_CPU_C::SYSENTER (bxInstruction_c *i)
{
#if BX_SUPPORT_SEP
if (!protected_mode ()) {
BX_INFO (("sysenter not from protected mode"));
exception (BX_GP_EXCEPTION, 0, 0);
return;
}
if (BX_CPU_THIS_PTR sysenter_cs_msr == 0) {
BX_INFO (("sysenter with zero sysenter_cs_msr"));
exception (BX_GP_EXCEPTION, 0, 0);
return;
}
invalidate_prefetch_q();
BX_CPU_THIS_PTR set_VM(0); // do this just like the book says to do
BX_CPU_THIS_PTR set_IF(0);
BX_CPU_THIS_PTR set_RF(0);
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = BX_CPU_THIS_PTR sysenter_cs_msr;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = BX_CPU_THIS_PTR sysenter_cs_msr >> 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = (BX_CPU_THIS_PTR sysenter_cs_msr >> 2) & 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = 1; // code segment
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = 0; // non-conforming
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = 1; // readable
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = 1; // accessed
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; // segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1; // 32-bit mode
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = BX_CPU_THIS_PTR sysenter_cs_msr + 8;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = (BX_CPU_THIS_PTR sysenter_cs_msr + 8) >> 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = (BX_CPU_THIS_PTR sysenter_cs_msr >> 2) & 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = 0;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = 0; // data segment
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = 0; // expand-up
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = 1; // writeable
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = 1; // accessed
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; // base address
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = 0xFFFF; // segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; // 4k granularity
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; // 32-bit mode
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; // available for use by system
// BX_INFO (("sysenter: old eip %X, esp %x, new eip %x, esp %X, edx %X", BX_CPU_THIS_PTR prev_eip, ESP, BX_CPU_THIS_PTR sysenter_eip_msr, BX_CPU_THIS_PTR sysenter_esp_msr, EDX));
ESP = BX_CPU_THIS_PTR sysenter_esp_msr;
EIP = BX_CPU_THIS_PTR sysenter_eip_msr;
#else
BX_INFO(("SYSENTER: use --enable-sep to enable SYSENTER/SYSEXIT support"));
UndefinedOpcode (i);
#endif
}
void
BX_CPU_C::SYSEXIT (bxInstruction_c *i)
{
#if BX_SUPPORT_SEP
if (!protected_mode ()) {
BX_INFO (("sysexit not from protected mode"));
exception (BX_GP_EXCEPTION, 0, 0);
return;
}
if (BX_CPU_THIS_PTR sysenter_cs_msr == 0) {
BX_INFO (("sysexit with zero sysenter_cs_msr"));
exception (BX_GP_EXCEPTION, 0, 0);
return;
}
if (CPL != 0) {
BX_INFO (("sysexit at non-zero cpl %u", CPL));
exception (BX_GP_EXCEPTION, 0, 0);
return;
}
invalidate_prefetch_q();
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value = (BX_CPU_THIS_PTR sysenter_cs_msr + 16) | 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.index = (BX_CPU_THIS_PTR sysenter_cs_msr + 16) >> 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.ti = (BX_CPU_THIS_PTR sysenter_cs_msr >> 2) & 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.rpl = 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.executable = 1; // code segment
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.c_ed = 0; // non-conforming
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.r_w = 1; // readable
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.a = 1; // accessed
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.base = 0; // base address
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit = 0xFFFF; // segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.g = 1; // 4k granularity
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.d_b = 1; // 32-bit mode
BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].cache.u.segment.avl = 0; // available for use by system
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value = (BX_CPU_THIS_PTR sysenter_cs_msr + 24) | 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.index = (BX_CPU_THIS_PTR sysenter_cs_msr + 24) >> 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.ti = (BX_CPU_THIS_PTR sysenter_cs_msr >> 2) & 1;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.rpl = 3;
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.executable = 0; // data segment
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.c_ed = 0; // expand-up
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.r_w = 1; // writeable
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.a = 1; // accessed
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.base = 0; // base address
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit = 0xFFFF; // segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.limit_scaled = 0xFFFFFFFF; // scaled segment limit
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.g = 1; // 4k granularity
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.d_b = 1; // 32-bit mode
BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].cache.u.segment.avl = 0; // available for use by system
// BX_INFO (("sysexit: old eip %X, esp %x, new eip %x, esp %X, eax %X", BX_CPU_THIS_PTR prev_eip, ESP, EDX, ECX, EAX));
ESP = ECX;
EIP = EDX;
#else
BX_INFO(("SYSEXIT: use --enable-sep to enable SYSENTER/SYSEXIT support"));
UndefinedOpcode (i);
#endif
}
#if BX_SUPPORT_X86_64
void BX_CPU_C::SWAPGS(bxInstruction_c *i)
{
Bit64u temp_GS_base;
if(CPL != 0)
exception(BX_GP_EXCEPTION, 0, 0);
temp_GS_base = MSR_GSBASE;
MSR_GSBASE = MSR_KERNELGSBASE;
MSR_KERNELGSBASE = temp_GS_base;
}
#endif
#if BX_X86_DEBUGGER
Bit32u BX_CPU_C::hwdebug_compare(Bit32u laddr_0, unsigned size,
unsigned opa, unsigned opb)
{
// Support x86 hardware debug facilities (DR0..DR7)
Bit32u dr7 = BX_CPU_THIS_PTR dr7;
- Apply patch.replace-Boolean rev 1.3. Every "Boolean" is now changed to a "bx_bool" which is always defined as Bit32u on all platforms. In Carbon specific code, Boolean is still used because the Carbon header files define it to unsigned char. - this fixes bug [ 623152 ] MacOSX: Triple Exception Booting win95. The bug was that some code in Bochs depends on Boolean to be a 32 bit value. (This should be fixed, but I don't know all the places where it needs to be fixed yet.) Because Carbon defined Boolean as an unsigned char, Bochs just followed along and used the unsigned char definition to avoid compile problems. This exposed the dependency on 32 bit Boolean on MacOS X only and led to major simulation problems, that could only be reproduced and debugged on that platform. - On the mailing list we debated whether to make all Booleans into "bool" or our own type. I chose bx_bool for several reasons. 1. Unlike C++'s bool, we can guarantee that bx_bool is the same size on all platforms, which makes it much less likely to have more platform-specific simulation differences in the future. (I spent hours on a borrowed MacOSX machine chasing bug 618388 before discovering that different sized Booleans were the problem, and I don't want to repeat that.) 2. We still have at least one dependency on 32 bit Booleans which must be fixed some time, but I don't want to risk introducing new bugs into the simulation just before the 2.0 release. Modified Files: bochs.h config.h.in gdbstub.cc logio.cc main.cc pc_system.cc pc_system.h plugin.cc plugin.h bios/rombios.c cpu/apic.cc cpu/arith16.cc cpu/arith32.cc cpu/arith64.cc cpu/arith8.cc cpu/cpu.cc cpu/cpu.h cpu/ctrl_xfer16.cc cpu/ctrl_xfer32.cc cpu/ctrl_xfer64.cc cpu/data_xfer16.cc cpu/data_xfer32.cc cpu/data_xfer64.cc cpu/debugstuff.cc cpu/exception.cc cpu/fetchdecode.cc cpu/flag_ctrl_pro.cc cpu/init.cc cpu/io_pro.cc cpu/lazy_flags.cc cpu/lazy_flags.h cpu/mult16.cc cpu/mult32.cc cpu/mult64.cc cpu/mult8.cc cpu/paging.cc cpu/proc_ctrl.cc cpu/segment_ctrl_pro.cc cpu/stack_pro.cc cpu/tasking.cc debug/dbg_main.cc debug/debug.h debug/sim2.cc disasm/dis_decode.cc disasm/disasm.h doc/docbook/Makefile docs-html/cosimulation.html fpu/wmFPUemu_glue.cc gui/amigaos.cc gui/beos.cc gui/carbon.cc gui/gui.cc gui/gui.h gui/keymap.cc gui/keymap.h gui/macintosh.cc gui/nogui.cc gui/rfb.cc gui/sdl.cc gui/siminterface.cc gui/siminterface.h gui/term.cc gui/win32.cc gui/wx.cc gui/wxmain.cc gui/wxmain.h gui/x.cc instrument/example0/instrument.cc instrument/example0/instrument.h instrument/example1/instrument.cc instrument/example1/instrument.h instrument/stubs/instrument.cc instrument/stubs/instrument.h iodev/cdrom.cc iodev/cdrom.h iodev/cdrom_osx.cc iodev/cmos.cc iodev/devices.cc iodev/dma.cc iodev/dma.h iodev/eth_arpback.cc iodev/eth_packetmaker.cc iodev/eth_packetmaker.h iodev/floppy.cc iodev/floppy.h iodev/guest2host.h iodev/harddrv.cc iodev/harddrv.h iodev/ioapic.cc iodev/ioapic.h iodev/iodebug.cc iodev/iodev.h iodev/keyboard.cc iodev/keyboard.h iodev/ne2k.h iodev/parallel.h iodev/pci.cc iodev/pci.h iodev/pic.h iodev/pit.cc iodev/pit.h iodev/pit_wrap.cc iodev/pit_wrap.h iodev/sb16.cc iodev/sb16.h iodev/serial.cc iodev/serial.h iodev/vga.cc iodev/vga.h memory/memory.h memory/misc_mem.cc
2002-10-25 15:44:41 +04:00
bx_bool ibpoint_found = 0;
Bit32u laddr_n = laddr_0 + (size - 1);
Bit32u dr0, dr1, dr2, dr3;
Bit32u dr0_n, dr1_n, dr2_n, dr3_n;
Bit32u len0, len1, len2, len3;
static unsigned alignment_mask[4] =
// 00b=1 01b=2 10b=undef 11b=4
{ 0xffffffff, 0xfffffffe, 0xffffffff, 0xfffffffc };
Bit32u dr0_op, dr1_op, dr2_op, dr3_op;
len0 = (dr7>>18) & 3;
len1 = (dr7>>22) & 3;
len2 = (dr7>>26) & 3;
len3 = (dr7>>30) & 3;
dr0 = BX_CPU_THIS_PTR dr0 & alignment_mask[len0];
dr1 = BX_CPU_THIS_PTR dr1 & alignment_mask[len1];
dr2 = BX_CPU_THIS_PTR dr2 & alignment_mask[len2];
dr3 = BX_CPU_THIS_PTR dr3 & alignment_mask[len3];
dr0_n = dr0 + len0;
dr1_n = dr1 + len1;
dr2_n = dr2 + len2;
dr3_n = dr3 + len3;
dr0_op = (dr7>>16) & 3;
dr1_op = (dr7>>20) & 3;
dr2_op = (dr7>>24) & 3;
dr3_op = (dr7>>28) & 3;
// See if this instruction address matches any breakpoints
if ( (dr7 & 0x00000003) ) {
if ( (dr0_op==opa || dr0_op==opb) &&
(laddr_0 <= dr0_n) &&
(laddr_n >= dr0) )
ibpoint_found = 1;
}
if ( (dr7 & 0x0000000c) ) {
if ( (dr1_op==opa || dr1_op==opb) &&
(laddr_0 <= dr1_n) &&
(laddr_n >= dr1) )
ibpoint_found = 1;
}
if ( (dr7 & 0x00000030) ) {
if ( (dr2_op==opa || dr2_op==opb) &&
(laddr_0 <= dr2_n) &&
(laddr_n >= dr2) )
ibpoint_found = 1;
}
if ( (dr7 & 0x000000c0) ) {
if ( (dr3_op==opa || dr3_op==opb) &&
(laddr_0 <= dr3_n) &&
(laddr_n >= dr3) )
ibpoint_found = 1;
}
// If *any* enabled breakpoints matched, then we need to
// set status bits for *all* breakpoints, even disabled ones,
// as long as they meet the other breakpoint criteria.
// This code is similar to that above, only without the
// breakpoint enabled check. Seems weird to duplicate effort,
// but its more efficient to do it this way.
if (ibpoint_found) {
// dr6_mask is the return value. These bits represent the bits to
// be OR'd into DR6 as a result of the debug event.
Bit32u dr6_mask=0;
if ( (dr0_op==opa || dr0_op==opb) &&
(laddr_0 <= dr0_n) &&
(laddr_n >= dr0) )
dr6_mask |= 0x01;
if ( (dr1_op==opa || dr1_op==opb) &&
(laddr_0 <= dr1_n) &&
(laddr_n >= dr1) )
dr6_mask |= 0x02;
if ( (dr2_op==opa || dr2_op==opb) &&
(laddr_0 <= dr2_n) &&
(laddr_n >= dr2) )
dr6_mask |= 0x04;
if ( (dr3_op==opa || dr3_op==opb) &&
(laddr_0 <= dr3_n) &&
(laddr_n >= dr3) )
dr6_mask |= 0x08;
return(dr6_mask);
}
return(0);
}
#endif