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"/>
|
||||
<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"}}'/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
|
|
|
|||
|
|
@ -1538,13 +1538,15 @@ if (DEBUGGER) {
|
|||
*/
|
||||
if (this.nSuppressBreaks && fProt || !this.segDebugger) return null;
|
||||
}
|
||||
|
||||
var seg = this.segDebugger;
|
||||
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 {
|
||||
this.segDebugger.loadProt(sel);
|
||||
seg.loadProt(sel);
|
||||
}
|
||||
return this.segDebugger;
|
||||
return seg;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -2929,7 +2931,7 @@ if (DEBUGGER) {
|
|||
if (!fRegs || this.nStep == 1)
|
||||
this.doUnassemble();
|
||||
else {
|
||||
this.doRegisters(null);
|
||||
this.doRegisters();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -3841,6 +3843,7 @@ if (DEBUGGER) {
|
|||
if (dbgAddrIns.addr != X86.ADDR_INVALID && dbgAddr.addr != X86.ADDR_INVALID) {
|
||||
do {
|
||||
sBytes += str.toHex(this.getByte(dbgAddrIns, 1), 2);
|
||||
if (dbgAddrIns.addr == null) break;
|
||||
} while (dbgAddrIns.addr != dbgAddr.addr);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3079,7 +3079,7 @@ X86.opMOVBLb = function MOVBLb()
|
|||
*/
|
||||
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;
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||
};
|
||||
|
|
@ -3091,7 +3091,7 @@ X86.opMOVAHb = function MOVAHb()
|
|||
*/
|
||||
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;
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||
};
|
||||
|
|
@ -3103,7 +3103,7 @@ X86.opMOVCHb = function MOVCHb()
|
|||
*/
|
||||
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;
|
||||
this.nStepCycles -= this.cycleCounts.nOpCyclesLAHF;
|
||||
};
|
||||
|
|
@ -3115,7 +3115,7 @@ X86.opMOVDHb = function MOVDHb()
|
|||
*/
|
||||
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;
|
||||
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;
|
||||
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?
|
||||
|
|
@ -1204,24 +1224,6 @@ X86Seg.prototype.updateMode = function(fLoad, fProt, fV86)
|
|||
* we're updating segment registers as part of a mode change.
|
||||
*/
|
||||
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.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)) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue