Fixed high 8-bit register MOVs, restricted ACCESSED bit updates to SEGMENT descriptors, and prevented the Debugger from looping endlessly on bad instructions
This commit is contained in:
parent
8971e22717
commit
2d7cbe2864
4 changed files with 33 additions and 28 deletions
|
|
@ -11,7 +11,7 @@
|
||||||
<video ref="/devices/pc/video/ibm/vga/ibm-vga-lockfs.xml"/>
|
<video ref="/devices/pc/video/ibm/vga/ibm-vga-lockfs.xml"/>
|
||||||
<keyboard id="keyboard"/>
|
<keyboard id="keyboard"/>
|
||||||
<fdc ref="/disks/pc/library.xml" automount='{B: {name: "Win95 Build 499 (Disk 1)", path: "/disks/pc/windows/win95/build499/WIN95-DISK01.json"}}'/>
|
<fdc ref="/disks/pc/library.xml" automount='{B: {name: "Win95 Build 499 (Disk 1)", path: "/disks/pc/windows/win95/build499/WIN95-DISK01.json"}}'/>
|
||||||
<debugger id="debugger" messages="fault|tss|int" commands='m dos off;bp 1ED4:16B4 "let fn=ah;dos;if fn!=3f||cx!=24"'/>
|
<debugger id="debugger" messages="fault|tss|int" commands='m dos off'/>
|
||||||
<panel ref="/devices/pc/panel/wide386.xml"/>
|
<panel ref="/devices/pc/panel/wide386.xml"/>
|
||||||
<hdc id="hdcAT" type="at" drives='[{name:"68Mb Hard Disk",type:4,path:"http://static.pcjs.org/devices/pc/machine/compaq/deskpro386/vga/4096kb/WDEB386-68Mb.json"}]'/>
|
<hdc id="hdcAT" type="at" drives='[{name:"68Mb Hard Disk",type:4,path:"http://static.pcjs.org/devices/pc/machine/compaq/deskpro386/vga/4096kb/WDEB386-68Mb.json"}]'/>
|
||||||
<chipset id="chipset" model="deskpro386" floppies="[1200,1200]" monitor="vga"/>
|
<chipset id="chipset" model="deskpro386" floppies="[1200,1200]" monitor="vga"/>
|
||||||
|
|
|
||||||
|
|
@ -1538,13 +1538,15 @@ if (DEBUGGER) {
|
||||||
*/
|
*/
|
||||||
if (this.nSuppressBreaks && fProt || !this.segDebugger) return null;
|
if (this.nSuppressBreaks && fProt || !this.segDebugger) return null;
|
||||||
}
|
}
|
||||||
|
var seg = this.segDebugger;
|
||||||
if (!fProt) {
|
if (!fProt) {
|
||||||
this.segDebugger.loadReal(sel);
|
seg.loadReal(sel);
|
||||||
|
seg.limit = 0xffff; // although an ACTUAL real-mode segment load would not modify the limit,
|
||||||
|
seg.offMax = 0x10000; // proper segDebugger operation requires that we update the limit ourselves
|
||||||
} else {
|
} else {
|
||||||
this.segDebugger.loadProt(sel);
|
seg.loadProt(sel);
|
||||||
}
|
}
|
||||||
return this.segDebugger;
|
return seg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2929,7 +2931,7 @@ if (DEBUGGER) {
|
||||||
if (!fRegs || this.nStep == 1)
|
if (!fRegs || this.nStep == 1)
|
||||||
this.doUnassemble();
|
this.doUnassemble();
|
||||||
else {
|
else {
|
||||||
this.doRegisters(null);
|
this.doRegisters();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -3841,6 +3843,7 @@ if (DEBUGGER) {
|
||||||
if (dbgAddrIns.addr != X86.ADDR_INVALID && dbgAddr.addr != X86.ADDR_INVALID) {
|
if (dbgAddrIns.addr != X86.ADDR_INVALID && dbgAddr.addr != X86.ADDR_INVALID) {
|
||||||
do {
|
do {
|
||||||
sBytes += str.toHex(this.getByte(dbgAddrIns, 1), 2);
|
sBytes += str.toHex(this.getByte(dbgAddrIns, 1), 2);
|
||||||
|
if (dbgAddrIns.addr == null) break;
|
||||||
} while (dbgAddrIns.addr != dbgAddr.addr);
|
} while (dbgAddrIns.addr != dbgAddr.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3079,7 +3079,7 @@ X86.opMOVBLb = function MOVBLb()
|
||||||
*/
|
*/
|
||||||
X86.opMOVAHb = function MOVAHb()
|
X86.opMOVAHb = function MOVAHb()
|
||||||
{
|
{
|
||||||
this.regEAX = (this.regEAX & 0xff) | (this.getIPByte() << 8);
|
this.regEAX = (this.regEAX & ~0xff00) | (this.getIPByte() << 8);
|
||||||
if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiMem0;
|
if (BACKTRACK) this.backTrack.btiAH = this.backTrack.btiMem0;
|
||||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||||
};
|
};
|
||||||
|
|
@ -3091,7 +3091,7 @@ X86.opMOVAHb = function MOVAHb()
|
||||||
*/
|
*/
|
||||||
X86.opMOVCHb = function MOVCHb()
|
X86.opMOVCHb = function MOVCHb()
|
||||||
{
|
{
|
||||||
this.regECX = (this.regECX & 0xff) | (this.getIPByte() << 8);
|
this.regECX = (this.regECX & ~0xff00) | (this.getIPByte() << 8);
|
||||||
if (BACKTRACK) this.backTrack.btiCH = this.backTrack.btiMem0;
|
if (BACKTRACK) this.backTrack.btiCH = this.backTrack.btiMem0;
|
||||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||||
};
|
};
|
||||||
|
|
@ -3103,7 +3103,7 @@ X86.opMOVCHb = function MOVCHb()
|
||||||
*/
|
*/
|
||||||
X86.opMOVDHb = function MOVDHb()
|
X86.opMOVDHb = function MOVDHb()
|
||||||
{
|
{
|
||||||
this.regEDX = (this.regEDX & 0xff) | (this.getIPByte() << 8);
|
this.regEDX = (this.regEDX & ~0xff00) | (this.getIPByte() << 8);
|
||||||
if (BACKTRACK) this.backTrack.btiDH = this.backTrack.btiMem0;
|
if (BACKTRACK) this.backTrack.btiDH = this.backTrack.btiMem0;
|
||||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||||
};
|
};
|
||||||
|
|
@ -3115,7 +3115,7 @@ X86.opMOVDHb = function MOVDHb()
|
||||||
*/
|
*/
|
||||||
X86.opMOVBHb = function MOVBHb()
|
X86.opMOVBHb = function MOVBHb()
|
||||||
{
|
{
|
||||||
this.regEBX = (this.regEBX & 0xff) | (this.getIPByte() << 8);
|
this.regEBX = (this.regEBX & ~0xff00) | (this.getIPByte() << 8);
|
||||||
if (BACKTRACK) this.backTrack.btiBH = this.backTrack.btiMem0;
|
if (BACKTRACK) this.backTrack.btiBH = this.backTrack.btiMem0;
|
||||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1194,6 +1194,26 @@ X86Seg.prototype.updateMode = function(fLoad, fProt, fV86)
|
||||||
if (this.checkWrite == this.checkWriteProt) this.checkWrite = this.checkWriteProtDown;
|
if (this.checkWrite == this.checkWriteProt) this.checkWrite = this.checkWriteProtDown;
|
||||||
this.fExpDown = true;
|
this.fExpDown = true;
|
||||||
}
|
}
|
||||||
|
if (fLoad && this.id < X86Seg.ID.VER) {
|
||||||
|
/*
|
||||||
|
* We must update the descriptor's ACCESSED bit whenever the segment is "accessed" (ie,
|
||||||
|
* loaded); unlike the ACCESSED and DIRTY bits in PTEs, a descriptor ACCESSED bit is only
|
||||||
|
* updated on loads, not on every memory access.
|
||||||
|
*
|
||||||
|
* We compute address of the descriptor byte containing the ACCESSED bit (offset 0x5);
|
||||||
|
* note that it's perfectly normal for addrDesc to occasionally be invalid (eg, when the CPU
|
||||||
|
* is creating protected-mode-only segment registers like LDT and TSS, or when the CPU has
|
||||||
|
* transitioned from real-mode to protected-mode and new selector(s) have not been loaded yet).
|
||||||
|
*
|
||||||
|
* TODO: Note I do NOT update the ACCESSED bit for null GDT selectors, because I assume the
|
||||||
|
* hardware does not update it either. In fact, I've seen code that uses the null GDT descriptor
|
||||||
|
* for other purposes, on the assumption that that descriptor is completely unused.
|
||||||
|
*/
|
||||||
|
if ((this.sel & ~X86.SEL.RPL) && this.addrDesc !== X86.ADDR_INVALID) {
|
||||||
|
var addrType = this.addrDesc + X86.DESC.ACC.TYPE.OFFSET;
|
||||||
|
this.cpu.setByte(addrType, this.cpu.getByte(addrType) | (X86.DESC.ACC.TYPE.ACCESSED >> 8));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* TODO: For non-SEG descriptors, are there other checks or functions we should establish?
|
* TODO: For non-SEG descriptors, are there other checks or functions we should establish?
|
||||||
|
|
@ -1204,24 +1224,6 @@ X86Seg.prototype.updateMode = function(fLoad, fProt, fV86)
|
||||||
* we're updating segment registers as part of a mode change.
|
* we're updating segment registers as part of a mode change.
|
||||||
*/
|
*/
|
||||||
if (fLoad) {
|
if (fLoad) {
|
||||||
/*
|
|
||||||
* We must update the descriptor's ACCESSED bit whenever the segment is "accessed" (ie,
|
|
||||||
* loaded); unlike the ACCESSED and DIRTY bits in PTEs, a descriptor ACCESSED bit is only
|
|
||||||
* updated on loads, not on every memory access.
|
|
||||||
*
|
|
||||||
* We compute address of the descriptor byte containing the ACCESSED bit (offset 0x5);
|
|
||||||
* note that it's perfectly normal for addrDesc to occasionally be invalid (eg, when the CPU
|
|
||||||
* is creating protected-mode-only segment registers like LDT and TSS, or when the CPU has
|
|
||||||
* transitioned from real-mode to protected-mode and new selector(s) have not been loaded yet).
|
|
||||||
*
|
|
||||||
* TODO: Note I do NOT update the ACCESSED bit for null GDT selectors, because I assume the
|
|
||||||
* hardware does not update it either. In fact, I've seen code that uses the null GDT descriptor
|
|
||||||
* for other purposes, on the assumption that that descriptor is completely unused.
|
|
||||||
*/
|
|
||||||
if ((this.sel & ~X86.SEL.RPL) && this.addrDesc !== X86.ADDR_INVALID) {
|
|
||||||
var addrType = this.addrDesc + X86.DESC.ACC.TYPE.OFFSET;
|
|
||||||
this.cpu.setByte(addrType, this.cpu.getByte(addrType) | (X86.DESC.ACC.TYPE.ACCESSED >> 8));
|
|
||||||
}
|
|
||||||
this.cpl = this.sel & X86.SEL.RPL;
|
this.cpl = this.sel & X86.SEL.RPL;
|
||||||
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
|
this.dpl = (this.acc & X86.DESC.ACC.DPL.MASK) >> X86.DESC.ACC.DPL.SHIFT;
|
||||||
if (this.cpu.model < X86.MODEL_80386 || !(this.ext & X86.DESC.EXT.BIG)) {
|
if (this.cpu.model < X86.MODEL_80386 || !(this.ext & X86.DESC.EXT.BIG)) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue