v1.18.5: Working on running Windows 3.00 in real/standard/enhanced modes

This commit is contained in:
Jeff Parsons 2015-07-26 17:02:48 -07:00
commit e269cd49c3
32 changed files with 11054 additions and 4121 deletions

View file

@ -3163,7 +3163,9 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
* TODO: Support EOI commands with automatic rotation (eg, ChipSet.PIC_LO.OCW2_EOI_ROT and ChipSet.PIC_LO.OCW2_EOI_ROTSPEC)
*/
if (bOCW2 & ChipSet.PIC_LO.OCW2_SET_ROTAUTO) {
this.notice("PIC" + iPIC + '(' + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut));
if (this.messageEnabled(/*Messages.PIC | */Messages.WARN)) {
this.printMessage("PIC" + iPIC + '(' + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command " + str.toHexByte(bOut), true, true);
}
}
}
else if (bOCW2 == ChipSet.PIC_LO.OCW2_SET_PRI) {
@ -3176,7 +3178,9 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
/*
* TODO: Remaining commands to support: ChipSet.PIC_LO.OCW2_SET_ROTAUTO and ChipSet.PIC_LO.OCW2_CLR_ROTAUTO
*/
this.notice("PIC" + iPIC + '(' + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut));
if (this.messageEnabled(/*Messages.PIC | */Messages.WARN)) {
this.printMessage("PIC" + iPIC + '(' + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command " + str.toHexByte(bOut), true, true);
}
}
} else {
/*
@ -3186,7 +3190,9 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
* that's unfortunate, because I don't support them yet.
*/
if (bOut & (ChipSet.PIC_LO.OCW3_POLL_CMD | ChipSet.PIC_LO.OCW3_SMM_CMD)) {
this.notice("PIC" + iPIC + '(' + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut));
if (this.messageEnabled(/*Messages.PIC | */Messages.WARN)) {
this.printMessage("PIC" + iPIC + '(' + str.toHexByte(pic.port) + "): unsupported OCW3 command " + str.toHexByte(bOut), true, true);
}
}
pic.bOCW3 = bOut;
}

View file

@ -68,6 +68,7 @@ if (DEBUGGER) {
* @property {number|null|undefined} off (offset, if any)
* @property {number|null|undefined} sel (selector, if any)
* @property {number|null|undefined} addr (linear address, if any)
* @property {boolean|undefined} fProt (true if protected-mode address)
* @property {boolean|undefined} fData32 (true if 32-bit operand size in effect)
* @property {boolean|undefined} fAddr32 (true if 32-bit address size in effect)
* @property {number|undefined} cOverrides (non-zero if any overrides were processed with this address)
@ -1302,6 +1303,11 @@ if (DEBUGGER) {
this.cchAddr = bus.getWidth() >> 2;
this.maskAddr = bus.nBusLimit;
/*
* Allocate a special segment "register" for our own use, whenever a requested selector is not currently loaded
*/
this.segDebugger = new X86Seg(this.cpu, X86Seg.ID.DEBUG, "DBG");
this.aaOpDescs = Debugger.aaOpDescs;
if (this.cpu.model >= X86.MODEL_80186) {
this.aaOpDescs = Debugger.aaOpDescs.slice();
@ -1434,7 +1440,18 @@ if (DEBUGGER) {
};
/**
* getSegment(sel)
* getProtMode()
*
* @this {Debugger}
* @return {boolean}
*/
Debugger.prototype.getProtMode = function()
{
return this.cpu && !!(this.cpu.regCR0 & X86.CR0.MSW.PE) && !(this.cpu.regPS & X86.PS.VM);
};
/**
* getSegment(sel, fProt)
*
* If the selector matches that of any of the CPU segment registers, then return the CPU's segment
* register, instead of creating our own dummy segment register. This makes it possible for us to
@ -1442,29 +1459,39 @@ if (DEBUGGER) {
* switched the processor from real to protected mode. Actually loading the selector from the GDT/LDT
* should be done only as a last resort.
*
* @this {Debugger}
* @param {number|null|undefined} sel
* @param {boolean} [fProt]
* @return {X86Seg|null} seg
*/
Debugger.prototype.getSegment = function(sel)
Debugger.prototype.getSegment = function(sel, fProt)
{
if (sel === this.cpu.getCS()) return this.cpu.segCS;
if (sel === this.cpu.getDS()) return this.cpu.segDS;
if (sel === this.cpu.getES()) return this.cpu.segES;
if (sel === this.cpu.getSS()) return this.cpu.segSS;
if (I386 && this.cpu.model >= X86.MODEL_80386) {
if (sel === this.cpu.getFS()) return this.cpu.segFS;
if (sel === this.cpu.getGS()) return this.cpu.segGS;
var fProtMode = this.getProtMode();
if (fProt === undefined) {
fProt = fProtMode;
}
if (this.nSuppressBreaks) return null;
var seg = new X86Seg(this.cpu, X86Seg.ID.DEBUG, "DBG");
if (fProt == fProtMode) {
if (sel === this.cpu.getCS()) return this.cpu.segCS;
if (sel === this.cpu.getDS()) return this.cpu.segDS;
if (sel === this.cpu.getES()) return this.cpu.segES;
if (sel === this.cpu.getSS()) return this.cpu.segSS;
if (I386 && this.cpu.model >= X86.MODEL_80386) {
if (sel === this.cpu.getFS()) return this.cpu.segFS;
if (sel === this.cpu.getGS()) return this.cpu.segGS;
}
}
if (this.nSuppressBreaks || !this.segDebugger) return null;
/*
* Note the load() function's fSuppress parameter, which the Debugger should ALWAYS set to true
* to avoid triggering a fault.
*
* TODO: Confirm that it's OK for getSegment() to drop any error from seg.load() on the floor....
* to avoid triggering a fault. Unfortunately, when paging is enabled, there's still the risk of
* triggering a page fault that will alter the machine's state, so be careful.
*/
seg.load(sel, true);
return seg;
if (!fProt) {
this.segDebugger.loadReal(sel, true);
} else {
this.segDebugger.loadProt(sel, true);
}
return this.segDebugger;
};
/**
@ -1487,7 +1514,7 @@ if (DEBUGGER) {
var addr = dbgAddr.addr;
if (addr == null) {
addr = X86.ADDR_INVALID;
var seg = this.getSegment(dbgAddr.sel);
var seg = this.getSegment(dbgAddr.sel, dbgAddr.fProt);
if (seg) {
if (!fWrite) {
addr = seg.checkRead(dbgAddr.off, cb || 1, true);
@ -1612,21 +1639,23 @@ if (DEBUGGER) {
};
/**
* newAddr(off, sel, addr, fData32, fAddr32)
* newAddr(off, sel, addr, fProt, fData32, fAddr32)
*
* @this {Debugger}
* @param {number|null|undefined} [off] (default is zero)
* @param {number|null|undefined} [sel] (default is undefined)
* @param {number|null|undefined} [addr] (default is undefined)
* @param {boolean} [fProt] (default is the current CPU mode)
* @param {boolean} [fData32] (default is false)
* @param {boolean} [fAddr32] (default is false)
* @return {{DbgAddr}}
*/
Debugger.prototype.newAddr = function(off, sel, addr, fData32, fAddr32)
Debugger.prototype.newAddr = function(off, sel, addr, fProt, fData32, fAddr32)
{
if (fProt === undefined) fProt = this.getProtMode();
if (fData32 === undefined) fData32 = (this.cpu && this.cpu.segCS.dataSize == 4);
if (fAddr32 === undefined) fAddr32 = (this.cpu && this.cpu.segCS.addrSize == 4);
return {off: off || 0, sel: sel, addr: addr, fTempBreak: false, fData32: fData32 || false, fAddr32: fAddr32 || false};
return {off: off || 0, sel: sel, addr: addr, fProt: fProt || false, fTempBreak: false, fData32: fData32 || false, fAddr32: fAddr32 || false};
};
/**
@ -1662,8 +1691,8 @@ if (DEBUGGER) {
Debugger.prototype.checkLimit = function(dbgAddr)
{
if (dbgAddr.sel != null) {
var seg = this.getSegment(dbgAddr.sel);
if (!seg || (dbgAddr.off >>> 0) >= seg.offMax) {
var seg = this.getSegment(dbgAddr.sel, dbgAddr.fProt);
if (seg && (dbgAddr.off >>> 0) >= seg.offMax) {
/*
* TODO: This automatic wrap-to-zero is OK for normal segments, but for expand-down segments, not so much.
*/
@ -1927,7 +1956,7 @@ if (DEBUGGER) {
return;
}
var seg = this.getSegment(sel);
var seg = this.getSegment(sel, true);
this.println("dumpDesc(" + str.toHexWord(seg? seg.sel : sel) + "): %" + str.toHex(seg? seg.addrDesc : null, this.cchAddr));
if (!seg) return;
@ -2026,7 +2055,7 @@ if (DEBUGGER) {
* We must create a new dbgAddr from the address in aHistory, because dbgAddr was
* a reference, not a copy, and we don't want getInstruction() modifying the original.
*/
dbgAddr = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, fData32 == null? dbgAddr.fData32 : fData32, fAddr32 == null? dbgAddr.fAddr32 : fAddr32);
dbgAddr = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, dbgAddr.fProt, fData32 == null? dbgAddr.fData32 : fData32, fAddr32 == null? dbgAddr.fAddr32 : fAddr32);
this.println(this.getInstruction(dbgAddr, "history", n--));
/*
* If there were OPERAND or ADDRESS overrides on the previous instruction, getInstruction()
@ -2074,7 +2103,7 @@ if (DEBUGGER) {
this.println("invalid task selector: " + s);
return;
}
seg = this.getSegment(sel);
seg = this.getSegment(sel, true);
}
this.println("dumpTSS(" + str.toHexWord(seg? seg.sel : sel) + "): %" + str.toHex(seg? seg.base : null, this.cchAddr));
@ -2414,11 +2443,10 @@ if (DEBUGGER) {
*/
Debugger.prototype.messageInt = function(nInt, addr)
{
var AH;
var fMessage = false;
var AH = this.cpu.regEAX >> 8;
var fMessage = this.messageEnabled(Messages.CPU) && nInt != 0x28 && nInt != 0x2A;
var nCategory = Debugger.INT_MESSAGES[nInt];
if (nCategory) {
AH = this.cpu.regEAX >> 8;
if (this.messageEnabled(nCategory)) {
fMessage = true;
} else {
@ -2966,6 +2994,7 @@ if (DEBUGGER) {
dbgAddr.off = this.cpu.getIP();
dbgAddr.sel = this.cpu.getCS();
dbgAddr.addr = addr;
dbgAddr.fProt = this.getProtMode();
dbgAddr.fData32 = (this.cpu && this.cpu.segCS.dataSize == 4);
dbgAddr.fAddr32 = (this.cpu && this.cpu.segCS.addrSize == 4);
if (++this.iOpcodeHistory == this.aOpcodeHistory.length) this.iOpcodeHistory = 0;
@ -3334,7 +3363,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.getInstruction = function(dbgAddr, sComment, nSequence)
{
var dbgAddrIns = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr);
var dbgAddrIns = this.newAddr(dbgAddr.off, dbgAddr.sel, dbgAddr.addr, dbgAddr.fProt);
var bOpcode = this.getByte(dbgAddr, 1);
@ -3550,7 +3579,7 @@ if (DEBUGGER) {
sOperand = str.toHex(this.getShort(dbgAddr, 2), 4);
break;
case Debugger.TYPE_FARP:
sOperand = this.hexAddr(this.newAddr(this.getWord(dbgAddr, true), this.getShort(dbgAddr, 2), null, dbgAddr.fData32, dbgAddr.fAddr32));
sOperand = this.hexAddr(this.newAddr(this.getWord(dbgAddr, true), this.getShort(dbgAddr, 2), null, dbgAddr.fProt, dbgAddr.fData32, dbgAddr.fAddr32));
break;
default:
sOperand = "imm(" + str.toHexWord(type) + ")";
@ -3886,9 +3915,7 @@ if (DEBUGGER) {
Debugger.prototype.getRegDump = function(fProt)
{
var s;
if (fProt === undefined) {
fProt = !!(this.cpu.regCR0 & X86.CR0.MSW.PE);
}
if (fProt === undefined) fProt = this.getProtMode();
s = this.getRegString(Debugger.REG_AX) +
this.getRegString(Debugger.REG_BX) +
this.getRegString(Debugger.REG_CX) +
@ -4538,6 +4565,14 @@ if (DEBUGGER) {
dbgAddr = this.parseAddr(sAddr, Debugger.ADDR_CODE, true);
if (dbgAddr.off == null) return;
}
/*
* We want our breakpoints to be "mode-less"; ie, independent of the processor mode at the
* time they're set. Therefore, it's critical that we erase the fProt setting that parseAddr(),
* via newAddr(), initialized dbgAddr with.
*/
dbgAddr.fProt = undefined;
sAddr = (dbgAddr.off == null? sAddr : str.toHexWord(dbgAddr.off));
if (sParm == "c") {
if (dbgAddr.off == null) {
@ -4630,10 +4665,6 @@ if (DEBUGGER) {
if (sDumpers.length) this.println("dump extensions:\n\t" + sDumpers);
return;
}
if (sAddr == "state") {
this.println(this.cmp.powerOff(true));
return;
}
if (sAddr == "symbols") {
this.dumpSymbols();
return;
@ -4643,6 +4674,15 @@ if (DEBUGGER) {
if (sLen.charAt(0) == "l") sLen = sLen.substr(1);
cLines = +sLen;
}
if (sCmd == "d") {
sCmd = this.sCmdDumpPrev || "db";
} else {
this.sCmdDumpPrev = sCmd;
}
if (sAddr == "state") {
this.println(this.cmp.powerOff(true));
return;
}
if (sCmd == "dh") {
this.dumpHistory(sAddr, cLines);
return;

View file

@ -786,7 +786,7 @@ X86Seg.prototype.loadDesc8 = function(addrDesc, sel, fSuppress)
this.type = type;
this.ext = ext;
this.addrDesc = addrDesc;
this.updateMode(true);
this.updateMode(true, true, false);
if (fGate === false && this.fStackSwitch) {
/*
@ -1194,21 +1194,21 @@ X86Seg.prototype.updateMode = function(fLoad, fProt, fV86)
this.addrSize = this.dataSize;
this.addrMask = this.dataMask;
}
} else {
/*
* One important feature of real-mode (as compared to V86-mode) are that other segment attributes
* (eg, limit, operand size, address size, etc) are NOT updated, enabling features like "big real-mode"
* (aka "unreal mode"), which is used by system software like HIMEM.SYS to access extended memory from
* real-mode.
*/
this.load = this.loadReal;
this.loadIDT = this.loadIDTReal;
this.checkRead = this.checkReadReal;
this.checkWrite = this.checkWriteReal;
this.cpl = this.dpl = 0;
this.addrDesc = X86.ADDR_INVALID;
this.fStackSwitch = false;
return;
}
/*
* One important feature of real-mode (as compared to V86-mode) are that other segment attributes
* (eg, limit, operand size, address size, etc) are NOT updated, enabling features like "big real-mode"
* (aka "unreal mode"), which is used by system software like HIMEM.SYS to access extended memory from
* real-mode.
*/
this.load = this.loadReal;
this.loadIDT = this.loadIDTReal;
this.checkRead = this.checkReadReal;
this.checkWrite = this.checkWriteReal;
this.cpl = this.dpl = 0;
this.addrDesc = X86.ADDR_INVALID;
this.fStackSwitch = false;
};
/**