Fixed 5170 memory test and debugger addressing issues

This commit is contained in:
Jeff Parsons 2014-10-02 01:49:03 -07:00 committed by jeffpar
commit 32bf809645
8 changed files with 937 additions and 857 deletions

View file

@ -483,7 +483,7 @@ ChipSet.PPI_A = {}; // this.bPPIA
ChipSet.PPI_A.PORT = 0x60; // INPUT: keyboard scan code (PPI_B_CLEAR_KBD must be clear)
ChipSet.PPI_B = {}; // this.bPPIB
ChipSet.PPI_B.PORT = 0x61; // OUTPUT (although it has to be treated as INPUT, too: the keyboard interrupt handler reads it, OR's PPI_B_CLEAR_KBD, writes it, and then rewrites the original read value)
ChipSet.PPI_B.PORT = 0x61; // OUTPUT (although it has to be treated as INPUT, too: the keyboard interrupt handler reads it, OR's PPI_B.CLEAR_KBD, writes it, and then rewrites the original read value)
ChipSet.PPI_B.CLK_TIMER2 = 0x01; // ALL: set to enable clock to TIMER2
ChipSet.PPI_B.SPK_TIMER2 = 0x02; // ALL: set to connect output of TIMER2 to speaker (MODEL_5150: clear for cassette)
ChipSet.PPI_B.ENABLE_SW2 = 0x04; // MODEL_5150: set to enable SW2[1-4] through PPI_C.PORT, clear to enable SW2[5]; MODEL_5160: unused (there is no SW2 switch block on the MODEL_5160 motherboard)
@ -513,6 +513,7 @@ ChipSet.PPI_CTRL.A_MODE = 0x60;
/*
* On the MODEL_5150, the following PPI_SW bits are exposed through PPI_A.
*
* On the MODEL_5160, either the low or high 4 bits are exposed through PPI_C_SW, if PPI_B_ENABLE_SW_HI is clear or set.
*/
ChipSet.PPI_SW = {};
@ -542,20 +543,20 @@ ChipSet.PPI_SW.FDRIVE.SHIFT = 6;
/*
* 8042 Keyboard Controller I/O ports (MODEL_5170)
*
* On the MODEL_5170, port 0x60 is treated as KBD_DATA rather than PPI_A (although the 5170 BIOS also refers
* to it as "PORT_A"). This is the 8042's output buffer and should be read only when KBD_STATUS.OUTBUFF_FULL set.
* On the MODEL_5170, port 0x60 is designated KBD_DATA rather than PPI_A, although the BIOS also refers to it
* as "PORT_A: 8042 KEYBOARD SCAN/DIAG OUTPUTS"). This is the 8042's output buffer and should be read only when
* KBD_STATUS.OUTBUFF_FULL is set.
*
* The MODEL_5170 also uses port 0x61 (PPI_B), which the BIOS refers to as "8042 READ WRITE REGISTER (PORT_B)",
* but it is not discussed in the MODEL_5170 TechRef's 8042 documentation. There are brief references to bits 0
* and 1 (PPI_B.CLK_TIMER2 and PPI_B.SPK_TIMER2), and the BIOS sets bits 3-7 to "DISABLE PARITY CHECKERS"
* (principally PPI_B.DISABLE_RW_MEM and PPI_B.DISABLE_IO_CHK, which are bits 4 and 5); why the BIOS also sets
* bits 3 and 6-7 is unclear and undocumented, since it uses 11111100B rather than defined constants.
* Similarly, port 0x61 is designated KBD_RWREG rather than PPI_B; the BIOS also refers to it as "PORT_B: 8042
* READ WRITE REGISTER", but it is not otherwise discussed in the MODEL_5170 TechRef's 8042 documentation.
* There are brief references to bits 0 and 1 (KBD_RWREG.CLK_TIMER2 and KBD_RWREG.SPK_TIMER2), and the BIOS sets
* bits 2-7 to "DISABLE PARITY CHECKERS" (principally KBD_RWREG.DISABLE_CHK, which are bits 2 and 3); why the BIOS
* also sets bits 4-7 (or if those bits are even settable) is unclear, since it uses 11111100B rather than defined
* constants.
*
* The bottom line is, even on a MODEL_5170, PPI_B is still used for speaker control and parity checking. It's
* not clear whether that port is managed by the 8042 or independent circuitry.
*
* PPI_B on a MODEL_5170 is also bi-directional: at one point, the BIOS reads bit 5 (PPI_B.DISABLE_RW_MEM) to verify
* that it's alternating (the BIOS refers to it as "REFRESH_BIT").
* The bottom line: on a MODEL_5170, port 0x61 is still used for speaker control and parity checking, so we use
* the same register (bPPIB) but install different I/O handlers. It's also bi-directional: at one point, the BIOS
* reads KBD_RWREG.REFRESH_BIT (bit 4) to verify that it's alternating.
*
* PPI_C and PPI_CTRL are neither documented nor used by the MODEL_5170 BIOS, so I'm assuming they're obsolete.
*
@ -565,7 +566,7 @@ ChipSet.PPI_SW.FDRIVE.SHIFT = 6;
* http://halicery.com/8042/8042_INTERN_TXT.htm
* http://www.os2museum.com/wp/?p=589 ("IBM PC/AT 8042 Keyboard Controller Commands")
*/
ChipSet.KBD_DATA = { // this.b8042OutBuff
ChipSet.KBD_DATA = { // this.b8042OutBuff (PPI_A on previous models, still referred to as "PORT A" by the MODEL_5170 BIOS)
PORT: 0x60
};
@ -612,6 +613,26 @@ ChipSet.KBD_DATA.TESTPORT = { // generated "on the fly"
KBD_DATA: 0x02 // keyboard data (input)
};
ChipSet.KBD_RWREG = { // this.bPPIB (since CLK_TIMER2 and SPK_TIMER2 are in both PPI_B and KBD_RWREG)
PORT: 0x61,
CLK_TIMER2: 0x01, // set to enable clock to TIMER2
SPK_TIMER2: 0x02, // set to connect output of TIMER2 to speaker
DISABLE_CHK: 0x0C, // set these bits to disable I/O and RAM parity checks, clear them to enable checks
REFRESH_BIT: 0x10, // indicates memory refresh
IO_CHK: 0x40, // indicates I/O check
PARITY_CHK: 0x80, // indicates RAM parity check
PARITY_ERR: 0xC0
};
ChipSet.KBD_DATA.CMD = { // this.b8042CmdData (KBD_DATA.CMD "data bytes" written to port 0x60, after writing a KBD_CMD byte to port 0x64)
PC_COMPAT: 0x40, // generate IBM PC-compatible scan codes
PC_MODE: 0x20,
NO_CLOCK: 0x10, // disable keyboard by driving "clock" line low
NO_INHIBIT: 0x08, // disable inhibit function
SYS_FLAG: 0x04, // this value is propagated to ChipSet.KBD_STATUS.SYS_FLAG
INT_ENABLE: 0x01 // generate an interrupt when the controller places data in the output buffer
};
ChipSet.KBD_CMD = { // this.b8042InBuff (on write to port 0x64, interpret this as a CMD)
PORT: 0x64,
READ_CMD: 0x20,
@ -1245,12 +1266,13 @@ ChipSet.prototype.initCMOSData = function()
this.abCMOSData[ChipSet.CMOS_ADDR.EQUIP] = this.sw1 & (ChipSet.PPI_SW.MONITOR.MASK | ChipSet.PPI_SW.COPROC | ChipSet.PPI_SW.FDRIVE.IPL | ChipSet.PPI_SW.FDRIVE.MASK);
/*
* TODO: We default all floppy diskette drives to non-High Capacity (double-density) drives, but this will have to change.
* TODO: We default all floppy diskette drives to High Capacity, but MODEL_5170 machines will need more control
* over settings like this.
*/
var bDisketteTypes = 0;
var cDisketteDrives = this.getSW1FloppyDrives();
if (cDisketteDrives > 0) bDisketteTypes |= ChipSet.CMOS_FDRIVE.D0_DS;
if (cDisketteDrives > 1) bDisketteTypes |= ChipSet.CMOS_FDRIVE.D1_DS;
if (cDisketteDrives > 0) bDisketteTypes |= ChipSet.CMOS_FDRIVE.D0_HC;
if (cDisketteDrives > 1) bDisketteTypes |= ChipSet.CMOS_FDRIVE.D1_HC;
this.abCMOSData[ChipSet.CMOS_ADDR.FDRIVE] = bDisketteTypes;
var wBaseMemKb = this.getSWMemorySize();
@ -2266,7 +2288,10 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (DEBUG) obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", ChipSet.MESSAGE_DMA);
channel.fWarning = true;
}
b = 0xff; // TODO: Determine whether to abort, as we do for DMA_MODE_XFER_READ
/*
* TODO: Determine whether to abort, as we do for DMA_MODE_XFER_READ.
*/
b = 0xff;
}
if (!channel.masked) {
/*
@ -3263,6 +3288,29 @@ ChipSet.prototype.updateAllTimers = function(fCycleReset)
if (this.model >= ChipSet.MODEL_5170) this.updateRTCDate();
};
/**
* updateSpeaker(bOut)
*
* @this {ChipSet}
* @param {number} bOut
*/
ChipSet.prototype.updateSpeaker = function(bOut)
{
var fNewSpeaker = !!(bOut & ChipSet.PPI_B.SPK_TIMER2);
var fOldSpeaker = !!(this.bPPIB & ChipSet.PPI_B.SPK_TIMER2);
this.bPPIB = bOut;
if (fNewSpeaker != fOldSpeaker) {
/*
* Originally, this code didn't catch the "ERROR_BEEP" case @F000:EC34, which first turns both PPI_B_CLK_TIMER2 (0x01)
* and PPI_B_SPK_TIMER2 (0x02) off, then turns on only PPI_B_SPK_TIMER2 (0x02), then restores the original port value.
*
* So, when the ROM BIOS keyboard buffer got full, we didn't issue a BEEP alert. I've fixed that by limiting the test
* to PPI_B_SPK_TIMER2 and ignoring PPI_B_CLK_TIMER2.
*/
this.setSpeaker(fNewSpeaker);
}
};
/**
* inPPIA(port, addrFrom)
*
@ -3302,7 +3350,7 @@ ChipSet.prototype.outPPIA = function(port, bOut, addrFrom)
/**
* inPPIB(port, addrFrom)
*
*
* @this {ChipSet}
* @param {number} port (0x61)
* @param {number|undefined} addrFrom (not defined if the Debugger is trying to read the specified port)
@ -3311,18 +3359,13 @@ ChipSet.prototype.outPPIA = function(port, bOut, addrFrom)
ChipSet.prototype.inPPIB = function(port, addrFrom)
{
var b = this.bPPIB;
/*
* "TEST.09" of the MODEL_5170 BIOS expects the following bit ("REFRESH_BIT") to alternate, so we oblige;
* hopefully this won't affect MODEL_5150 or MODEL_5160, because we didn't used to do this.
*/
this.bPPIB ^= ChipSet.PPI_B.DISABLE_RW_MEM;
this.messagePort(port, null, addrFrom, "PPI_B", ChipSet.MESSAGE_CHIPSET, b);
return b;
};
/**
* outPPIB(port, bOut, addrFrom)
*
*
* @this {ChipSet}
* @param {number} port (0x61)
* @param {number} bOut
@ -3331,19 +3374,7 @@ ChipSet.prototype.inPPIB = function(port, addrFrom)
ChipSet.prototype.outPPIB = function(port, bOut, addrFrom)
{
this.messagePort(port, bOut, addrFrom, "PPI_B", ChipSet.MESSAGE_CHIPSET);
var fNewSpeaker = !!(bOut & ChipSet.PPI_B.SPK_TIMER2);
var fOldSpeaker = !!(this.bPPIB & ChipSet.PPI_B.SPK_TIMER2);
this.bPPIB = bOut;
if (fNewSpeaker != fOldSpeaker) {
/*
* Originally, this code didn't catch the "ERROR_BEEP" case @F000:EC34, which first turns both PPI_B_CLK_TIMER2 (0x01)
* and PPI_B_SPK_TIMER2 (0x02) off, then turns on only PPI_B_SPK_TIMER2 (0x02), then restores the original port value.
*
* So, when the ROM BIOS keyboard buffer got full, we didn't issue a BEEP alert. I've fixed that by limiting the test
* to PPI_B_SPK_TIMER2 and ignoring PPI_B_CLK_TIMER2.
*/
this.setSpeaker(fNewSpeaker);
}
this.updateSpeaker(bOut);
if (this.kbd) this.kbd.setEnable((bOut & ChipSet.PPI_B.CLEAR_KBD)? false : true, (bOut & ChipSet.PPI_B.CLK_KBD)? true : false);
};
@ -3529,7 +3560,7 @@ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
* F000:1B65 C3 RET
*
* But WAIT, the FUN doesn't end there. After this function returns, "KBD_RESET" waits for a Keyboard interrupt
* to occur, hoping for a 0xAA scan code as the Keyboard's final response. "KBD_RESET" also returns CX to the caller,
* to occur, hoping for scan code 0xAA as the Keyboard's final response. "KBD_RESET" also returns CX to the caller,
* and the caller ("TEST.21") assumes there was no interrupt if CX is zero.
*
* MOV AL,0FDH
@ -3546,7 +3577,8 @@ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
* ...
*
* However, if [INTR_FLAG] is set immediately, the above code will exit immediately, without ever decrementing CX.
* CX can be zero not only if the loop exhausted it, but also if no looping was required!
* CX can be zero not only if the loop exhausted it, but also if no looping was required; the latter is not an
* error, but "TEST.21" assumes that it is.
*/
default:
this.b8042CmdData &= ~ChipSet.KBD_DATA.CMD.NO_CLOCK;
@ -3558,6 +3590,43 @@ ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
this.b8042Status &= ~ChipSet.KBD_STATUS.CMD_FLAG;
};
/**
* in8042RWReg(port, addrFrom)
*
* @this {ChipSet}
* @param {number} port (0x61)
* @param {number|undefined} addrFrom (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.in8042RWReg = function(port, addrFrom)
{
/*
* Normally, we return whatever was last written to this port, but we do need to mask the
* two upper-most bits (KBD_RWREG.PARITY_ERR), because we never want to report a parity error.
*/
var b = this.bPPIB & ~ChipSet.KBD_RWREG.PARITY_ERR;
this.messagePort(port, null, addrFrom, "8042_RWREG", ChipSet.MESSAGE_CHIPSET, b);
/*
* "TEST.09" of the MODEL_5170 BIOS expects the following bit ("REFRESH_BIT") to alternate, so we oblige.
*/
this.bPPIB ^= ChipSet.KBD_RWREG.REFRESH_BIT;
return b;
};
/**
* out8042RWReg(port, bOut, addrFrom)
*
* @this {ChipSet}
* @param {number} port (0x61)
* @param {number} bOut
* @param {number|undefined} addrFrom (not defined if the Debugger is trying to read the specified port)
*/
ChipSet.prototype.out8042RWReg = function(port, bOut, addrFrom)
{
this.messagePort(port, bOut, addrFrom, "8042_RWREG", ChipSet.MESSAGE_CHIPSET);
this.updateSpeaker(bOut);
};
/**
* in8042Status(port, addrFrom)
*
@ -3975,7 +4044,7 @@ ChipSet.aPortInput5150 = {
ChipSet.aPortInput5170 = {
0x60: ChipSet.prototype.in8042OutBuff,
0x61: ChipSet.prototype.inPPIB,
0x61: ChipSet.prototype.in8042RWReg,
0x64: ChipSet.prototype.in8042Status,
0x70: ChipSet.prototype.inCMOSAddr,
0x71: ChipSet.prototype.inCMOSData,
@ -4045,7 +4114,7 @@ ChipSet.aPortOutput5150 = {
ChipSet.aPortOutput5170 = {
0x60: ChipSet.prototype.out8042InBuffData,
0x61: ChipSet.prototype.outPPIB,
0x61: ChipSet.prototype.out8042RWReg,
0x64: ChipSet.prototype.out8042InBuffCmd,
0x70: ChipSet.prototype.outCMOSAddr,
0x71: ChipSet.prototype.outCMOSData,

View file

@ -86,11 +86,11 @@ function Debugger(parmsDbg)
* or aAddrNextData when no address has been given. doDump() and doUnassemble(), in turn,
* update aAddrNextData and aAddrNextCode, respectively, when they're done.
*
* The format of all aAddr variables is [off, seg], where seg:off is a segmented address if
* seg is defined, and off is a physical address if seg is undefined. For some segmented
* addresses (eg, breakpoint addresses), we also pre-compute the physical address and save that
* in aAddr[2], so that the breakpoint will still operate as intended even if the mode changes
* later (eg, from real-mode to protected-mode).
* The format of all aAddr variables is [off, seg, addr], where seg:off is the segmented
* address and addr is the corresponding physical address. For some segmented addresses
* (eg, breakpoint addresses), we pre-compute the physical address and save that in aAddr[2],
* so that the breakpoint will still operate as intended even if the mode changes later
* (eg, from real-mode to protected-mode).
*
* Finally, for TEMPORARY breakpoint addresses, we set aAddr[3] to true, so that they can be
* automatically cleared when they're hit.
@ -1491,7 +1491,7 @@ if (DEBUGGER) {
* Preallocate dummy Addr (Array) objects in every history slot, so that checkInstruction()
* doesn't need to call newAddr() on every instruction check.
*/
this.aOpcodeHistory[i] = [0, 0, 0];
this.aOpcodeHistory[i] = [0, null, 0];
}
this.iOpcodeHistory = 0;
}
@ -1973,7 +1973,7 @@ if (DEBUGGER) {
* @this {Debugger}
* @param {Array} aAddr
* @param {boolean} [fWrite]
* @param {number} [cb]
* @param {number} [cb] is number of extra bytes to check (0 or 1)
* @return {number} is the corresponding physical address, or -1 if there's an error
*/
Debugger.prototype.getAddr = function(aAddr, fWrite, cb)
@ -1986,15 +1986,11 @@ if (DEBUGGER) {
*/
var addr = aAddr[2];
if (addr == null) {
if (aAddr[1] == null) {
addr = (aAddr[0] <= this.bus.addrLimit? aAddr[0] : -1);
var seg = this.getSegment(aAddr[1]);
if (!fWrite) {
addr = seg.checkRead(aAddr[0], cb || 0, true);
} else {
var seg = this.getSegment(aAddr[1]);
if (!fWrite) {
addr = seg.checkRead(aAddr[0], cb || 0, true);
} else {
addr = seg.checkWrite(aAddr[0], cb || 0, true);
}
addr = seg.checkWrite(aAddr[0], cb || 0, true);
}
}
/*
@ -2020,7 +2016,7 @@ if (DEBUGGER) {
Debugger.prototype.getByte = function(aAddr, inc)
{
var b = 0xff;
var addr = this.getAddr(aAddr, false, 1);
var addr = this.getAddr(aAddr, false, 0);
if (addr >= 0) {
b = this.bus.getByteDirect(addr);
Component.assert((b == (b & 0xff)), "invalid byte (" + b + ") at address: " + this.hexAddr(aAddr));
@ -2040,7 +2036,7 @@ if (DEBUGGER) {
Debugger.prototype.getWord = function(aAddr, inc)
{
var w = 0xffff;
var addr = this.getAddr(aAddr, false, 2);
var addr = this.getAddr(aAddr, false, 1);
if (addr >= 0) {
w = this.bus.getWordDirect(addr);
Component.assert((w == (w & 0xffff)), "invalid word (" + w + ") at address: " + this.hexAddr(aAddr));
@ -2063,7 +2059,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.setByte = function(aAddr, b, inc)
{
var addr = this.getAddr(aAddr, true, 1);
var addr = this.getAddr(aAddr, true, 0);
if (addr >= 0) {
this.bus.setByteDirect(addr, b);
if (inc !== undefined) this.incAddr(aAddr, inc);
@ -2081,7 +2077,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.setWord = function(aAddr, w, inc)
{
var addr = this.getAddr(aAddr, true, 2);
var addr = this.getAddr(aAddr, true, 1);
if (addr >= 0) {
this.bus.setWordDirect(addr, w);
if (inc !== undefined) this.incAddr(aAddr, inc);
@ -2098,24 +2094,29 @@ if (DEBUGGER) {
*/
Debugger.prototype.hexAddr = function(aAddr)
{
return aAddr[1] == null? ("%" + str.toHex(aAddr[0])) : str.toHexAddr(aAddr[0], aAddr[1]);
return aAddr[1] == null? ("%" + str.toHex(aAddr[2])) : str.toHexAddr(aAddr[0], aAddr[1]);
};
/**
* incAddr(aAddr, inc)
*
* @this {Debugger}
* @param {Array} aAddr containing [off, seg]
* @param {Array} aAddr containing [off, seg, addr]
* @param {number|undefined} inc contains value to increment by (default is 1)
*/
Debugger.prototype.incAddr = function(aAddr, inc)
{
inc = (inc === undefined? 1 : inc);
aAddr[0] += inc;
if (aAddr[2] != null) aAddr[2] += inc;
if (aAddr[0] != (aAddr[0] & 0xffff)) {
aAddr[0] = aAddr[0] & 0xffff;
aAddr[2] = null;
if (aAddr[2] != null) {
aAddr[2] += inc;
}
if (aAddr[1] != null) {
aAddr[0] += inc;
// TODO: Shouldn't we be using the segment (aAddr[1]) limit instead of 0xffff?
if (aAddr[0] != (aAddr[0] & 0xffff)) {
aAddr[0] = aAddr[0] & 0xffff;
aAddr[2] = null;
}
}
};
@ -2223,6 +2224,9 @@ if (DEBUGGER) {
/**
* listBreakpoints(aBreak)
*
* TODO: We may need to start listing the physical addresses of breakpoints, because
* segmented address can be ambiguous.
*
* @this {Debugger}
* @param {Array} aBreak
* @return {number} of breakpoints listed, 0 if none
@ -2348,7 +2352,7 @@ if (DEBUGGER) {
*/
Debugger.prototype.getInstruction = function(aAddr, sComment, nSequence)
{
var aAddrIns = this.newAddr(aAddr[0], aAddr[1]);
var aAddrIns = this.newAddr(aAddr[0], aAddr[1], aAddr[2]);
var bOpcode = this.getByte(aAddr, 1);
var aOpDesc = this.aaOpDescs[bOpcode];
@ -2716,8 +2720,8 @@ if (DEBUGGER) {
/**
* parseAddr(sAddr, type)
*
* As discussed above, the format of all aAddr variables is [off, seg]; they represent a segmented
* address (seg:off) when seg is defined or a physical address (off) when seg is undefined (or null).
* As discussed above, the format of aAddr variables is [off, seg, addr]; they represent a segmented
* address (seg:off) when seg is defined or a physical address (addr) when seg is undefined (or null).
*
* To create a segmented address, specify two values separated by ":"; for a physical address, use
* a "%" prefix. We check for ":" after "%", so if for some strange reason you specify both, the
@ -2743,13 +2747,14 @@ if (DEBUGGER) {
{
var aAddrNext = (type == Debugger.ADDR_DATA? this.aAddrNextData : this.aAddrNextCode);
var off = aAddrNext[0], seg = aAddrNext[1];
var off = aAddrNext[0], seg = aAddrNext[1], addr = aAddrNext[2];
if (sAddr !== undefined) {
if (sAddr.charAt(0) == '%') {
sAddr = sAddr.substr(1);
seg = null;
addr = 0;
}
var aAddr = this.findSymbolAddr(sAddr);
@ -2757,14 +2762,18 @@ if (DEBUGGER) {
var iColon = sAddr.indexOf(":");
if (iColon < 0) {
off = this.parseValue(sAddr);
if (addr == null) {
off = this.parseValue(sAddr);
} else {
addr = this.parseValue(sAddr);
}
}
else {
seg = this.parseValue(sAddr.substring(0, iColon));
off = this.parseValue(sAddr.substring(iColon + 1));
}
}
return [off, seg];
return [off, seg, addr];
};
/**
@ -3502,7 +3511,7 @@ if (DEBUGGER) {
}
iHistory -= n;
if (iHistory < 0) {
if (aHistory[aHistory.length - 1].length) {
if (aHistory[aHistory.length - 1][1] != null) {
iHistory += aHistory.length;
} else {
n = iHistory + n;
@ -3514,10 +3523,10 @@ if (DEBUGGER) {
}
while (cLines && iHistory != this.iOpcodeHistory) {
var aAddr = aHistory[iHistory];
if (!aAddr.length) break;
if (aAddr[1] == null) break;
/*
* We must create a new aAddr from the address we obtained from aHistory, because
* it was a reference, not a copy, and we don't want getInstruction() modifying the original.
* aAddr was a reference, not a copy, and we don't want getInstruction() modifying the original.
*/
aAddr = this.newAddr(aAddr[0], aAddr[1], aAddr[2]);
this.println(this.getInstruction(aAddr, "history", -n));
@ -4229,7 +4238,7 @@ if (DEBUGGER) {
return;
if (n === undefined) n = 1;
var aAddrEnd = this.newAddr(this.bus.addrLimit, aAddr[1]);
var aAddrEnd = this.newAddr(0xffff, aAddr[1], this.bus.addrLimit);
if (sAddrEnd !== undefined) {
aAddrEnd = this.parseAddr(sAddrEnd, Debugger.ADDR_CODE);
@ -4250,7 +4259,7 @@ if (DEBUGGER) {
var fBlank = (aAddr[0] != this.aAddrNextCode[0]);
while (n-- && aAddr[0] < aAddrEnd[0]) {
while (n-- && (aAddr[1] != null? (aAddr[0] < aAddrEnd[0]) : (aAddr[2] < aAddrEnd[2]))) {
/*
* I pass nCycles instead of cInstructions to getInstruction() now, to assist with visual
* verification of the accuracy (or inaccuracy) of instruction cycle counts.

View file

@ -1374,9 +1374,14 @@ FDC.prototype.outFDCControl = function(port, bOut, addrFrom)
FDC.prototype.intBIOSDiskette = function(addr)
{
if (DEBUGGER) {
var AL = this.cpu.regAX & 0xff;
var AH = this.cpu.regAX >> 8;
var CL = this.cpu.regCX & 0xff;
var CH = this.cpu.regCX >> 8;
var DL = this.cpu.regDX & 0xff;
var DH = this.cpu.regDX >> 8;
if (this.dbg && this.dbg.messageEnabled(this.dbg.MESSAGE_FDC) && DL < 0x80) {
this.dbg.message("FDC.intBIOS(AX=" + str.toHexWord(this.cpu.regAX) + ",DL=" + str.toHexByte(DL) + ") at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel));
this.dbg.message("FDC.intBIOS(AH=" + str.toHexByte(AH) + ",D=" + str.toHexByte(DL) + ",C=" + str.toHexByte(CH) + ",H=" + str.toHexByte(DH) + ",S=" + str.toHexByte(CL) + ",N=" + str.toHexByte(AL) + ") at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel));
// this.cpu.haltCPU();
this.cpu.addInterruptReturn(addr, function (fdc, nCycles) {
return function onBIOSDisketteReturn(nLevel) {

View file

@ -1810,6 +1810,9 @@ X86CPU.prototype.modEAByteDisabled = function(seg, off)
{
this.segEA = seg;
this.offEA = off;
/*
* TODO: Should this not also set regEA? Optimization or oversight?
*/
this.regEAWrite = seg.base + off;
return 0;
};
@ -1909,13 +1912,6 @@ X86CPU.prototype.modEAWordEnabled = function(seg, off)
X86CPU.prototype.setEAByteEnabled = function(b)
{
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
/*
* TODO: We used to call checkEAWrite(this.segEA, this.offEA, 1), which would simply return
* regEAWrite in real-mode (or recalculate the address in prot-mode and verify that it still matched
* regEAWrite); determine if there's any value in reinstating that feature with the new X86Seg class.
*
* this.setByte(this.checkEAWrite(this.segEA, this.offEA, 1), b);
*/
this.setByte(this.segEA.checkWrite(this.offEA, 1), b);
};
@ -1928,13 +1924,6 @@ X86CPU.prototype.setEAByteEnabled = function(b)
X86CPU.prototype.setEAWordEnabled = function(w)
{
if (!FASTDISABLE && (this.opFlags & X86.OPFLAG.NOWRITE)) return;
/*
* TODO: We used to call checkEAWrite(this.segEA, this.offEA, 2), which would simply return
* regEAWrite in real-mode (or recalculate the address in prot-mode and verify that it still matched
* regEAWrite); determine if there's any value in reinstating that feature with the new X86Seg class.
*
* this.setByte(this.checkEAWrite(this.segEA, this.offEA, 1), b);
*/
this.setWord(this.segEA.checkWrite(this.offEA, 2), w);
};

View file

@ -162,7 +162,7 @@ X86Seg.loadProt = function loadProt(sel, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb
* @param {number} cb is number of extra bytes to check (0 or 1)
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} corresponding physical address if valid, -1 if not
*/
@ -179,7 +179,7 @@ X86Seg.checkReadReal = function checkReadReal(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb
* @param {number} cb is number of extra bytes to check (0 or 1)
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} corresponding physical address if valid, -1 if not
*/
@ -193,7 +193,7 @@ X86Seg.checkWriteReal = function checkWriteReal(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb
* @param {number} cb is number of extra bytes to check (0 or 1)
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} corresponding physical address if valid, -1 if not
*/
@ -210,7 +210,7 @@ X86Seg.checkReadProtEnabled = function checkReadProtEnabled(off, cb, fSuppress)
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb
* @param {number} cb is number of extra bytes to check (0 or 1)
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} corresponding physical address if valid, -1 if not
*/
@ -227,7 +227,7 @@ X86Seg.checkReadProtDisabled = function checkReadProtDisabled(off, cb, fSuppress
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb
* @param {number} cb is number of extra bytes to check (0 or 1)
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} corresponding physical address if valid, -1 if not
*/
@ -244,7 +244,7 @@ X86Seg.checkWriteProtEnabled = function checkWriteProtEnabled(off, cb, fSuppress
*
* @this {X86Seg}
* @param {number} off is a segment-relative offset
* @param {number} cb
* @param {number} cb is number of extra bytes to check (0 or 1)
* @param {boolean} [fSuppress] is true to suppress any errors
* @return {number} corresponding physical address if valid, -1 if not
*/