First v1.18.8 change: preliminary support for 80386 debug registers
This commit is contained in:
parent
a9229c6443
commit
6003e948b6
145 changed files with 1099 additions and 947 deletions
|
|
@ -1512,15 +1512,15 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* getAddr(dbgAddr, fWrite, cb)
|
||||
* getAddr(dbgAddr, fWrite, nb)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {{DbgAddr}} dbgAddr
|
||||
* @param {boolean} [fWrite]
|
||||
* @param {number} [cb] is number of bytes to check (1, 2 or 4); default is 1
|
||||
* @param {number} [nb] is number of bytes to check (1, 2 or 4); default is 1
|
||||
* @return {number} is the corresponding linear address, or X86.ADDR_INVALID
|
||||
*/
|
||||
Debugger.prototype.getAddr = function(dbgAddr, fWrite, cb)
|
||||
Debugger.prototype.getAddr = function(dbgAddr, fWrite, nb)
|
||||
{
|
||||
/*
|
||||
* Some addresses (eg, breakpoint addresses) save their original linear address in dbgAddr.addr,
|
||||
|
|
@ -1534,9 +1534,9 @@ if (DEBUGGER) {
|
|||
var seg = this.getSegment(dbgAddr.sel, dbgAddr.fProt);
|
||||
if (seg) {
|
||||
if (!fWrite) {
|
||||
addr = seg.checkRead(dbgAddr.off, cb || 1, true);
|
||||
addr = seg.checkRead(dbgAddr.off, nb || 1, true);
|
||||
} else {
|
||||
addr = seg.checkWrite(dbgAddr.off, cb || 1, true);
|
||||
addr = seg.checkWrite(dbgAddr.off, nb || 1, true);
|
||||
}
|
||||
dbgAddr.addr = addr;
|
||||
}
|
||||
|
|
@ -2990,7 +2990,7 @@ if (DEBUGGER) {
|
|||
Debugger.prototype.checkInstruction = function(addr, nState)
|
||||
{
|
||||
if (nState > 0) {
|
||||
if (this.checkBreakpoint(addr, this.aBreakExec)) {
|
||||
if (this.checkBreakpoint(addr, 1, this.aBreakExec)) {
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
|
|
@ -3027,18 +3027,19 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* checkMemoryRead(addr)
|
||||
* checkMemoryRead(addr, nb)
|
||||
*
|
||||
* This "check" function is called by a Memory block to inform us that a memory read occurred, giving us an
|
||||
* opportunity to track the read if we want, and look for a matching "read" breakpoint, if any.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} addr
|
||||
* @param {number} [nb] (# of bytes; default is 1)
|
||||
* @return {boolean} true if breakpoint hit, false if not
|
||||
*/
|
||||
Debugger.prototype.checkMemoryRead = function(addr)
|
||||
Debugger.prototype.checkMemoryRead = function(addr, nb)
|
||||
{
|
||||
if (this.checkBreakpoint(addr, this.aBreakRead)) {
|
||||
if (this.checkBreakpoint(addr, nb || 1, this.aBreakRead)) {
|
||||
this.stopCPU(true);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3046,18 +3047,19 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* checkMemoryWrite(addr)
|
||||
* checkMemoryWrite(addr, nb)
|
||||
*
|
||||
* This "check" function is called by a Memory block to inform us that a memory write occurred, giving us an
|
||||
* opportunity to track the write if we want, and look for a matching "write" breakpoint, if any.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} addr
|
||||
* @param {number} [nb] (# of bytes; default is 1)
|
||||
* @return {boolean} true if breakpoint hit, false if not
|
||||
*/
|
||||
Debugger.prototype.checkMemoryWrite = function(addr)
|
||||
Debugger.prototype.checkMemoryWrite = function(addr, nb)
|
||||
{
|
||||
if (this.checkBreakpoint(addr, this.aBreakWrite)) {
|
||||
if (this.checkBreakpoint(addr, nb || 1, this.aBreakWrite)) {
|
||||
this.stopCPU(true);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -3271,7 +3273,7 @@ if (DEBUGGER) {
|
|||
Debugger.prototype.clearTempBreakpoint = function(addr)
|
||||
{
|
||||
if (addr !== undefined) {
|
||||
this.checkBreakpoint(addr, this.aBreakExec, true);
|
||||
this.checkBreakpoint(addr, 1, this.aBreakExec, true);
|
||||
this.fProcStep = 0;
|
||||
} else {
|
||||
for (var i = 1; i < this.aBreakExec.length; i++) {
|
||||
|
|
@ -3309,15 +3311,16 @@ if (DEBUGGER) {
|
|||
};
|
||||
|
||||
/**
|
||||
* checkBreakpoint(addr, aBreak, fTemp)
|
||||
* checkBreakpoint(addr, nb, aBreak, fTemp)
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} addr
|
||||
* @param {number} nb (# of bytes)
|
||||
* @param {Array} aBreak
|
||||
* @param {boolean} [fTemp]
|
||||
* @return {boolean} true if breakpoint has been hit, false if not
|
||||
*/
|
||||
Debugger.prototype.checkBreakpoint = function(addr, aBreak, fTemp)
|
||||
Debugger.prototype.checkBreakpoint = function(addr, nb, aBreak, fTemp)
|
||||
{
|
||||
/*
|
||||
* Time to check for execution breakpoints; note that this should be done BEFORE updating frequency
|
||||
|
|
@ -3361,13 +3364,20 @@ if (DEBUGGER) {
|
|||
* If you want to create a real-mode breakpoint that will break regardless of mode,
|
||||
* use the physical address of the real-mode memory location instead.
|
||||
*/
|
||||
if (addr == this.mapBreakpoint(this.getAddr(dbgAddrBreak))) {
|
||||
if (dbgAddrBreak.fTempBreak) {
|
||||
this.findBreakpoint(aBreak, dbgAddrBreak, true);
|
||||
} else if (!fTemp) {
|
||||
this.println("breakpoint hit: " + this.hexAddr(dbgAddrBreak) + " (" + aBreak[0] + ")");
|
||||
var addrBreak = this.mapBreakpoint(this.getAddr(dbgAddrBreak));
|
||||
for (var n = 0; n < nb; n++) {
|
||||
if (addr == addrBreak) {
|
||||
if (dbgAddrBreak.fTempBreak) {
|
||||
this.findBreakpoint(aBreak, dbgAddrBreak, true);
|
||||
} else if (!fTemp) {
|
||||
this.println("breakpoint hit: " + this.hexAddr(dbgAddrBreak) + " (" + aBreak[0] + ")");
|
||||
}
|
||||
fBreak = true;
|
||||
break;
|
||||
}
|
||||
fBreak = true;
|
||||
addrBreak++;
|
||||
addr++;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -795,88 +795,102 @@ Memory.prototype = {
|
|||
/**
|
||||
* readByteChecked(off, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readByteChecked: function readByteChecked(off, addr) {
|
||||
if (DEBUGGER && this.dbg) this.dbg.checkMemoryRead(addr);
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryRead(addr)) {
|
||||
if (I386) this.cpu.checkMemoryException(addr, 1, false);
|
||||
}
|
||||
return this.readByteDirect(off, addr);
|
||||
},
|
||||
/**
|
||||
* readShortChecked(off, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readShortChecked: function readShortChecked(off, addr) {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryRead(addr) ||
|
||||
this.dbg.checkMemoryRead(addr + 1);
|
||||
if (!DEBUGGER || !this.dbg && !this.dbg.checkMemoryRead(addr, 2)) {
|
||||
if (I386) this.cpu.checkMemoryException(addr, 2, false);
|
||||
}
|
||||
return this.readShortDirect(off, addr);
|
||||
},
|
||||
/**
|
||||
* readLongChecked(off, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @return {number}
|
||||
*/
|
||||
readLongChecked: function readLongChecked(off, addr) {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryRead(addr) ||
|
||||
this.dbg.checkMemoryRead(addr + 1) ||
|
||||
this.dbg.checkMemoryRead(addr + 2) ||
|
||||
this.dbg.checkMemoryRead(addr + 3);
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryRead(addr, 4)) {
|
||||
if (I386) this.cpu.checkMemoryException(addr, 4, false);
|
||||
}
|
||||
return this.readLongDirect(off, addr);
|
||||
},
|
||||
/**
|
||||
* writeByteChecked(off, b, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} b
|
||||
*/
|
||||
writeByteChecked: function writeByteChecked(off, b, addr) {
|
||||
if (DEBUGGER && this.dbg) this.dbg.checkMemoryWrite(addr);
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryWrite(addr)) {
|
||||
if (I386) this.cpu.checkMemoryException(addr, 1, true);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(off, b, addr); else this.writeByteDirect(off, b, addr);
|
||||
},
|
||||
/**
|
||||
* writeShortChecked(off, w, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} addr
|
||||
* @param {number} w
|
||||
*/
|
||||
writeShortChecked: function writeShortChecked(off, w, addr) {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryWrite(addr) ||
|
||||
this.dbg.checkMemoryWrite(addr + 1);
|
||||
if (!DEBUGGER || !this.dbg && !this.dbg.checkMemoryWrite(addr, 2)) {
|
||||
if (I386) this.cpu.checkMemoryException(addr, 2, true);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(off, w, addr); else this.writeShortDirect(off, w, addr);
|
||||
},
|
||||
/**
|
||||
* writeLongChecked(off, l, addr)
|
||||
*
|
||||
* TODO: Considering adding an assert that "this.addr + off === addr", and consider using that fact to eliminate
|
||||
* the extra 'addr' parameter.
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {number} off
|
||||
* @param {number} l
|
||||
* @param {number} addr
|
||||
*/
|
||||
writeLongChecked: function writeLongChecked(off, l, addr) {
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryWrite(this.addr + off) ||
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 1) ||
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 2) ||
|
||||
this.dbg.checkMemoryWrite(this.addr + off + 3);
|
||||
if (!DEBUGGER || !this.dbg || !this.dbg.checkMemoryWrite(addr, 4)) {
|
||||
if (I386) this.cpu.checkMemoryException(addr, 4, true);
|
||||
}
|
||||
if (this.fReadOnly) this.writeNone(off, l, addr); else this.writeLongDirect(off, l, addr);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -99,6 +99,36 @@ var X86 = {
|
|||
ET: 0x00000010, // coprocessor type (80287 or 80387); always 1 on post-80386 CPUs
|
||||
PG: 0x80000000|0 // 0: paging disabled
|
||||
},
|
||||
DR7: { // Debug Control Register
|
||||
L0: 0x00000001,
|
||||
G0: 0x00000002,
|
||||
L1: 0x00000004,
|
||||
G1: 0x00000008,
|
||||
L2: 0x00000010,
|
||||
G2: 0x00000020,
|
||||
L3: 0x00000040,
|
||||
G3: 0x00000080,
|
||||
ENABLE: 0x000000FF,
|
||||
LE: 0x00000100,
|
||||
GE: 0x00000200,
|
||||
RW0: 0x00030000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN0: 0x000C0000, // 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
RW1: 0x00300000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN1: 0x00C00000, // 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
RW2: 0x03000000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN2: 0x0C000000, // 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
RW3: 0x30000000, // 00: exec-only 01: write-only 10: undefined 11: read/write-only
|
||||
LEN3: 0xC0000000|0// 00: one-byte, 01: two-byte, 10: undefined 11: four-byte
|
||||
},
|
||||
DR6: { // Debug Status Register
|
||||
B0: 0x00000001,
|
||||
B1: 0x00000002,
|
||||
B2: 0x00000004,
|
||||
B3: 0x00000008,
|
||||
BD: 0x00002000, // set if the next instruction will read or write one of the eight debug registers and ICE-386 is also using them
|
||||
BS: 0x00004000, // set if the debug handler is entered due to the TF (trap flag) bit set in the EFLAGS register
|
||||
BT: 0x00008000 // set before entering the DEBUG handler if a task switch has occurred and the T-bit of the new TSS is set
|
||||
},
|
||||
SEL: {
|
||||
RPL: 0x0003, // requested privilege level (0-3)
|
||||
LDT: 0x0004, // table indicator (0: GDT, 1: LDT)
|
||||
|
|
@ -280,7 +310,7 @@ var X86 = {
|
|||
*/
|
||||
EXCEPTION: {
|
||||
DIV_ERR: 0x00, // Divide Error Interrupt
|
||||
TRAP: 0x01, // Single Step (aka Trap) Interrupt
|
||||
DEBUG: 0x01, // Debug (aka Single Step Trap) Interrupt
|
||||
NMI: 0x02, // Non-Maskable Interrupt
|
||||
BREAKPOINT: 0x03, // Breakpoint Interrupt
|
||||
OVERFLOW: 0x04, // INTO Overflow Interrupt (FYI, return address does NOT point to offending instruction)
|
||||
|
|
|
|||
|
|
@ -1312,8 +1312,8 @@ X86CPU.prototype.resetRegs = function()
|
|||
this.regCR1 = 0; // reserved
|
||||
this.regCR2 = 0; // page fault linear address (PFLA)
|
||||
this.regCR3 = 0; // page directory base register (PDBR)
|
||||
this.regDRn = [0,0,0,0,null,null,0,0]; // Debug Registers DR0-DR7 (DR4-DR5 are undefined)
|
||||
this.regTRn = [null,null,null,null,null,null,0,0]; // Test Registers TR0-TR7 (TR0-TR5 are undefined)
|
||||
this.regDR = [0,0,0,0,null,null,0,0]; // Debug Registers DR0-DR7 (DR4-DR5 are undefined)
|
||||
this.regTR = [null,null,null,null,null,null,0,0]; // Test Registers TR0-TR7 (TR0-TR5 are undefined)
|
||||
this.segFS = new X86Seg(this, X86Seg.ID.DATA, "FS");
|
||||
this.segGS = new X86Seg(this, X86Seg.ID.DATA, "GS");
|
||||
this.disablePageBlocks();
|
||||
|
|
@ -1678,6 +1678,79 @@ X86CPU.prototype.checkIntReturn = function(addr)
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* addMemCheck(addr, fWrite)
|
||||
*
|
||||
* These functions provide Debug register functionality by leveraging the same Memory block-based breakpoint
|
||||
* support originally created for our built-in Debugger. Only minimal changes were required to the Memory
|
||||
* component, by adding additional checkMemoryException() call-outs to the "checked" Memory access functions.
|
||||
*
|
||||
* Note that those call-outs occur only AFTER our own Debugger (if present) has checked the address and has
|
||||
* passed on it, because we want our own Debugger's breakpoints to take precedence over any breakpoints that
|
||||
* the emulated machine may have enabled.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} addr
|
||||
* @param {boolean} fWrite is true for a memory write check, false for a memory read check
|
||||
*/
|
||||
X86CPU.prototype.addMemCheck = function(addr, fWrite)
|
||||
{
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock].addBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
};
|
||||
|
||||
/**
|
||||
* removeMemCheck(addr, fWrite)
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} addr
|
||||
* @param {boolean} fWrite is true for a memory write check, false for a memory read check
|
||||
*/
|
||||
X86CPU.prototype.removeMemCheck = function(addr, fWrite)
|
||||
{
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
this.aMemBlocks[iBlock].removeBreakpoint(addr & this.nBlockLimit, fWrite);
|
||||
};
|
||||
|
||||
/**
|
||||
* checkMemoryException(addr, nb, fWrite)
|
||||
*
|
||||
* This "check" function is called by a Memory block to inform us that a memory read or write is occurring,
|
||||
* giving us the opportunity look for a matching "read" or "write" breakpoint enabled in one of the DRn registers.
|
||||
*
|
||||
* TODO: This currently does not discriminate between data reads and execution reads. When we switch to a true
|
||||
* "prefetch" model, that would also be a good time to include a signal to this function that any "read" accesses
|
||||
* are actually "exec" accesses.
|
||||
*
|
||||
* @this {X86CPU}
|
||||
* @param {number} addr
|
||||
* @param {number} nb (# of bytes)
|
||||
* @param {boolean|null} [fWrite] (false if read, true if write, null if exec)
|
||||
*/
|
||||
X86CPU.prototype.checkMemoryException = function(addr, nb, fWrite)
|
||||
{
|
||||
if (this.regDR[7] & X86.DR7.ENABLE) {
|
||||
var regDR7 = this.regDR[7];
|
||||
var bitsEnabled = X86.DR7.L0 | X86.DR7.G0;
|
||||
var bitsRWMask = 0x00030000;
|
||||
var bitsRWRequired = (fWrite? 0x00010000 : (fWrite == false? 0x00030000 : 0));
|
||||
var bitsLENMask = 0x000C0000;
|
||||
var bitsLENRequired = (nb == 1? 0x00000000 : (nb == 2? 0x00040000 : 0x000C000));
|
||||
for (var i = 0; i < 4; i++) {
|
||||
if ((regDR7 & bitsEnabled) && (regDR7 & bitsRWMask) == bitsRWRequired) {
|
||||
if ((regDR7 & bitsLENMask) == bitsLENRequired && addr == this.regDR[i]) {
|
||||
this.regDR[6] |= (1 << i);
|
||||
X86.fnFault.call(this, X86.EXCEPTION.DEBUG);
|
||||
return;
|
||||
}
|
||||
}
|
||||
bitsEnabled <<= 2;
|
||||
bitsRWMask <<= 2; bitsRWRequired <<= 2;
|
||||
bitsLENMask <<= 2; bitsLENRequired <<= 2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setProtMode(fProt, fV86)
|
||||
*
|
||||
|
|
@ -1742,8 +1815,8 @@ X86CPU.prototype.saveProtMode = function()
|
|||
a.push(this.regCR1);
|
||||
a.push(this.regCR2);
|
||||
a.push(this.regCR3);
|
||||
a.push(this.regDRn);
|
||||
a.push(this.regTRn);
|
||||
a.push(this.regDR);
|
||||
a.push(this.regTR);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
|
@ -1773,8 +1846,8 @@ X86CPU.prototype.restoreProtMode = function(a)
|
|||
this.regCR1 = a[8];
|
||||
this.regCR2 = a[9];
|
||||
this.regCR3 = a[10];
|
||||
this.regDRn = a[11];
|
||||
this.regTRn = a[12];
|
||||
this.regDR = a[11];
|
||||
this.regTR = a[12];
|
||||
}
|
||||
this.setProtMode();
|
||||
}
|
||||
|
|
@ -3832,7 +3905,7 @@ X86CPU.prototype.checkINTR = function()
|
|||
case 1:
|
||||
if ((this.intFlags & X86.INTFLAG.TRAP)) {
|
||||
this.intFlags &= ~X86.INTFLAG.TRAP;
|
||||
X86.fnINT.call(this, X86.EXCEPTION.TRAP, null, 11);
|
||||
X86.fnINT.call(this, X86.EXCEPTION.DEBUG, null, 11);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -3827,6 +3827,10 @@ X86.fnFaultMessage = function(nFault, nError, fHalt)
|
|||
nFault == X86.EXCEPTION.GP_FAULT && bOpcode == X86.OPCODE.INTN) {
|
||||
fHalt = false;
|
||||
}
|
||||
} else {
|
||||
if (nFault == X86.EXCEPTION.NP_FAULT && bOpcode == 0x8E) {
|
||||
fHalt = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ X86.opMOVrd = function MOVrd()
|
|||
return;
|
||||
}
|
||||
|
||||
this.setReg(bModRM & 0x7, this.regDRn[iSrc]);
|
||||
this.setReg(bModRM & 0x7, this.regDR[iSrc]);
|
||||
|
||||
this.nStepCycles -= 22;
|
||||
|
||||
|
|
@ -443,7 +443,6 @@ X86.opMOVcr = function MOVcr()
|
|||
}
|
||||
|
||||
var bModRM = this.getIPByte();
|
||||
|
||||
var reg = this.getReg(bModRM & 0x7);
|
||||
|
||||
switch((bModRM & 0x38) >> 3) {
|
||||
|
|
@ -499,14 +498,36 @@ X86.opMOVdr = function MOVdr()
|
|||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
var regDR = this.getReg(bModRM & 0x7);
|
||||
|
||||
/*
|
||||
* TODO: Do something with the Debug registers....
|
||||
*/
|
||||
this.regDRn[iDst] = this.getReg(bModRM & 0x7);
|
||||
|
||||
if (iDst == 7) {
|
||||
var regDR7 = this.regDR[7];
|
||||
if ((regDR ^ regDR7) & X86.DR7.ENABLE) {
|
||||
/*
|
||||
* We need to check changes to the Debug Control Register (DR7); specifically, if any of
|
||||
* DR0-DR3 are transitioning from disabled to enabled, or vice versa, then we need to call
|
||||
* addMemCheck(), or removeMemCheck(), as appropriate.
|
||||
*/
|
||||
var bitsEnabled = X86.DR7.L0 | X86.DR7.G0;
|
||||
var bitsRWMask = 0x00030000;
|
||||
for (var i = 0; i < 4; i++) {
|
||||
var fEnabled = (regDR & bitsEnabled);
|
||||
if (!fEnabled != !(regDR7 & bitsEnabled)) {
|
||||
var bitsRW = (regDR & bitsRWMask) >> (i << 1);
|
||||
var fWrite = !!(bitsRW & 0x00010000);
|
||||
if (fEnabled) {
|
||||
this.addMemCheck(this.regDR[i], fWrite);
|
||||
} else {
|
||||
this.removeMemCheck(this.regDR[i], fWrite);
|
||||
}
|
||||
}
|
||||
bitsEnabled <<= 2;
|
||||
bitsRWMask <<= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.regDR[iDst] = regDR;
|
||||
this.nStepCycles -= (iDst < 4? 22 : 14);
|
||||
|
||||
/*
|
||||
* TODO: Implement BACKTRACK for this instruction....
|
||||
*/
|
||||
|
|
@ -542,9 +563,7 @@ X86.opMOVrt = function MOVrt()
|
|||
X86.opUndefined.call(this);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setReg(bModRM & 0x7, this.regTRn[iSrc]);
|
||||
|
||||
this.setReg(bModRM & 0x7, this.regTR[iSrc]);
|
||||
this.nStepCycles -= 12;
|
||||
|
||||
/*
|
||||
|
|
@ -586,7 +605,7 @@ X86.opMOVtr = function MOVtr()
|
|||
/*
|
||||
* TODO: Do something with the Test registers....
|
||||
*/
|
||||
this.regTRn[iDst] = this.getReg(bModRM & 0x7);
|
||||
this.regTR[iDst] = this.getReg(bModRM & 0x7);
|
||||
|
||||
this.nStepCycles -= 12;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue