Hard disk controller fixes

Still some lingering OS/2 disk-related issues however
This commit is contained in:
Jeff Parsons 2014-12-03 16:59:12 -08:00 • committed by jeffpar
commit 9578faf231
12 changed files with 392 additions and 296 deletions

File diff suppressed because one or more lines are too long

View file

@ -121,7 +121,7 @@
F000:04C6 @ COMMANDI F000:04C6 @ COMMANDI
F000:0505 @ COMMANDO F000:0505 @ COMMANDO
F000:055C @ COMMAND F000:055C @ COMMAND
F000:055C @ WAIT F000:05C2 @ WAIT
F000:05F3 @ NOT_BUSY F000:05F3 @ NOT_BUSY
F000:061A @ WAIT_DRQ F000:061A @ WAIT_DRQ
F000:0630 @ CHECK_STATUS F000:0630 @ CHECK_STATUS

View file

@ -503,16 +503,16 @@ ChipSet.PIC_HI = { // ChipSet.PIC1.PORT_HI or ChipSet.PIC2.PORT_HI
ChipSet.IRQ = { ChipSet.IRQ = {
TIMER0: 0x00, TIMER0: 0x00,
KBD: 0x01, KBD: 0x01,
SLAVE: 0x02, SLAVE: 0x02, // MODEL_5170
COM2: 0x03, COM2: 0x03,
COM1: 0x04, COM1: 0x04,
XTC: 0x05, // MODEL_5160 uses IRQ 5 for HDC (XTC version) XTC: 0x05, // MODEL_5160 uses IRQ 5 for HDC (XTC version)
LPT2: 0x05, // MODEL_5170 uses IRQ 5 for LPT2 LPT2: 0x05, // MODEL_5170 uses IRQ 5 for LPT2
FDC: 0x06, FDC: 0x06,
LPT1: 0x07, LPT1: 0x07,
RTC: 0x08, RTC: 0x08, // MODEL_5170
IRQ2: 0x09, IRQ2: 0x09, // MODEL_5170
COPROC: 0x0D, COPROC: 0x0D, // MODEL_5170
ATC: 0x0E // MODEL_5170 uses IRQ 14 for HDC (ATC version) ATC: 0x0E // MODEL_5170 uses IRQ 14 for HDC (ATC version)
}; };
@ -1332,17 +1332,17 @@ ChipSet.prototype.getRTCCycleLimit = function(nCycles)
if (nCyclesUpdate > 0) { if (nCyclesUpdate > 0) {
if (nCycles > nCyclesUpdate) { if (nCycles > nCyclesUpdate) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) {
this.messageDebugger("getRTCCycleLimit(" + nCycles + "): reduced to " + nCyclesUpdate + " cycles"); this.messageDebugger("getRTCCycleLimit(" + nCycles + "): reduced to " + nCyclesUpdate + " cycles", true);
} }
nCycles = nCyclesUpdate; nCycles = nCyclesUpdate;
} else { } else {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) {
this.messageDebugger("getRTCCycleLimit(" + nCycles + "): already less than " + nCyclesUpdate + " cycles"); this.messageDebugger("getRTCCycleLimit(" + nCycles + "): already less than " + nCyclesUpdate + " cycles", true);
} }
} }
} else { } else {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.RTC)) {
this.messageDebugger("RTC next update has passed by " + nCyclesUpdate + " cycles"); this.messageDebugger("RTC next update has passed by " + nCyclesUpdate + " cycles", true);
} }
} }
} }
@ -2289,7 +2289,7 @@ ChipSet.prototype.inDMAChannelAddr = function(iDMAC, iChannel, port, addrFrom)
var channel = controller.aChannels[iChannel]; var channel = controller.aChannels[iChannel];
var b = channel.addrCurrent[controller.bIndex]; var b = channel.addrCurrent[controller.bIndex];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", 0, b); this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", b, true);
} }
controller.bIndex ^= 0x1; controller.bIndex ^= 0x1;
/* /*
@ -2326,7 +2326,7 @@ ChipSet.prototype.outDMAChannelAddr = function outDMAChannelAddr(iDMAC, iChannel
{ {
var controller = this.aDMACs[iDMAC]; var controller = this.aDMACs[iDMAC];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".ADDR[" + controller.bIndex + "]", null, true);
} }
var channel = controller.aChannels[iChannel]; var channel = controller.aChannels[iChannel];
channel.addrCurrent[controller.bIndex] = channel.addrInit[controller.bIndex] = bOut; channel.addrCurrent[controller.bIndex] = channel.addrInit[controller.bIndex] = bOut;
@ -2349,7 +2349,7 @@ ChipSet.prototype.inDMAChannelCount = function(iDMAC, iChannel, port, addrFrom)
var channel = controller.aChannels[iChannel]; var channel = controller.aChannels[iChannel];
var b = channel.countCurrent[controller.bIndex]; var b = channel.countCurrent[controller.bIndex];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", 0, b); this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", b, true);
} }
controller.bIndex ^= 0x1; controller.bIndex ^= 0x1;
/* /*
@ -2390,7 +2390,7 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add
{ {
var controller = this.aDMACs[iDMAC]; var controller = this.aDMACs[iDMAC];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".COUNT[" + controller.bIndex + "]", null, true);
} }
var channel = controller.aChannels[iChannel]; var channel = controller.aChannels[iChannel];
channel.countCurrent[controller.bIndex] = channel.countInit[controller.bIndex] = bOut; channel.countCurrent[controller.bIndex] = channel.countInit[controller.bIndex] = bOut;
@ -2433,7 +2433,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
var b = controller.bStatus | ChipSet.DMA_STATUS.CH0_TC; var b = controller.bStatus | ChipSet.DMA_STATUS.CH0_TC;
controller.bStatus &= ~ChipSet.DMA_STATUS.ALL_TC; controller.bStatus &= ~ChipSet.DMA_STATUS.ALL_TC;
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", 0, b); this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".STATUS", b, true);
} }
return b; return b;
}; };
@ -2450,7 +2450,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CMD"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CMD", null, true);
} }
this.aDMACs[iDMAC].bCmd = bOut; this.aDMACs[iDMAC].bCmd = bOut;
}; };
@ -2478,7 +2478,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
{ {
var controller = this.aDMACs[iDMAC]; var controller = this.aDMACs[iDMAC];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".REQ"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".REQ", null, true);
} }
/* /*
* Bits 0-1 contain the channel number * Bits 0-1 contain the channel number
@ -2505,7 +2505,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
{ {
var controller = this.aDMACs[iDMAC]; var controller = this.aDMACs[iDMAC];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASK", null, true);
} }
var iChannel = bOut & ChipSet.DMA_MASK.CHANNEL; var iChannel = bOut & ChipSet.DMA_MASK.CHANNEL;
var channel = controller.aChannels[iChannel]; var channel = controller.aChannels[iChannel];
@ -2525,7 +2525,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MODE"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MODE", null, true);
} }
var iChannel = bOut & ChipSet.DMA_MODE.CHANNEL; var iChannel = bOut & ChipSet.DMA_MODE.CHANNEL;
this.aDMACs[iDMAC].aChannels[iChannel].mode = bOut; this.aDMACs[iDMAC].aChannels[iChannel].mode = bOut;
@ -2546,7 +2546,7 @@ ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom)
ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".RESET_FF", null, true);
} }
this.aDMACs[iDMAC].bIndex = 0; this.aDMACs[iDMAC].bIndex = 0;
}; };
@ -2563,7 +2563,7 @@ ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom)
ChipSet.prototype.outDMAMasterClear = function(iDMAC, port, bOut, addrFrom) ChipSet.prototype.outDMAMasterClear = function(iDMAC, port, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".MASTER_CLEAR", null, true);
} }
/* /*
* The value written to this port doesn't matter; any write triggers a "master clear" operation * The value written to this port doesn't matter; any write triggers a "master clear" operation
@ -2590,7 +2590,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom)
{ {
var bIn = this.aDMACs[iDMAC].aChannels[iChannel].bPage; var bIn = this.aDMACs[iDMAC].aChannels[iChannel].bPage;
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", 0, bIn); this.messagePort(port, null, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", bIn, true);
} }
return bIn; return bIn;
}; };
@ -2608,7 +2608,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom)
ChipSet.prototype.outDMAPageReg = function(iDMAC, iChannel, port, bOut, addrFrom) ChipSet.prototype.outDMAPageReg = function(iDMAC, iChannel, port, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE"); this.messagePort(port, bOut, addrFrom, "DMA" + iDMAC + ".CHANNEL" + iChannel + ".PAGE", null, true);
} }
this.aDMACs[iDMAC].aChannels[iChannel].bPage = bOut; this.aDMACs[iDMAC].aChannels[iChannel].bPage = bOut;
}; };
@ -2626,7 +2626,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom)
{ {
var bIn = this.abDMAPageSpare[iSpare]; var bIn = this.abDMAPageSpare[iSpare];
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, null, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", 0, bIn); this.messagePort(port, null, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", bIn, true);
} }
return bIn; return bIn;
}; };
@ -2643,7 +2643,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom)
ChipSet.prototype.outDMAPageSpare = function(iSpare, port, bOut, addrFrom) ChipSet.prototype.outDMAPageSpare = function(iSpare, port, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "DMA.SPARE" + iSpare + ".PAGE"); this.messagePort(port, bOut, addrFrom, "DMA.SPARE" + iSpare + ".PAGE", null, true);
} }
this.abDMAPageSpare[iSpare] = bOut; this.abDMAPageSpare[iSpare] = bOut;
}; };
@ -2713,7 +2713,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
if (!channel.component || !channel.fnTransfer || !channel.obj) { if (!channel.component || !channel.fnTransfer || !channel.obj) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) {
this.messageDebugger("requestDMA(" + iDMAChannel + "): not connected to a component"); this.messageDebugger("requestDMA(" + iDMAChannel + "): not connected to a component", true);
} }
if (done) done(true); if (done) done(true);
return; return;
@ -2730,7 +2730,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
if (channel.masked) { if (channel.masked) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.OTHER)) {
this.messageDebugger("requestDMA(" + iDMAChannel + "): channel masked, request queued"); this.messageDebugger("requestDMA(" + iDMAChannel + "): channel masked, request queued", true);
} }
return; return;
} }
@ -2783,7 +2783,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (DEBUG && DEBUGGER && channel.sAddrDebug === null) { if (DEBUG && DEBUGGER && channel.sAddrDebug === null) {
channel.sAddrDebug = str.toHex(addr >> 4, 4) + ":" + str.toHex(addr & 0xf, 4); channel.sAddrDebug = str.toHex(addr >> 4, 4) + ":" + str.toHex(addr & 0xf, 4);
if (this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) { if (this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer != ChipSet.DMA_MODE.XFER_WRITE) {
this.messageDebugger("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug); this.messageDebugger("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug, true);
this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16));
} }
} }
@ -2794,7 +2794,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (b < 0) { if (b < 0) {
if (!channel.fWarning) { if (!channel.fWarning) {
if (DEBUG && obj.messageEnabled(Debugger.MESSAGE.DMA)) { if (DEBUG && obj.messageEnabled(Debugger.MESSAGE.DMA)) {
obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff"); obj.messageDebugger("advanceDMA(" + iDMAChannel + ") ran out of data, assuming 0xff", true);
} }
channel.fWarning = true; channel.fWarning = true;
} }
@ -2843,7 +2843,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
} }
else { else {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.WARN)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.DMA | Debugger.MESSAGE.WARN)) {
this.messageDebugger("advanceDMA(" + iDMAChannel + ") unsupported xfer mode: " + str.toHexWord(channel.xfer)); this.messageDebugger("advanceDMA(" + iDMAChannel + ") unsupported xfer mode: " + str.toHexWord(channel.xfer), true);
} }
channel.fError = true; channel.fError = true;
} }
@ -2897,7 +2897,7 @@ ChipSet.prototype.updateDMA = function(channel)
} }
if (DEBUG && this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) { if (DEBUG && this.messageEnabled(this.messageBitsDMA(iDMAChannel)) && channel.xfer == ChipSet.DMA_MODE.XFER_WRITE && channel.sAddrDebug) {
this.messageDebugger("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug); this.messageDebugger("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug, true);
this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16));
} }
@ -2938,8 +2938,8 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
break; break;
} }
} }
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, 0, b); this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, b, true);
} }
return b; return b;
}; };
@ -2955,8 +2955,8 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom) ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
{ {
var pic = this.aPICs[iPIC]; var pic = this.aPICs[iPIC];
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC); this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC, null, true);
} }
if (bOut & ChipSet.PIC_LO.ICW1) { if (bOut & ChipSet.PIC_LO.ICW1) {
/* /*
@ -3040,13 +3040,13 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
var nIRQ = (nIRL == null? undefined : pic.nIRQBase + nIRL); var nIRQ = (nIRL == null? undefined : pic.nIRQBase + nIRL);
if (pic.bISR & bIREnd) { if (pic.bISR & bIREnd) {
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) {
this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service"); this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): IRQ " + nIRQ + " going out of service", true);
} }
pic.bISR &= ~bIREnd; pic.bISR &= ~bIREnd;
this.checkIRR(iPIC); this.checkIRR();
} else { } else {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) {
this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unexpected EOI command, IRQ " + nIRQ + " not in service"); this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unexpected EOI command, IRQ " + nIRQ + " not in service", true);
if (!SAMPLER && MAXDEBUG) this.dbg.stopCPU(); if (!SAMPLER && MAXDEBUG) this.dbg.stopCPU();
} }
} }
@ -3054,7 +3054,7 @@ 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) * TODO: Support EOI commands with automatic rotation (eg, ChipSet.PIC_LO.OCW2_EOI_ROT and ChipSet.PIC_LO.OCW2_EOI_ROTSPEC)
*/ */
if (DEBUG && (bOCW2 & ChipSet.PIC_LO.OCW2_SET_ROTAUTO) && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { if (DEBUG && (bOCW2 & ChipSet.PIC_LO.OCW2_SET_ROTAUTO) && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) {
this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut)); this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unsupported OCW2 rotate command: " + str.toHexByte(bOut), true);
this.dbg.stopCPU(); this.dbg.stopCPU();
} }
} }
@ -3069,7 +3069,7 @@ 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 * TODO: Remaining commands to support: ChipSet.PIC_LO.OCW2_SET_ROTAUTO and ChipSet.PIC_LO.OCW2_CLR_ROTAUTO
*/ */
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) {
this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut)); this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unsupported OCW2 automatic EOI command: " + str.toHexByte(bOut), true);
this.dbg.stopCPU(); this.dbg.stopCPU();
} }
} }
@ -3082,7 +3082,7 @@ ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
*/ */
if (bOut & (ChipSet.PIC_LO.OCW3_POLL_CMD | ChipSet.PIC_LO.OCW3_SMM_CMD)) { if (bOut & (ChipSet.PIC_LO.OCW3_POLL_CMD | ChipSet.PIC_LO.OCW3_SMM_CMD)) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.WARN)) {
this.messageDebugger("outPIC" + iPIC + "(" + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut)); this.messageDebugger("outPIC" + iPIC + "(0x" + str.toHexByte(pic.port) + "): unsupported OCW3 command: " + str.toHexByte(bOut), true);
} }
} }
pic.bOCW3 = bOut; pic.bOCW3 = bOut;
@ -3101,8 +3101,8 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
{ {
var pic = this.aPICs[iPIC]; var pic = this.aPICs[iPIC];
var b = pic.bIMR; var b = pic.bIMR;
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, 0, b); this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, b, true);
} }
return b; return b;
}; };
@ -3118,8 +3118,8 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom) ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom)
{ {
var pic = this.aPICs[iPIC]; var pic = this.aPICs[iPIC];
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC); this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC, null, true);
} }
if (pic.nICW < pic.aICW.length) { if (pic.nICW < pic.aICW.length) {
pic.aICW[pic.nICW++] = bOut; pic.aICW[pic.nICW++] = bOut;
@ -3143,80 +3143,7 @@ ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom)
* previous models could be handled with a 4-instruction delay provided by the Keyboard.resetDevice() call * previous models could be handled with a 4-instruction delay provided by the Keyboard.resetDevice() call
* to setIRR(), but the MODEL_5170 needs a roughly 6-instruction delay after it unmasks the KBD IRQ. * to setIRR(), but the MODEL_5170 needs a roughly 6-instruction delay after it unmasks the KBD IRQ.
*/ */
this.checkIRR(iPIC, !iPIC && bOut == 0xFD? 6 : 0); this.checkIRR(!iPIC && bOut == 0xFD? 6 : 0);
}
};
/**
* checkIRR(iPIC, nDelay)
*
* @this {ChipSet}
* @param {number} iPIC
* @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector)
*/
ChipSet.prototype.checkIRR = function(iPIC, nDelay)
{
/*
* Look for any IRR bits that aren't masked and aren't already in service
*/
var pic = this.aPICs[iPIC];
var bIR = ((pic.bISR | pic.bIMR) ^ 0xff) & pic.bIRR;
this.cpu.updateINTR(!!bIR);
if (bIR && nDelay) pic.nDelay = nDelay;
};
/**
* setIRR(nIRQ, nDelay)
*
* @this {ChipSet}
* @param {number} nIRQ (IRQ 0-7 implies iPIC 0, and IRQ 8-15 implies iPIC 1)
* @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector)
*/
ChipSet.prototype.setIRR = function(nIRQ, nDelay)
{
var iPIC = nIRQ >> 3;
var nIRL = nIRQ & 0x7;
var pic = this.aPICs[iPIC];
pic.bIRR |= 1 << nIRL;
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) {
this.messageDebugger("setIRR(" + nIRQ + ")");
}
pic.nDelay = nDelay || 0;
/*
* When any slave IRR goes high, I'm assuming that the master's slave IRR line should go high as well
*/
if (iPIC == 1) this.aPICs[0].bIRR |= 0x4;
this.checkIRR(iPIC);
};
/**
* clearIRR(nIRQ)
*
* @this {ChipSet}
* @param {number} nIRQ (IRQ 0-7 implies iPIC 0, which is all we currently support anyway)
*/
ChipSet.prototype.clearIRR = function(nIRQ)
{
var iPIC = nIRQ >> 3;
var nIRL = nIRQ & 0x7;
var pic = this.aPICs[iPIC];
var bIRR = (1 << nIRL);
if (pic.bIRR & bIRR) {
pic.bIRR &= ~bIRR;
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) {
this.messageDebugger("clearIRR(" + nIRQ + ")");
}
/*
* When all slave IRRs go low, I'm assuming that the master's slave IRR line should go low as well
*/
if (iPIC == 1 && !pic.bIRR) this.aPICs[0].bIRR &= ~0x4;
/*
* NOTE: I don't think calling checkIRR(), and by extension, cpu.updateINTR(false), is strictly necessary,
* because when the CPU gets around to acknowledging the INTR signal, it still has to call getIRRVector(), which
* will inform the CPU that there are no longer any requested interrupts. However, some small efficiency may be
* gained by clearing INTR sooner rather than later. So that's what we'll do.
*/
this.checkIRR(iPIC);
} }
}; };
@ -3235,6 +3162,101 @@ ChipSet.prototype.checkIMR = function(nIRQ)
return (pic.bIMR & (0x1 << nIRL))? true : false; return (pic.bIMR & (0x1 << nIRL))? true : false;
}; };
/**
* setIRR(nIRQ, nDelay)
*
* @this {ChipSet}
* @param {number} nIRQ (IRQ 0-7 implies iPIC 0, and IRQ 8-15 implies iPIC 1)
* @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of the IRQ (see getIRRVector)
*/
ChipSet.prototype.setIRR = function(nIRQ, nDelay)
{
var iPIC = nIRQ >> 3;
var nIRL = nIRQ & 0x7;
var pic = this.aPICs[iPIC];
pic.bIRR |= 1 << nIRL;
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ) | Debugger.MESSAGE.CHIPSET)) {
this.messageDebugger("setIRR(" + nIRQ + ")", true);
}
pic.nDelay = nDelay || 0;
/*
* When any (unmasked) slave IRR goes high, the master's slave IRR line should go high as well
*/
if (iPIC == 1 && (pic.bIRR & ~pic.bIMR)) this.aPICs[0].bIRR |= (1 << ChipSet.IRQ.SLAVE);
this.checkIRR();
};
/**
* clearIRR(nIRQ)
*
* @this {ChipSet}
* @param {number} nIRQ (IRQ 0-7 implies iPIC 0, which is all we currently support anyway)
*/
ChipSet.prototype.clearIRR = function(nIRQ)
{
var iPIC = nIRQ >> 3;
var nIRL = nIRQ & 0x7;
var pic = this.aPICs[iPIC];
var bIRR = (1 << nIRL);
if (pic.bIRR & bIRR) {
pic.bIRR &= ~bIRR;
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ) | Debugger.MESSAGE.CHIPSET)) {
this.messageDebugger("clearIRR(" + nIRQ + ")", true);
}
/*
* When all (unmasked) slave IRRs go low, the master's slave IRR line should go low as well
*/
if (iPIC == 1 && !(pic.bIRR & ~pic.bIMR)) this.aPICs[0].bIRR &= ~(1 << ChipSet.IRQ.SLAVE);
/*
* NOTE: I don't think calling checkIRR(), and by extension, cpu.updateINTR(false), is strictly necessary,
* because when the CPU gets around to acknowledging the INTR signal, it still has to call getIRRVector(),
* which will inform the CPU that there are no longer any requested interrupts.
*
* However, some efficiency may be gained by clearing INTR sooner rather than later, so that's what we'll do.
*/
this.checkIRR();
}
};
/**
* checkIRR(nDelay)
*
* @this {ChipSet}
* @param {number} [nDelay] is an optional number of instructions to delay acknowledgment of a pending interrupt
*/
ChipSet.prototype.checkIRR = function(nDelay)
{
/*
* Look for any IRR bits that aren't masked and aren't already in service; in theory, all we have to
* check is the master PIC (which is the *only* PIC on pre-5170 models), because when any IRQs are set
* or cleared on the slave, that should automatically be reflected in IRQ.SLAVE on the master.
*
* HOWEVER, when a slave interrupt is acknowledged, getIRRVector() ends up clearing the IRR bits for BOTH
* the slave's IRQ and the master's IRQ.SLAVE, setting the corresponding ISR bits, and then when interrupt
* handler send an EOI for both, the corresponding ISR bits are cleared as well.
*
* As a result, if another lower-priority slave IRQ was waiting to be dispatched, that fact would no longer
* be reflected in the master's IRR bit for IRQ.SLAVE. We resolve that problem here, by first checking the
* slave PIC for any unmasked, unserviced interrupts and updating the master's IRR bit for IRQ.SLAVE.
*/
var pic;
var bIR = 0;
if (this.cPICs > 1) {
pic = this.aPICs[1];
bIR = ~(pic.bISR | pic.bIMR) & pic.bIRR;
}
pic = this.aPICs[0];
if (bIR) pic.bIRR |= (1 << ChipSet.IRQ.SLAVE);
bIR = ~(pic.bISR | pic.bIMR) & pic.bIRR;
this.cpu.updateINTR(!!bIR);
if (bIR && nDelay) pic.nDelay = nDelay;
};
/** /**
* getIRRVector() * getIRRVector()
* *
@ -3283,7 +3305,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
var bIRNext = 1 << nIRL; var bIRNext = 1 << nIRL;
if (bIR & bIRNext) { if (bIR & bIRNext) {
if (!iPIC && nIRL == 2) { if (!iPIC && nIRL == ChipSet.IRQ.SLAVE) {
/* /*
* Slave interrupts are tied to the master PIC on IRQ2; query the slave PIC for the vector # * Slave interrupts are tied to the master PIC on IRQ2; query the slave PIC for the vector #
*/ */
@ -3297,15 +3319,20 @@ ChipSet.prototype.getIRRVector = function(iPIC)
if (nIDT >= 0) { if (nIDT >= 0) {
pic.bISR |= bIRNext; pic.bISR |= bIRNext;
pic.bIRR &= ~bIRNext;
}
var nIRQ = pic.nIRQBase + nIRL; /*
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) { * Setting the ISR implies clearing the IRR, but clearIRR() has side-effects we don't want
this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regSP, this.cpu.segSS.sel)); * (eg, clearing the slave IRQ, notifying the CPU, etc), so we clear the IRR ourselves.
} */
if (MAXDEBUG && DEBUGGER) { pic.bIRR &= ~bIRNext;
this.acInterrupts[nIRQ]++;
var nIRQ = pic.nIRQBase + nIRL;
if (DEBUG && this.messageEnabled(this.messageBitsIRQ(nIRQ))) {
this.messageDebugger("getIRRVector(): IRQ " + nIRQ + " interrupting @" + str.toHexAddr(this.cpu.regIP, this.cpu.segCS.sel) + " stack=" + str.toHexAddr(this.cpu.regSP, this.cpu.segSS.sel), true);
}
if (MAXDEBUG && DEBUGGER) {
this.acInterrupts[nIRQ]++;
}
} }
break; break;
} }
@ -3338,7 +3365,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom)
this.updateTimer(iTimer); this.updateTimer(iTimer);
b = timer.countCurrent[timer.countIndex++]; b = timer.countCurrent[timer.countIndex++];
if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) {
this.messagePort(ChipSet.TIMER0.PORT + iTimer, null, addrFrom, "TIMER" + iTimer, 0, b); this.messagePort(ChipSet.TIMER0.PORT + iTimer, null, addrFrom, "TIMER" + iTimer, b, true);
} }
return b; return b;
}; };
@ -3363,7 +3390,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom)
ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom) ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
{ {
if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.TIMER | Debugger.MESSAGE.PORT)) {
this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer); this.messagePort(ChipSet.TIMER0.PORT + iTimer, bOut, addrFrom, "TIMER" + iTimer, null, true);
} }
var timer = this.aTimers[iTimer]; var timer = this.aTimers[iTimer];
if (timer.countIndex == timer.countBytes) this.resetTimerIndex(iTimer); if (timer.countIndex == timer.countBytes) this.resetTimerIndex(iTimer);
@ -3416,7 +3443,7 @@ ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
*/ */
ChipSet.prototype.inTimerCtrl = function(port, addrFrom) ChipSet.prototype.inTimerCtrl = function(port, addrFrom)
{ {
this.messagePort(port, null, addrFrom, "TIMER_CTRL", Debugger.MESSAGE.TIMER); this.messagePort(port, null, addrFrom, "TIMER_CTRL", null, Debugger.MESSAGE.TIMER);
if (DEBUG) this.messageDebugger("TIMER_CTRL: Read-Back command not supported (yet)", Debugger.MESSAGE.TIMER); if (DEBUG) this.messageDebugger("TIMER_CTRL: Read-Back command not supported (yet)", Debugger.MESSAGE.TIMER);
return null; return null;
}; };
@ -3432,7 +3459,7 @@ ChipSet.prototype.inTimerCtrl = function(port, addrFrom)
ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom) ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
{ {
this.bTimerCtrl = bOut; this.bTimerCtrl = bOut;
this.messagePort(port, bOut, addrFrom, "TIMER_CTRL", Debugger.MESSAGE.TIMER); this.messagePort(port, bOut, addrFrom, "TIMER_CTRL", null, Debugger.MESSAGE.TIMER);
/* /*
* Extract the SC (Select Counter) bits * Extract the SC (Select Counter) bits
*/ */
@ -3490,7 +3517,7 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
timer.countStart[1] = timer.countInit[1]; timer.countStart[1] = timer.countInit[1];
timer.nCyclesStart = this.cpu.getCycles(this.fScaleTimers); timer.nCyclesStart = this.cpu.getCycles(this.fScaleTimers);
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("TIMER0 count reset @" + timer.nCyclesStart + " cycles"); this.messageDebugger("TIMER0 count reset @" + timer.nCyclesStart + " cycles", true);
} }
} }
} }
@ -3693,7 +3720,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
if (ticksElapsed < 0) { if (ticksElapsed < 0) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("updateTimer(" + iTimer + "): negative tick count (" + ticksElapsed + ")"); this.messageDebugger("updateTimer(" + iTimer + "): negative tick count (" + ticksElapsed + ")", true);
} }
timer.nCyclesStart = nCycles; timer.nCyclesStart = nCycles;
ticksElapsed = 0; ticksElapsed = 0;
@ -3713,7 +3740,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
if (timer.mode == ChipSet.TIMER_CTRL.MODE0) { if (timer.mode == ChipSet.TIMER_CTRL.MODE0) {
if (count <= 0) count = 0; if (count <= 0) count = 0;
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("updateTimer(" + iTimer + "): MODE0 timer count=" + count); this.messageDebugger("updateTimer(" + iTimer + "): MODE0 timer count=" + count, true);
} }
if (!count) { if (!count) {
timer.fOUT = true; timer.fOUT = true;
@ -3748,7 +3775,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
count = countInit + count; count = countInit + count;
if (count <= 0) { if (count <= 0) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count); this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, true);
} }
count = countInit; count = countInit;
} }
@ -3780,7 +3807,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
count = countInit + count; count = countInit + count;
if (count <= 0) { if (count <= 0) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count); this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, true);
} }
count = countInit; count = countInit;
} }
@ -3844,7 +3871,7 @@ ChipSet.prototype.inPPIA = function(port, addrFrom)
b = this.kbd.readScanCode(); b = this.kbd.readScanCode();
} }
} }
this.messagePort(port, null, addrFrom, "PPI_A", Debugger.MESSAGE.CHIPSET, b); this.messagePort(port, null, addrFrom, "PPI_A", b);
return b; return b;
}; };
@ -3858,7 +3885,7 @@ ChipSet.prototype.inPPIA = function(port, addrFrom)
*/ */
ChipSet.prototype.outPPIA = function(port, bOut, addrFrom) ChipSet.prototype.outPPIA = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "PPI_A", Debugger.MESSAGE.CHIPSET); this.messagePort(port, bOut, addrFrom, "PPI_A");
this.bPPIA = bOut; this.bPPIA = bOut;
}; };
@ -3873,7 +3900,7 @@ ChipSet.prototype.outPPIA = function(port, bOut, addrFrom)
ChipSet.prototype.inPPIB = function(port, addrFrom) ChipSet.prototype.inPPIB = function(port, addrFrom)
{ {
var b = this.bPPIB; var b = this.bPPIB;
this.messagePort(port, null, addrFrom, "PPI_B", Debugger.MESSAGE.CHIPSET, b); this.messagePort(port, null, addrFrom, "PPI_B", b);
return b; return b;
}; };
@ -3887,7 +3914,7 @@ ChipSet.prototype.inPPIB = function(port, addrFrom)
*/ */
ChipSet.prototype.outPPIB = function(port, bOut, addrFrom) ChipSet.prototype.outPPIB = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "PPI_B", Debugger.MESSAGE.CHIPSET); this.messagePort(port, bOut, addrFrom, "PPI_B");
this.updatePPIB(bOut); this.updatePPIB(bOut);
if (this.kbd) this.kbd.setEnable((bOut & ChipSet.PPI_B.CLEAR_KBD)? false : true, (bOut & ChipSet.PPI_B.CLK_KBD)? true : false); if (this.kbd) this.kbd.setEnable((bOut & ChipSet.PPI_B.CLEAR_KBD)? false : true, (bOut & ChipSet.PPI_B.CLK_KBD)? true : false);
}; };
@ -3964,7 +3991,7 @@ ChipSet.prototype.inPPIC = function(port, addrFrom)
* The ROM BIOS polls this port incessantly during its memory tests, checking for memory parity errors * The ROM BIOS polls this port incessantly during its memory tests, checking for memory parity errors
* (which of course we never report), so we further restrict these port messages to MESSAGE_MEM. * (which of course we never report), so we further restrict these port messages to MESSAGE_MEM.
*/ */
this.messagePort(port, null, addrFrom, "PPI_C", Debugger.MESSAGE.CHIPSET | Debugger.MESSAGE.MEM, b); this.messagePort(port, null, addrFrom, "PPI_C", b, Debugger.MESSAGE.CHIPSET | Debugger.MESSAGE.MEM);
return b; return b;
}; };
@ -3978,7 +4005,7 @@ ChipSet.prototype.inPPIC = function(port, addrFrom)
*/ */
ChipSet.prototype.outPPIC = function(port, bOut, addrFrom) ChipSet.prototype.outPPIC = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "PPI_C", Debugger.MESSAGE.CHIPSET); this.messagePort(port, bOut, addrFrom, "PPI_C");
this.bPPIC = bOut; this.bPPIC = bOut;
}; };
@ -3993,7 +4020,7 @@ ChipSet.prototype.outPPIC = function(port, bOut, addrFrom)
ChipSet.prototype.inPPICtrl = function(port, addrFrom) ChipSet.prototype.inPPICtrl = function(port, addrFrom)
{ {
var b = this.bPPICtrl; var b = this.bPPICtrl;
this.messagePort(port, null, addrFrom, "PPI_CTRL", Debugger.MESSAGE.CHIPSET, b); this.messagePort(port, null, addrFrom, "PPI_CTRL", b);
return b; return b;
}; };
@ -4007,7 +4034,7 @@ ChipSet.prototype.inPPICtrl = function(port, addrFrom)
*/ */
ChipSet.prototype.outPPICtrl = function(port, bOut, addrFrom) ChipSet.prototype.outPPICtrl = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "PPI_CTRL", Debugger.MESSAGE.CHIPSET); this.messagePort(port, bOut, addrFrom, "PPI_CTRL");
this.bPPICtrl = bOut; this.bPPICtrl = bOut;
}; };
@ -4022,7 +4049,7 @@ ChipSet.prototype.outPPICtrl = function(port, bOut, addrFrom)
ChipSet.prototype.in8042OutBuff = function(port, addrFrom) ChipSet.prototype.in8042OutBuff = function(port, addrFrom)
{ {
var b = this.b8042OutBuff; var b = this.b8042OutBuff;
this.messagePort(port, null, addrFrom, "8042_OUTBUFF", Debugger.MESSAGE.C8042, b); this.messagePort(port, null, addrFrom, "8042_OUTBUFF", b, Debugger.MESSAGE.C8042);
this.b8042Status &= ~(ChipSet.KBC.STATUS.OUTBUFF_FULL | ChipSet.KBC.STATUS.OUTBUFF_DELAY); this.b8042Status &= ~(ChipSet.KBC.STATUS.OUTBUFF_FULL | ChipSet.KBC.STATUS.OUTBUFF_DELAY);
var bNext = this.kbd && this.kbd.readScanCode(true); var bNext = this.kbd && this.kbd.readScanCode(true);
if (bNext) this.set8042OutBuff(bNext); if (bNext) this.set8042OutBuff(bNext);
@ -4043,7 +4070,7 @@ ChipSet.prototype.in8042OutBuff = function(port, addrFrom)
*/ */
ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom) ChipSet.prototype.out8042InBuffData = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "8042_INBUF.DATA", Debugger.MESSAGE.C8042); this.messagePort(port, bOut, addrFrom, "8042_INBUF.DATA", null, Debugger.MESSAGE.C8042);
if (this.b8042Status & ChipSet.KBC.STATUS.CMD_FLAG) { if (this.b8042Status & ChipSet.KBC.STATUS.CMD_FLAG) {
switch (this.b8042InBuff) { switch (this.b8042InBuff) {
@ -4169,7 +4196,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom)
* Thanks to the WAITF function, this has become a very "busy" port, so let's not generate messages * Thanks to the WAITF function, this has become a very "busy" port, so let's not generate messages
* unless both MESSAGE_8042 *and* MESSAGE_LOG are set. * unless both MESSAGE_8042 *and* MESSAGE_LOG are set.
*/ */
this.messagePort(port, null, addrFrom, "8042_RWREG", Debugger.MESSAGE.C8042, b); this.messagePort(port, null, addrFrom, "8042_RWREG", b, Debugger.MESSAGE.C8042);
return b; return b;
}; };
@ -4183,7 +4210,7 @@ ChipSet.prototype.in8042RWReg = function(port, addrFrom)
*/ */
ChipSet.prototype.out8042RWReg = function(port, bOut, addrFrom) ChipSet.prototype.out8042RWReg = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "8042_RWREG", Debugger.MESSAGE.C8042); this.messagePort(port, bOut, addrFrom, "8042_RWREG", null, Debugger.MESSAGE.C8042);
this.updatePPIB(bOut); this.updatePPIB(bOut);
}; };
@ -4197,7 +4224,7 @@ ChipSet.prototype.out8042RWReg = function(port, bOut, addrFrom)
*/ */
ChipSet.prototype.in8042Status = function(port, addrFrom) ChipSet.prototype.in8042Status = function(port, addrFrom)
{ {
this.messagePort(port, null, addrFrom, "8042_STATUS", Debugger.MESSAGE.C8042, this.b8042Status); this.messagePort(port, null, addrFrom, "8042_STATUS", this.b8042Status, Debugger.MESSAGE.C8042);
var b = this.b8042Status & 0xff; var b = this.b8042Status & 0xff;
/* /*
* There's code in the 5170 BIOS (F000:03BF) that writes an 8042 command (0xAA), waits for * There's code in the 5170 BIOS (F000:03BF) that writes an 8042 command (0xAA), waits for
@ -4235,7 +4262,7 @@ ChipSet.prototype.in8042Status = function(port, addrFrom)
*/ */
ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom) ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "8042_INBUFF.CMD", Debugger.MESSAGE.C8042); this.messagePort(port, bOut, addrFrom, "8042_INBUFF.CMD", null, Debugger.MESSAGE.C8042);
this.assert(!(this.b8042Status & ChipSet.KBC.STATUS.INBUFF_FULL)); this.assert(!(this.b8042Status & ChipSet.KBC.STATUS.INBUFF_FULL));
this.b8042InBuff = bOut; this.b8042InBuff = bOut;
@ -4302,7 +4329,7 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
default: default:
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) {
this.messageDebugger("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff)); this.messageDebugger("unrecognized 8042 command: " + str.toHexByte(this.b8042InBuff), true);
this.dbg.stopCPU(); this.dbg.stopCPU();
} }
break; break;
@ -4379,7 +4406,7 @@ ChipSet.prototype.set8042OutPort = function(b)
* determine if that's what the caller intended. * determine if that's what the caller intended.
*/ */
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.C8042)) {
this.messageDebugger("unexpected 8042 output port reset: " + str.toHexByte(b)); this.messageDebugger("unexpected 8042 output port reset: " + str.toHexByte(b), true);
this.dbg.stopCPU(); this.dbg.stopCPU();
} }
this.cpu.resetRegs(); this.cpu.resetRegs();
@ -4493,7 +4520,7 @@ ChipSet.prototype.notifyKbdData = function(fAvail)
*/ */
ChipSet.prototype.inCMOSAddr = function(port, addrFrom) ChipSet.prototype.inCMOSAddr = function(port, addrFrom)
{ {
this.messagePort(port, null, addrFrom, "CMOS.ADDR", Debugger.MESSAGE.CMOS, this.bCMOSAddr); this.messagePort(port, null, addrFrom, "CMOS.ADDR", this.bCMOSAddr, Debugger.MESSAGE.CMOS);
return this.bCMOSAddr; return this.bCMOSAddr;
}; };
@ -4507,7 +4534,7 @@ ChipSet.prototype.inCMOSAddr = function(port, addrFrom)
*/ */
ChipSet.prototype.outCMOSAddr = function(port, bOut, addrFrom) ChipSet.prototype.outCMOSAddr = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "CMOS.ADDR", Debugger.MESSAGE.CMOS); this.messagePort(port, bOut, addrFrom, "CMOS.ADDR", null, Debugger.MESSAGE.CMOS);
this.bCMOSAddr = bOut; this.bCMOSAddr = bOut;
this.bNMI = (bOut & ChipSet.CMOS.ADDR.NMI_DISABLE)? ChipSet.NMI.DISABLE : ChipSet.NMI.ENABLE; this.bNMI = (bOut & ChipSet.CMOS.ADDR.NMI_DISABLE)? ChipSet.NMI.DISABLE : ChipSet.NMI.ENABLE;
}; };
@ -4525,7 +4552,7 @@ ChipSet.prototype.inCMOSData = function(port, addrFrom)
var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK; var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK;
var bIn = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.getRTCByte(bAddr) : this.abCMOSData[bAddr]); var bIn = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.getRTCByte(bAddr) : this.abCMOSData[bAddr]);
if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) {
this.messagePort(port, null, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", 0, bIn); this.messagePort(port, null, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", bIn, true);
} }
if (addrFrom != null) { if (addrFrom != null) {
if (bAddr == ChipSet.CMOS.ADDR.STATUSC) { if (bAddr == ChipSet.CMOS.ADDR.STATUSC) {
@ -4560,7 +4587,7 @@ ChipSet.prototype.outCMOSData = function(port, bOut, addrFrom)
{ {
var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK; var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK;
if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) { if (this.messageEnabled(Debugger.MESSAGE.CMOS | Debugger.MESSAGE.PORT)) {
this.messagePort(port, bOut, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]"); this.messagePort(port, bOut, addrFrom, "CMOS.DATA[" + str.toHexByte(bAddr) + "]", null, true);
} }
var bDelta = bOut ^ this.abCMOSData[bAddr]; var bDelta = bOut ^ this.abCMOSData[bAddr];
this.abCMOSData[bAddr] = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.setRTCByte(bAddr, bOut) : bOut); this.abCMOSData[bAddr] = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.setRTCByte(bAddr, bOut) : bOut);
@ -4584,7 +4611,7 @@ ChipSet.prototype.outCMOSData = function(port, bOut, addrFrom)
*/ */
ChipSet.prototype.inMFGData = function(port, addrFrom) ChipSet.prototype.inMFGData = function(port, addrFrom)
{ {
this.messagePort(port, null, addrFrom, "MFG_DATA", Debugger.MESSAGE.CHIPSET, this.bMFGData); this.messagePort(port, null, addrFrom, "MFG_DATA", this.bMFGData);
return this.bMFGData; return this.bMFGData;
}; };
@ -4598,7 +4625,7 @@ ChipSet.prototype.inMFGData = function(port, addrFrom)
*/ */
ChipSet.prototype.outMFGData = function(port, bOut, addrFrom) ChipSet.prototype.outMFGData = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "MFG_DATA", Debugger.MESSAGE.CHIPSET); this.messagePort(port, bOut, addrFrom, "MFG_DATA");
this.bMFGData = bOut; this.bMFGData = bOut;
}; };
@ -4614,7 +4641,7 @@ ChipSet.prototype.outMFGData = function(port, bOut, addrFrom)
*/ */
ChipSet.prototype.outNMI = function(port, bOut, addrFrom) ChipSet.prototype.outNMI = function(port, bOut, addrFrom)
{ {
this.messagePort(port, bOut, addrFrom, "NMI", Debugger.MESSAGE.CHIPSET); this.messagePort(port, bOut, addrFrom, "NMI");
this.bNMI = bOut; this.bNMI = bOut;
}; };
@ -4711,17 +4738,13 @@ ChipSet.prototype.setSpeaker = function(fOn)
if (fOn) { if (fOn) {
if (this.sourceAudio) { if (this.sourceAudio) {
this.sourceAudio['frequency']['value'] = freq; this.sourceAudio['frequency']['value'] = freq;
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker set to " + freq + "hz", true);
this.messageDebugger("speaker set to " + freq + "hz");
}
} else { } else {
this.sourceAudio = this.contextAudio['createOscillator'](); this.sourceAudio = this.contextAudio['createOscillator']();
this.sourceAudio['type'] = 1; // 0: sine wave, 1: square wave, 2: sawtooth wave, 3: triangle wave this.sourceAudio['type'] = 1; // 0: sine wave, 1: square wave, 2: sawtooth wave, 3: triangle wave
this.sourceAudio['connect'](this.contextAudio['destination']); this.sourceAudio['connect'](this.contextAudio['destination']);
this.sourceAudio['frequency']['value'] = freq; this.sourceAudio['frequency']['value'] = freq;
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker on at " + freq + "hz", true);
this.messageDebugger("speaker on at " + freq + "hz");
}
this.sourceAudio['noteOn'](0); // aka start() this.sourceAudio['noteOn'](0); // aka start()
} }
} else { } else {
@ -4729,9 +4752,7 @@ ChipSet.prototype.setSpeaker = function(fOn)
this.sourceAudio['noteOff'](0); // aka stop() this.sourceAudio['noteOff'](0); // aka stop()
this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again? this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again?
delete this.sourceAudio; // QUESTION: ditto? delete this.sourceAudio; // QUESTION: ditto?
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) { if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker off at " + freq + "hz", true);
this.messageDebugger("speaker off at " + freq + "hz");
}
} }
} }
} else if (fOn) { } else if (fOn) {
@ -4767,12 +4788,20 @@ ChipSet.prototype.messageBitsDMA = function(iChannel)
ChipSet.prototype.messageBitsIRQ = function(nIRQ) ChipSet.prototype.messageBitsIRQ = function(nIRQ)
{ {
var bitsMessage = Debugger.MESSAGE.PIC; var bitsMessage = Debugger.MESSAGE.PIC;
if (nIRQ == ChipSet.IRQ.TIMER0) { if (nIRQ == ChipSet.IRQ.TIMER0) { // IRQ 0
bitsMessage |= Debugger.MESSAGE.TIMER; bitsMessage |= Debugger.MESSAGE.TIMER;
} else if (nIRQ == ChipSet.IRQ.KBD) { } else if (nIRQ == ChipSet.IRQ.KBD) { // IRQ 1
bitsMessage |= Debugger.MESSAGE.KBD; bitsMessage |= Debugger.MESSAGE.KBD;
} else if (nIRQ == ChipSet.IRQ.FDC) { } else if (nIRQ == ChipSet.IRQ.SLAVE) { // IRQ 2 (MODEL_5170 and up)
bitsMessage |= Debugger.MESSAGE.CHIPSET;
} else if (nIRQ == ChipSet.IRQ.XTC) { // IRQ 5 (MODEL_5160)
bitsMessage |= Debugger.MESSAGE.HDC;
} else if (nIRQ == ChipSet.IRQ.FDC) { // IRQ 6
bitsMessage |= Debugger.MESSAGE.FDC; bitsMessage |= Debugger.MESSAGE.FDC;
} else if (nIRQ == ChipSet.IRQ.RTC) { // IRQ 8 (MODEL_5170 and up)
bitsMessage |= Debugger.MESSAGE.RTC;
} else if (nIRQ == ChipSet.IRQ.ATC) { // IRQ 14 (MODEL_5170 and up)
bitsMessage |= Debugger.MESSAGE.HDC;
} }
return bitsMessage; return bitsMessage;
}; };

View file

@ -1656,7 +1656,7 @@ if (DEBUGGER) {
* at the moment. If that changes, then this will have to change as well. * at the moment. If that changes, then this will have to change as well.
*/ */
addr -= 2; addr -= 2;
this.message("INT 0x" + str.toHexByte(nInt) + ": AH=" + str.toHexByte(AH) + " at " + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel) + sFunc); this.message("INT 0x" + str.toHexByte(nInt) + ": AH=" + str.toHexByte(AH) + " @" + str.toHexAddr(addr - this.cpu.segCS.base, this.cpu.segCS.sel) + sFunc);
} }
return fMessage; return fMessage;
}; };
@ -1684,12 +1684,11 @@ if (DEBUGGER) {
* @param {number|null} bOut if an output operation * @param {number|null} bOut if an output operation
* @param {number|null} [addrFrom] * @param {number|null} [addrFrom]
* @param {string|null} [name] of the port, if any * @param {string|null} [name] of the port, if any
* @param {number} [bIn] is the input value, if known, on an input operation * @param {number|null} [bIn] is the input value, if known, on an input operation
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) * @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s)
*/ */
Debugger.prototype.messageIO = function(component, port, bOut, addrFrom, name, bIn, bitsMessage) Debugger.prototype.messageIO = function(component, port, bOut, addrFrom, name, bIn, bitsMessage)
{ {
if (!bitsMessage) bitsMessage = 0;
bitsMessage |= Debugger.MESSAGE.PORT; bitsMessage |= Debugger.MESSAGE.PORT;
if (addrFrom == null || (this.bitsMessage & bitsMessage) == bitsMessage) { if (addrFrom == null || (this.bitsMessage & bitsMessage) == bitsMessage) {
var segFrom = null; var segFrom = null;
@ -1697,7 +1696,7 @@ if (DEBUGGER) {
segFrom = this.cpu.segCS.sel; segFrom = this.cpu.segCS.sel;
addrFrom -= this.cpu.segCS.base; addrFrom -= this.cpu.segCS.base;
} }
this.message(component.idComponent + "." + (bOut != null? "outPort" : "inPort") + "(0x" + str.toHexWord(port) + "," + (name? name : "unknown") + (bOut != null? ",0x" + str.toHexByte(bOut) : "") + ")" + (bIn != null? (": 0x" + str.toHexByte(bIn)) : "") + (addrFrom != null? (" at " + str.toHexAddr(addrFrom, segFrom)) : "")); this.message(component.idComponent + "." + (bOut != null? "outPort" : "inPort") + "(0x" + str.toHexWord(port) + "," + (name? name : "unknown") + (bOut != null? ",0x" + str.toHexByte(bOut) : "") + ")" + (bIn != null? (": 0x" + str.toHexByte(bIn)) : "") + (addrFrom != null? (" @" + str.toHexAddr(addrFrom, segFrom)) : ""));
} }
}; };
@ -4078,7 +4077,7 @@ if (DEBUGGER) {
* "biggest" being that the large disk images really need to be compressed first, because they * "biggest" being that the large disk images really need to be compressed first, because they
* get "inflated" with use. See the dump() method in the Disk component for more details. * get "inflated" with use. See the dump() method in the Disk component for more details.
*/ */
this.println(drive.disk.dump()); this.println(drive.disk.toJSON());
return; return;
} }
if (dc.seekDrive(drive, iSector, nSectors)) { if (dc.seekDrive(drive, iSector, nSectors)) {
@ -4539,6 +4538,10 @@ if (DEBUGGER) {
this.incAddr(aAddr, 1); this.incAddr(aAddr, 1);
fRepeat = fPrefix = true; fRepeat = fPrefix = true;
break; break;
case X86.OPCODE.INSB:
case X86.OPCODE.INSW:
case X86.OPCODE.OUTSB:
case X86.OPCODE.OUTSW:
case X86.OPCODE.MOVSB: case X86.OPCODE.MOVSB:
case X86.OPCODE.MOVSW: case X86.OPCODE.MOVSW:
case X86.OPCODE.CMPSB: case X86.OPCODE.CMPSB:

View file

@ -36,12 +36,12 @@
* 1) creating an empty disk: create() * 1) creating an empty disk: create()
* 2) loading a disk image: load() * 2) loading a disk image: load()
* 3) getting disk information: info() * 3) getting disk information: info()
* 4) dumping disk contents: dump() * 4) seeking a disk sector: seek()
* 5) seeking a disk sector: seek() * 5) reading data from a sector: read()
* 6) reading data from a sector: read() * 6) writing data to a sector: write()
* 7) writing data to a sector: write() * 7) save disk deltas: save()
* 8) save disk deltas: save() * 8) restore disk deltas: restore()
* 9) restore disk deltas: restore() * 9) converting disk contents: toJSON()
* *
* More functionality may be factored out of the FDC and HDC components later and moved here, to * More functionality may be factored out of the FDC and HDC components later and moved here, to
* further reduce some of the duplication between them, but the above functionality is a good start. * further reduce some of the duplication between them, but the above functionality is a good start.
@ -1236,39 +1236,6 @@ Disk.prototype.info = function()
return [this.aDiskData.length, this.aDiskData[0].length, this.aDiskData[0][0].length, this.aDiskData[0][0][0]['length']]; return [this.aDiskData.length, this.aDiskData[0].length, this.aDiskData[0][0].length, this.aDiskData[0][0][0]['length']];
}; };
/**
* dump()
*
* We perform some RegExp massaging on the JSON data to eliminate unnecessary properties
* (eg, 'length' values of 512, 'pattern' values of 0, quotes around the property names, etc).
* Sectors that were initially compressed should remain compressed unless/until they were modified.
*
* TODO: Check sectors (or at least modified sectors) to see if they can be recompressed.
*
* @this {Disk}
* @return {string} containing the entire disk image as JSON-encoded data
*/
Disk.prototype.dump = function()
{
var s = JSON.stringify(this.aDiskData);
s = s.replace(/,"length":512/gm, "").replace(/,"pattern":0/gm, "");
/*
* I don't really want to strip quotes from disk image property names, since I would have to put them
* back again during mount() -- or whenever JSON.parse() is used instead of eval(). But I still remove
* them temporarily, so that any remaining property names (eg, "iModify", "cModify", "fDirty") can
* easily be stripped out, by virtue of their being the only quoted properties left. We then "requote"
* all the property names that remain.
*/
s = s.replace(/"(sector|length|data|pattern)":/gm, "$1:");
/*
* The next line will remove any other numeric or boolean properties that were added at runtime, although
* they may have completely different ("minified") names if the code has been compiled.
*/
s = s.replace(/,"[^"]*":([0-9]+|true|false)/gm, "");
s = s.replace(/(sector|length|data|pattern):/gm, "\"$1\":");
return s;
};
/** /**
* seek(iCylinder, iHead, iSector, fWrite, done) * seek(iCylinder, iHead, iSector, fWrite, done)
* *
@ -1653,6 +1620,74 @@ Disk.prototype.restore = function(deltas)
return nChanges; return nChanges;
}; };
/**
* toJSON()
*
* We perform some RegExp massaging on the JSON data to eliminate unnecessary properties
* (eg, 'length' values of 512, 'pattern' values of 0, quotes around the property names, etc).
* Sectors that were initially compressed should remain compressed unless/until they were modified.
*
* TODO: Check sectors (or at least modified sectors) to see if they can be recompressed.
*
* @this {Disk}
* @return {string} containing the entire disk image as JSON-encoded data
*/
Disk.prototype.toJSON = function()
{
var s = JSON.stringify(this.aDiskData);
s = s.replace(/,"length":512/gm, "").replace(/,"pattern":0/gm, "");
/*
* I don't really want to strip quotes from disk image property names, since I would have to put them
* back again during mount() -- or whenever JSON.parse() is used instead of eval(). But I still remove
* them temporarily, so that any remaining property names (eg, "iModify", "cModify", "fDirty") can
* easily be stripped out, by virtue of their being the only quoted properties left. We then "requote"
* all the property names that remain.
*/
s = s.replace(/"(sector|length|data|pattern)":/gm, "$1:");
/*
* The next line will remove any other numeric or boolean properties that were added at runtime, although
* they may have completely different ("minified") names if the code has been compiled.
*/
s = s.replace(/,"[^"]*":([0-9]+|true|false)/gm, "");
s = s.replace(/(sector|length|data|pattern):/gm, "\"$1\":");
return s;
};
/**
* dumpSector(sector)
*
* @param {Object} sector (returned from a previous seek)
* @return {string|undefined}
*/
Disk.prototype.dumpSector = function(sector)
{
var sDump;
if (DEBUG) {
sDump = "";
var sBytes = "", sChars = "";
var cbSector = sector['length'];
var cdwData = sector['data'].length;
var dw = 0;
for (var i = 0; i < cbSector; i++) {
if (i % 16 == 0) {
if (sDump) sDump += sBytes + ' ' + sChars + '\n';
sDump += str.toHexWord(i) + ": ";
sBytes = sChars = "";
}
if (i % 4 == 0) {
var idw = i >> 2;
dw = (idw < cdwData? sector['data'][idw] : sector['pattern']);
}
var b = dw & 0xff;
dw >>>= 8;
sBytes += str.toHexByte(b) + (i % 16 == 7? "-" : " ");
sChars += (b >= 32 && b < 128? String.fromCharCode(b) : ".");
}
if (sBytes) sDump += sBytes + ' ' + sChars + '\n';
}
return sDump;
};
if (typeof APP_PCJS !== 'undefined') APP_PCJS.Disk = Disk; if (typeof APP_PCJS !== 'undefined') APP_PCJS.Disk = Disk;
if (typeof module !== 'undefined') module.exports = Disk; if (typeof module !== 'undefined') module.exports = Disk;

View file

@ -2026,10 +2026,10 @@ FDC.prototype.popCmd = function(name)
{ {
this.assert((!this.regDataIndex || name !== undefined) && this.regDataIndex < this.regDataTotal); this.assert((!this.regDataIndex || name !== undefined) && this.regDataIndex < this.regDataTotal);
var bCmd = this.regDataArray[this.regDataIndex]; var bCmd = this.regDataArray[this.regDataIndex];
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.FDC)) {
var bCmdMasked = bCmd & FDC.REG_DATA.CMD.MASK; var bCmdMasked = bCmd & FDC.REG_DATA.CMD.MASK;
if (!name && !this.regDataIndex && FDC.aCmdInfo[bCmdMasked]) name = FDC.aCmdInfo[bCmdMasked].name; if (!name && !this.regDataIndex && FDC.aCmdInfo[bCmdMasked]) name = FDC.aCmdInfo[bCmdMasked].name;
this.messageDebugger("FDC.CMD[" + (name || this.regDataIndex) + "]: 0x" + str.toHexByte(bCmd)); this.messageDebugger("FDC.CMD[" + (name || this.regDataIndex) + "]: 0x" + str.toHexByte(bCmd), true);
} }
this.regDataIndex++; this.regDataIndex++;
return bCmd; return bCmd;
@ -2080,8 +2080,8 @@ FDC.prototype.beginResult = function()
*/ */
FDC.prototype.pushResult = function(bResult, name) FDC.prototype.pushResult = function(bResult, name)
{ {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.FDC)) {
this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult)); this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult), true);
} }
this.regDataArray[this.regDataTotal++] = bResult; this.regDataArray[this.regDataTotal++] = bResult;
}; };

View file

@ -891,7 +891,7 @@ HDC.prototype.initDrive = function(iDrive, drive, driveConfig, data, fHard)
this.verifyDrive(drive); this.verifyDrive(drive);
/* /*
* The next group of properties are managed by worker functions (eg, doRead()) to maintain state across DMA requests. * The next group of properties are managed by worker functions (eg, doDMARead()) to maintain state across DMA requests.
*/ */
drive.ibSector = data[i++]; // location of the next byte to be accessed in the above sector drive.ibSector = data[i++]; // location of the next byte to be accessed in the above sector
drive.sector = null; // initialized to null by worker, and then set to the next sector satisfying the request drive.sector = null; // initialized to null by worker, and then set to the next sector satisfying the request
@ -1082,7 +1082,7 @@ HDC.prototype.seekDrive = function(drive, iSector, nSectors)
drive.errorCode = HDC.XTC.DATA.ERR.NONE; drive.errorCode = HDC.XTC.DATA.ERR.NONE;
/* /*
* At this point, we've finished simulating what an HDC.XTC.DATA.CMD.READ_DATA command would have performed, * At this point, we've finished simulating what an HDC.XTC.DATA.CMD.READ_DATA command would have performed,
* up through doRead(). Now it's the caller responsibility to call readByte(), like the DMA Controller would. * up through doDMARead(). Now it's the caller responsibility to call readByte(), like the DMA Controller would.
*/ */
return true; return true;
} }
@ -1261,7 +1261,7 @@ HDC.prototype.outXTCData = function(port, bOut, addrFrom)
*/ */
this.regStatus |= HDC.XTC.STATUS.IOMODE; this.regStatus |= HDC.XTC.STATUS.IOMODE;
this.regStatus &= ~HDC.XTC.STATUS.REQ; this.regStatus &= ~HDC.XTC.STATUS.REQ;
this.doXTCommand(); this.doXTC();
} }
}; };
@ -1386,14 +1386,8 @@ HDC.prototype.outXTCNoise = function(port, bOut, addrFrom)
HDC.prototype.inATCData = function(port, addrFrom) HDC.prototype.inATCData = function(port, addrFrom)
{ {
var bIn = -1; var bIn = -1;
var fSuppress = false;
if (this.drive) { if (this.drive) {
/*
* messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte.
*/
fSuppress = (this.drive.ibSector > 0);
/* /*
* We use the synchronous form of readByte() at this point because we have no choice; an I/O instruction * We use the synchronous form of readByte() at this point because we have no choice; an I/O instruction
* has just occurred and cannot be delayed. The good news is that doATCommand() should have already primed * has just occurred and cannot be delayed. The good news is that doATCommand() should have already primed
@ -1407,7 +1401,22 @@ HDC.prototype.inATCData = function(port, addrFrom)
* Now that we've supplied a full sector of data, see if the caller's expecting additional sectors; * Now that we've supplied a full sector of data, see if the caller's expecting additional sectors;
* if so, prime the pump again. The caller should not poll us again until another interrupt's been delivered. * if so, prime the pump again. The caller should not poll us again until another interrupt's been delivered.
*/ */
if (this.drive.ibSector == this.drive.cbSector) { if (this.drive.ibSector == 1) {
/*
* messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte
* of each sector.
*/
if (this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) {
this.messagePort(port, null, addrFrom, "DATA[" + this.drive.ibSector + "]", bIn);
}
}
else if (this.drive.ibSector == this.drive.cbSector) {
if (this.messageEnabled(Debugger.MESSAGE.OTHER | Debugger.MESSAGE.HDC)) {
var sDump = this.drive.disk.dumpSector(this.drive.sector);
if (sDump) this.dbg.message(sDump);
}
this.drive.nBytes -= this.drive.cbSector; this.drive.nBytes -= this.drive.cbSector;
this.regSecCnt = (this.regSecCnt - 1) & 0xff; this.regSecCnt = (this.regSecCnt - 1) & 0xff;
/* /*
@ -1416,13 +1425,11 @@ HDC.prototype.inATCData = function(port, addrFrom)
*/ */
if (this.drive.nBytes >= this.drive.cbSector) { if (this.drive.nBytes >= this.drive.cbSector) {
var hdc = this; var hdc = this;
hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
this.readByte(this.drive, function(b, fAsync) { this.readByte(this.drive, function(b, fAsync) {
if (b >= 0) { if (b >= 0) {
hdc.setATCIRR(); hdc.setATCIRR();
/* hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
* I shouldn't have to set BUSY (or DATA_REQ) again, because it should still be set, no?
*/
hdc.assert(!!(hdc.regStatus & HDC.ATC.STATUS.BUSY));
} else { } else {
/* /*
* TODO: It would be nice to be a bit more specific about the error (if any) that just occurred. * TODO: It would be nice to be a bit more specific about the error (if any) that just occurred.
@ -1439,7 +1446,6 @@ HDC.prototype.inATCData = function(port, addrFrom)
} }
} }
} }
if (!fSuppress) this.messagePort(port, null, addrFrom, "DATA", bIn);
return bIn; return bIn;
}; };
@ -1453,11 +1459,6 @@ HDC.prototype.inATCData = function(port, addrFrom)
*/ */
HDC.prototype.outATCData = function(port, bOut, addrFrom) HDC.prototype.outATCData = function(port, bOut, addrFrom)
{ {
/*
* messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte.
*/
if (!this.drive || !this.drive.ibSector) this.messagePort(port, bOut, addrFrom, "DATA");
if (this.drive) { if (this.drive) {
if (this.drive.nBytes >= this.drive.cbSector) { if (this.drive.nBytes >= this.drive.cbSector) {
if (this.writeByte(this.drive, bOut) < 0) { if (this.writeByte(this.drive, bOut) < 0) {
@ -1471,18 +1472,30 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom)
this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write failed"); this.messageDebugger("HDC.outATCData(" + str.toHexByte(bOut) + "): write failed");
} }
} }
else if (this.drive.ibSector == 1) {
/*
* messagePort() calls, if enabled, can be overwhelming for this port, so limit them to the first byte
* of each sector.
*/
if (this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) {
this.messagePort(port, bOut, addrFrom, "DATA[" + this.drive.ibSector + "]");
}
}
else if (this.drive.ibSector == this.drive.cbSector) { else if (this.drive.ibSector == this.drive.cbSector) {
if (this.messageEnabled(Debugger.MESSAGE.OTHER | Debugger.MESSAGE.HDC)) {
var sDump = this.drive.disk.dumpSector(this.drive.sector);
if (sDump) this.dbg.message(sDump);
}
this.drive.nBytes -= this.drive.cbSector; this.drive.nBytes -= this.drive.cbSector;
this.regSecCnt = (this.regSecCnt - 1) & 0xff; this.regSecCnt = (this.regSecCnt - 1) & 0xff;
this.setATCIRR(); this.setATCIRR(true);
this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
if (this.drive.nBytes >= this.drive.cbSector) { if (this.drive.nBytes >= this.drive.cbSector) {
/* this.regStatus |= HDC.ATC.STATUS.DATA_REQ;
* I shouldn't have to set BUSY (or DATA_REQ) again, because it should still be set, no?
*/
this.assert(!!(this.regStatus & HDC.ATC.STATUS.BUSY));
} else { } else {
this.assert(!this.drive.nBytes); this.assert(!this.drive.nBytes);
this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
} }
} }
} else { } else {
@ -1710,6 +1723,7 @@ HDC.prototype.inATCStatus = function(port, addrFrom)
{ {
var bIn = this.regStatus; var bIn = this.regStatus;
this.messagePort(port, null, addrFrom, "STATUS", bIn); this.messagePort(port, null, addrFrom, "STATUS", bIn);
if (this.chipset) this.chipset.clearIRR(ChipSet.IRQ.ATC);
return bIn; return bIn;
}; };
@ -1726,7 +1740,7 @@ HDC.prototype.outATCCommand = function(port, bOut, addrFrom)
this.messagePort(port, bOut, addrFrom, "COMMAND"); this.messagePort(port, bOut, addrFrom, "COMMAND");
this.regCommand = bOut; this.regCommand = bOut;
if (this.chipset) this.chipset.clearIRR(ChipSet.IRQ.ATC); if (this.chipset) this.chipset.clearIRR(ChipSet.IRQ.ATC);
this.doATCommand(); this.doATC();
}; };
/** /**
@ -1752,13 +1766,13 @@ HDC.prototype.outATCFDR = function(port, bOut, addrFrom)
}; };
/** /**
* doATCommand() * doATC()
* *
* Handles ATC (AT Controller) commands * Handles ATC (AT Controller) commands
* *
* @this {HDC} * @this {HDC}
*/ */
HDC.prototype.doATCommand = function() HDC.prototype.doATC = function()
{ {
var hdc = this; var hdc = this;
var fInterrupt = false; var fInterrupt = false;
@ -1790,35 +1804,40 @@ HDC.prototype.doATCommand = function()
* follow-up I/O instructions. For example, any subsequent inATCData() and outATCData() calls need to * follow-up I/O instructions. For example, any subsequent inATCData() and outATCData() calls need to
* know which drive to talk to ("this.drive"), to issue their own readByte() and writeByte() calls. * know which drive to talk to ("this.drive"), to issue their own readByte() and writeByte() calls.
* *
* The XTC didn't need this, because it used doRead(), doWrite(), doFormat() helper functions, which * The XTC didn't need this, because it used doDMARead(), doDMAWrite(), doDMAFormat() helper functions,
* reset the current drive's "sector" and "errorCode" properties themselves and then used DMA functions * which reset the current drive's "sector" and "errorCode" properties themselves and then used DMA
* that delivered drive data with direct calls to readByte() and writeByte(). * functions that delivered drive data with direct calls to readByte() and writeByte().
*/ */
drive.sector = null; drive.sector = null;
drive.ibSector = 0;
drive.errorCode = 0; drive.errorCode = 0;
this.drive = drive; this.drive = drive;
} }
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.doATCommand(" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd]); this.messageDebugger("HDC.doATC(0x" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd], true);
} }
switch (bCmd & HDC.ATC.COMMAND.MASK) { switch (bCmd & HDC.ATC.COMMAND.MASK) {
case HDC.ATC.COMMAND.READ_DATA: case HDC.ATC.COMMAND.READ_DATA:
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.doRead(" + iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + nSectors + ")", true);
}
/* /*
* We're using a call to readByte() that disables auto-increment, so that once we've got the first * We're using a call to readByte() that disables auto-increment, so that once we've got the first
* byte of the next sector, we can signal an interrupt without also consuming the first byte, allowing * byte of the next sector, we can signal an interrupt without also consuming the first byte, allowing
* inATCData() to begin with that byte. * inATCData() to begin with that byte.
*
* As with the WRITE_DATA command, I'm not sure which of BUSY and DATA_REQ (or both) should be set here,
* so I'm setting both of them for now. I clear them as soon as I have data.
*/ */
hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
this.readByte(drive, function(b, fAsync) { this.readByte(drive, function(b, fAsync) {
if (b >= 0 && hdc.chipset) { if (b >= 0 && hdc.chipset) {
hdc.setATCIRR(); hdc.setATCIRR();
/* hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
* As with the WRITE_DATA command, I'm not sure which of BUSY and DATA_REQ (or both)
* should be set here, so I'm setting both of them for now.
*/
hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
} else { } else {
/* /*
* TODO: It would be nice to be a bit more specific about the error (if any) that just occurred. * TODO: It would be nice to be a bit more specific about the error (if any) that just occurred.
@ -1831,17 +1850,10 @@ HDC.prototype.doATCommand = function()
break; break;
case HDC.ATC.COMMAND.WRITE_DATA: case HDC.ATC.COMMAND.WRITE_DATA:
if (this.chipset) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) {
this.setATCIRR(); this.messageDebugger("HDC.doWrite(" + iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + nSectors + ")", true);
/*
* I know that DATA_REQ must be set at this point, but I'm not sure about BUSY; so I'm
* setting both of them for now.
*/
this.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
} else {
this.regStatus = HDC.ATC.STATUS.ERROR;
this.regError = HDC.ATC.ERROR.CMD_ABORT;
} }
this.regStatus = HDC.ATC.STATUS.DATA_REQ;
break; break;
case HDC.ATC.COMMAND.RESTORE: case HDC.ATC.COMMAND.RESTORE:
@ -1853,7 +1865,8 @@ HDC.prototype.doATCommand = function()
case HDC.ATC.COMMAND.READ_VERF: case HDC.ATC.COMMAND.READ_VERF:
/* /*
* Since the READ VERIFY command returns no data, once again, logically, there isn't much for us to do. * Since the READ VERIFY command returns no data, once again, logically, there isn't much we HAVE to
* to do, but... TODO: Verify that all the disk parameters are valid, and return an error if they're not.
*/ */
fInterrupt = true; fInterrupt = true;
break; break;
@ -1871,8 +1884,8 @@ HDC.prototype.doATCommand = function()
* *
* WPREC: 0x4B * WPREC: 0x4B
* SECCNT: 0x11 (for 17 sectors per track) * SECCNT: 0x11 (for 17 sectors per track)
* CYL: 0x100 (256 -- uh, what?) * CYL: 0x100 (256 -- huh?)
* SECNUM: 0x0C (12 -- uh, what?) * SECNUM: 0x0C (12 -- huh?)
* DRVHD: 0xA3 (max head of 0x03, for 4 total heads) * DRVHD: 0xA3 (max head of 0x03, for 4 total heads)
* *
* The importance of SECCNT (nSectors) and DRVHD (nHeads) is controlling how multi-sector operations * The importance of SECCNT (nSectors) and DRVHD (nHeads) is controlling how multi-sector operations
@ -1887,7 +1900,7 @@ HDC.prototype.doATCommand = function()
default: default:
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled()) {
this.messageDebugger("HDC.doATCommand(" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); this.messageDebugger("HDC.doATC(0x" + str.toHexByte(this.regCommand) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation"));
if (bCmd >= 0) this.dbg.stopCPU(); if (bCmd >= 0) this.dbg.stopCPU();
} }
break; break;
@ -1897,25 +1910,33 @@ HDC.prototype.doATCommand = function()
}; };
/** /**
* setATCIRR() * setATCIRR(fWrite)
* *
* Raise the ATC's IRQ, provided ATC interrupts are enabled. * Raise the ATC's IRQ, provided ATC interrupts are enabled.
* *
* @this {HDC} * @this {HDC}
* @param {boolean} [fWrite] is true on completion of a write to the sector buffer
*/ */
HDC.prototype.setATCIRR = function() HDC.prototype.setATCIRR = function(fWrite)
{ {
if (this.chipset && !(this.regFDR & HDC.ATC.FDR.INT_DISABLE)) this.chipset.setIRR(ChipSet.IRQ.ATC); if (this.chipset) {
if (!(this.regFDR & HDC.ATC.FDR.INT_DISABLE)) {
this.chipset.setIRR(ChipSet.IRQ.ATC);
if (DEBUG) this.messageDebugger("HDC.setATCIRR(): enabled", Debugger.MESSAGE.PIC | Debugger.MESSAGE.HDC);
} else {
if (DEBUG) this.messageDebugger("HDC.setATCIRR(): disabled", Debugger.MESSAGE.PIC | Debugger.MESSAGE.HDC);
}
}
}; };
/** /**
* doXTCommand() * doXTC()
* *
* Handles XTC (XT Controller) commands * Handles XTC (XT Controller) commands
* *
* @this {HDC} * @this {HDC}
*/ */
HDC.prototype.doXTCommand = function() HDC.prototype.doXTC = function()
{ {
var hdc = this; var hdc = this;
this.regDataIndex = 0; this.regDataIndex = 0;
@ -1985,7 +2006,7 @@ HDC.prototype.doXTCommand = function()
bDataStatus = HDC.XTC.DATA.STATUS_OK; bDataStatus = HDC.XTC.DATA.STATUS_OK;
if (!drive && this.iDriveAllowFail == iDrive) { if (!drive && this.iDriveAllowFail == iDrive) {
this.iDriveAllowFail = -1; this.iDriveAllowFail = -1;
if (DEBUG) this.messageDebugger("HDC.doXTCommand(): fake failure triggered"); if (DEBUG) this.messageDebugger("HDC.doXTC(): fake failure triggered");
bDataStatus = HDC.XTC.DATA.STATUS_ERROR; bDataStatus = HDC.XTC.DATA.STATUS_ERROR;
} }
this.beginResult(bDataStatus | bDrive); this.beginResult(bDataStatus | bDrive);
@ -2022,7 +2043,7 @@ HDC.prototype.doXTCommand = function()
case HDC.XTC.DATA.CMD.RECALIBRATE: // 0x01 case HDC.XTC.DATA.CMD.RECALIBRATE: // 0x01
drive.bControl = bControl; drive.bControl = bControl;
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled()) {
this.messageDebugger("HDC.doXTCommand(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl)); this.messageDebugger("HDC.doXTC(): drive " + iDrive + " control byte: 0x" + str.toHexByte(bControl));
} }
this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive); this.beginResult(HDC.XTC.DATA.STATUS_OK | bDrive);
break; break;
@ -2035,7 +2056,7 @@ HDC.prototype.doXTCommand = function()
break; break;
case HDC.XTC.DATA.CMD.READ_DATA: // 0x08 case HDC.XTC.DATA.CMD.READ_DATA: // 0x08
this.doRead(drive, function(bStatus) { this.doDMARead(drive, function(bStatus) {
hdc.beginResult(bStatus | bDrive); hdc.beginResult(bStatus | bDrive);
}); });
break; break;
@ -2046,13 +2067,13 @@ HDC.prototype.doXTCommand = function()
* but it is omitted from the HDC.XTC.DATA.CMD.READ_DATA command. Is that correct? Note that, as far as the length * but it is omitted from the HDC.XTC.DATA.CMD.READ_DATA command. Is that correct? Note that, as far as the length
* of the transfer is concerned, we rely exclusively on the DMA controller being programmed with the appropriate byte count. * of the transfer is concerned, we rely exclusively on the DMA controller being programmed with the appropriate byte count.
*/ */
this.doWrite(drive, function(bStatus) { this.doDMAWrite(drive, function(bStatus) {
hdc.beginResult(bStatus | bDrive); hdc.beginResult(bStatus | bDrive);
}); });
break; break;
case HDC.XTC.DATA.CMD.WRITE_BUFFER: // 0x0F case HDC.XTC.DATA.CMD.WRITE_BUFFER: // 0x0F
this.doWriteToBuffer(drive, function(bStatus) { this.doDMAWriteBuffer(drive, function(bStatus) {
hdc.beginResult(bStatus | bDrive); hdc.beginResult(bStatus | bDrive);
}); });
break; break;
@ -2060,7 +2081,7 @@ HDC.prototype.doXTCommand = function()
default: default:
this.beginResult(HDC.XTC.DATA.STATUS_ERROR | bDrive); this.beginResult(HDC.XTC.DATA.STATUS_ERROR | bDrive);
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled()) {
this.messageDebugger("HDC.doXTCommand(" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation")); this.messageDebugger("HDC.doXTC(0x" + str.toHexByte(bCmdOrig) + "): " + (bCmd < 0? ("invalid drive (" + iDrive + ")") : "unsupported operation"));
if (bCmd >= 0) this.dbg.stopCPU(); if (bCmd >= 0) this.dbg.stopCPU();
} }
break; break;
@ -2081,7 +2102,7 @@ HDC.prototype.popCmd = function()
if (bCmdIndex < this.regDataTotal) { if (bCmdIndex < this.regDataTotal) {
bCmd = this.regDataArray[this.regDataIndex++]; bCmd = this.regDataArray[this.regDataIndex++];
if (DEBUG && this.messageEnabled((bCmdIndex > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) { if (DEBUG && this.messageEnabled((bCmdIndex > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.CMD[" + bCmdIndex + "]: 0x" + str.toHexByte(bCmd) + (!bCmdIndex && HDC.aXTCCommands[bCmd]? (" (" + HDC.aXTCCommands[bCmd] + ")") : "")); this.messageDebugger("HDC.CMD[" + bCmdIndex + "]: 0x" + str.toHexByte(bCmd) + (!bCmdIndex && HDC.aXTCCommands[bCmd]? (" (" + HDC.aXTCCommands[bCmd] + ")") : ""), true);
} }
} }
return bCmd; return bCmd;
@ -2121,7 +2142,7 @@ HDC.prototype.beginResult = function(bResult)
HDC.prototype.pushResult = function(bResult) HDC.prototype.pushResult = function(bResult)
{ {
if (DEBUG && this.messageEnabled((this.regDataTotal > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) { if (DEBUG && this.messageEnabled((this.regDataTotal > 0? Debugger.MESSAGE.PORT : 0) | Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.RES[" + this.regDataTotal + "]: 0x" + str.toHexByte(bResult)); this.messageDebugger("HDC.RES[" + this.regDataTotal + "]: 0x" + str.toHexByte(bResult), true);
} }
this.regDataArray[this.regDataTotal++] = bResult; this.regDataArray[this.regDataTotal++] = bResult;
}; };
@ -2205,18 +2226,18 @@ HDC.prototype.dmaWriteFormat = function(drive, b)
}; };
/** /**
* doRead(drive, done) * doDMARead(drive, done)
* *
* @this {HDC} * @this {HDC}
* @param {Object} drive * @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
*/ */
HDC.prototype.doRead = function(drive, done) HDC.prototype.doDMARead = function(drive, done)
{ {
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled()) {
this.messageDebugger("HDC.doRead(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); this.messageDebugger("HDC.doDMARead(" + drive.iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + ((drive.nBytes / drive.cbSector)|0) + ")");
} }
if (drive.disk) { if (drive.disk) {
@ -2249,18 +2270,18 @@ HDC.prototype.doRead = function(drive, done)
}; };
/** /**
* doWrite(drive, done) * doDMAWrite(drive, done)
* *
* @this {HDC} * @this {HDC}
* @param {Object} drive * @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
*/ */
HDC.prototype.doWrite = function(drive, done) HDC.prototype.doDMAWrite = function(drive, done)
{ {
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled()) {
this.messageDebugger("HDC.doWrite(" + drive.wCylinder + ":" + drive.bHead + ":" + drive.bSector + ")"); this.messageDebugger("HDC.doDMAWrite(" + drive.iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + ((drive.nBytes / drive.cbSector)|0) + ")");
} }
if (drive.disk) { if (drive.disk) {
@ -2300,17 +2321,17 @@ HDC.prototype.doWrite = function(drive, done)
}; };
/** /**
* doWriteToBuffer(drive, done) * doDMAWriteBuffer(drive, done)
* *
* @this {HDC} * @this {HDC}
* @param {Object} drive * @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
*/ */
HDC.prototype.doWriteToBuffer = function(drive, done) HDC.prototype.doDMAWriteBuffer = function(drive, done)
{ {
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
if (DEBUG) this.messageDebugger("HDC.doWriteToBuffer()"); if (DEBUG) this.messageDebugger("HDC.doDMAWriteBuffer()");
if (!drive.abSector || drive.abSector.length != drive.nBytes) { if (!drive.abSector || drive.abSector.length != drive.nBytes) {
drive.abSector = new Array(drive.nBytes); drive.abSector = new Array(drive.nBytes);
@ -2343,9 +2364,9 @@ HDC.prototype.doWriteToBuffer = function(drive, done)
}; };
/** /**
* doFormat(drive, done) * doDMAFormat(drive, done)
* *
* The drive variable is initialized by doXTCommand() to the following extent: * The drive variable is initialized by doXTC() to the following extent:
* *
* drive.bHead (ignored) * drive.bHead (ignored)
* drive.nBytes (bytes/sector) * drive.nBytes (bytes/sector)
@ -2358,7 +2379,7 @@ HDC.prototype.doWriteToBuffer = function(drive, done)
* @param {Object} drive * @param {Object} drive
* @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well) * @param {function(number)} done (dataStatus is XTC.DATA.STATUS_OK or XTC.DATA.STATUS_ERROR; if error, then drive.errorCode should be set as well)
*/ */
HDC.prototype.doFormat = function(drive, done) HDC.prototype.doDMAFormat = function(drive, done)
{ {
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY; drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;

View file

@ -967,7 +967,7 @@ Keyboard.prototype.resetDevice = function()
/* /*
* TODO: There's more to reset, like LED indicators, default type rate, and emptying the scan code buffer. * TODO: There's more to reset, like LED indicators, default type rate, and emptying the scan code buffer.
*/ */
this.messageDebugger("keyboard reset", Debugger.MESSAGE.PORT); this.messageDebugger("keyboard reset", Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT);
this.abScanBuffer = [Keyboard.CMDRES.BAT_SUCC]; this.abScanBuffer = [Keyboard.CMDRES.BAT_SUCC];
if (this.chipset) this.chipset.notifyKbdData(true); if (this.chipset) this.chipset.notifyKbdData(true);
}; };
@ -989,8 +989,8 @@ Keyboard.prototype.setEnable = function(fData, fClock)
{ {
var fReset = false; var fReset = false;
if (this.fClock !== fClock) { if (this.fClock !== fClock) {
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT)) {
this.messageDebugger("keyboard clock line changing to " + fClock, Debugger.MESSAGE.PORT); this.messageDebugger("keyboard clock line changing to " + fClock, true);
} }
/* /*
* Toggling the clock line low and then high signals a "reset", which we acknowledge once the * Toggling the clock line low and then high signals a "reset", which we acknowledge once the
@ -999,8 +999,8 @@ Keyboard.prototype.setEnable = function(fData, fClock)
this.fClock = this.fResetOnEnable = fClock; this.fClock = this.fResetOnEnable = fClock;
} }
if (this.fData !== fData) { if (this.fData !== fData) {
if (DEBUG && this.messageEnabled()) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT)) {
this.messageDebugger("keyboard data line changing to " + fData, Debugger.MESSAGE.PORT); this.messageDebugger("keyboard data line changing to " + fData, true);
} }
this.fData = fData; this.fData = fData;
/* /*
@ -1637,7 +1637,7 @@ Keyboard.prototype.keyUpDown = function(event, fDown)
} }
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) {
this.messageDebugger(/*(fDown?"\n":"") +*/ "key" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "pass" : "consume")); this.messageDebugger(/*(fDown?"\n":"") +*/ "key" + (fDown? "Down" : "Up") + "(" + keyCode + "): " + (fPass? "pass" : "consume"), true);
} }
return fPass; return fPass;
}; };
@ -1687,7 +1687,7 @@ Keyboard.prototype.keyPress = function(event)
} }
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) {
this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume")); this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume"), true);
} }
return fPass; return fPass;
}; };
@ -1749,7 +1749,7 @@ Keyboard.prototype.keySimulatePress = function(keyCode, fCheckShift, fQuickRelea
fSimulated = true; fSimulated = true;
} }
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) {
this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false")); this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false"), true);
} }
return fSimulated; return fSimulated;
}; };
@ -1836,7 +1836,7 @@ Keyboard.prototype.keySimulateUpOrDown = function(keyCode, fDown, simCode)
fSimulated = true; fSimulated = true;
} }
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) { if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) {
this.messageDebugger("keySimulateUpOrDown(" + keyCode + "," + (fDown? "down" : "up") + "," + Keyboard.aSimCodeDescs[simCode] + "): " + (fSimulated? "true" : "false")); this.messageDebugger("keySimulateUpOrDown(" + keyCode + "," + (fDown? "down" : "up") + "," + Keyboard.aSimCodeDescs[simCode] + "): " + (fSimulated? "true" : "false"), true);
} }
return fSimulated; return fSimulated;
}; };

View file

@ -43,16 +43,6 @@ if (typeof module !== 'undefined') {
var Debugger = require("./debugger"); var Debugger = require("./debugger");
} }
/**
* @class Font
* @property {number} cxCell
* @property {number} cyCell
* @property {Array} aCSSColors
* @property {Array} aRGBColors
* @property {Array} aColorMap
* @property {Array} aCanvas
*/
/** /**
* Video(parmsVideo, canvas, context, textarea) * Video(parmsVideo, canvas, context, textarea)
* *
@ -171,14 +161,13 @@ function Video(parmsVideo, canvas, context, textarea)
* Originally, setMode() would map/unmap the video buffer ONLY when the active card changed, * Originally, setMode() would map/unmap the video buffer ONLY when the active card changed,
* because as long as an MDA or CGA remained active, its video buffer never changed. However, * because as long as an MDA or CGA remained active, its video buffer never changed. However,
* since the EGA can change its video buffer on the fly, setMode() must also compare the card's * since the EGA can change its video buffer on the fly, setMode() must also compare the card's
* hard-coded and/or programmed) buffer address/size to the "active" address/size; the latter * hard-coded and/or programmed buffer address/size to the "active" address/size; the latter
* is recorded here. * is recorded here.
*/ */
this.addrBuffer = this.sizeBuffer = 0; this.addrBuffer = this.sizeBuffer = 0;
/* /*
* aFonts is an array of font objects (ie, arrays) indexed by FONT ID. Font characters are * aFonts is an array of font objects indexed by FONT ID. Font characters are * arranged in 16x16 grids, with one grid per canvas object in the aCanvas array of each font object.
* arranged in 16x16 grids, with one grid per canvas object in the aCanvas array of each font object.
* *
* Each element is a Font object that describes the font size and provides bitmaps for all the font * Each element is a Font object that describes the font size and provides bitmaps for all the font
* color permutations. aFonts.length will be non-zero if ANY fonts are loaded, but do NOT assume * color permutations. aFonts.length will be non-zero if ANY fonts are loaded, but do NOT assume
@ -495,6 +484,16 @@ Video.MODES.EGA_640X350_MONO = 0x0F; // mapped at A000:0000, monochrome
Video.MODES.EGA_640X350 = 0x10; // mapped at A000:0000, color Video.MODES.EGA_640X350 = 0x10; // mapped at A000:0000, color
Video.MODES.UNKNOWN = 0xFF; Video.MODES.UNKNOWN = 0xFF;
/**
* @class Font
* @property {number} cxCell
* @property {number} cyCell
* @property {Array} aCSSColors
* @property {Array} aRGBColors
* @property {Array} aColorMap
* @property {Array} aCanvas
*/
/* /*
* Supported Fonts * Supported Fonts
* *

View file

@ -2516,13 +2516,13 @@ X86CPU.prototype.stepCPU = function(nMinCycles)
this.opPrefixes = this.opFlags & X86.OPFLAG.REPEAT; this.opPrefixes = this.opFlags & X86.OPFLAG.REPEAT;
if (this.intFlags) { if (this.intFlags) {
if (this.checkINTR()) { if (this.checkINTR()) {
/* if (!nMinCycles) {
* ASSERT: If it's never possible to have !nMinCycles WITHOUT the Debugger, then all we need this.assert(DEBUGGER); // nMinCycles of zero should be generated ONLY by the Debugger
* to check is !nMinCycles. if (DEBUGGER) {
*/ this.println("interrupt dispatched");
if (DEBUGGER && !nMinCycles) { this.opFlags = 0;
this.opFlags = 0; break;
break; }
} }
} }
if (this.intFlags & X86.INTFLAG.HALT) { if (this.intFlags & X86.INTFLAG.HALT) {

View file

@ -691,7 +691,7 @@ var X86Help = {
if (this.messageEnabled(bitsMessage) || fHalt) { if (this.messageEnabled(bitsMessage) || fHalt) {
var sMessage = (fHalt? '\n' : '') + "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")"; var sMessage = (fHalt? '\n' : '') + "Fault " + str.toHexByte(nFault) + (nError != null? " (" + str.toHexWord(nError) + ")" : "") + " on opcode 0x" + str.toHexByte(bOpcode) + " at " + str.toHexAddr(this.regIP, this.segCS.sel) + " (%" + str.toHex(this.regEIP, 6) + ")";
var fRunning = this.bitField.fRunning; var fRunning = this.bitField.fRunning;
if (this.messageDebugger(sMessage)) { if (this.messageDebugger(sMessage, bitsMessage)) {
if (fHalt) { if (fHalt) {
/* /*
* By setting fHalt to fRunning (which is true while running but false while single-stepping), * By setting fHalt to fRunning (which is true while running but false while single-stepping),

View file

@ -933,20 +933,20 @@ Component.prototype = {
return true; return true;
}, },
/** /**
* messageEnabled(bitsMessage, fOnly) * messageEnabled(bitsMessage)
*
* If bitsMessage is not specified, the component's MESSAGE category is used.
* *
* @this {Component} * @this {Component}
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) * @param {number} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s)
* @return {boolean} true if all specified message enabled, false if not * @return {boolean} true if all specified message enabled, false if not
*/ */
messageEnabled: function(bitsMessage) { messageEnabled: function(bitsMessage) {
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
if (this === this.dbg) { if (this === this.dbg) {
bitsMessage = bitsMessage || 0; bitsMessage |= 0;
} else { } else {
if (!bitsMessage) { bitsMessage = bitsMessage || this.bitsMessage;
bitsMessage = this.bitsMessage;
}
} }
var bitsEnabled = this.dbg.bitsMessage & bitsMessage; var bitsEnabled = this.dbg.bitsMessage & bitsMessage;
return (bitsEnabled === bitsMessage || !!(bitsEnabled & this.dbg.bitsWarning)); return (bitsEnabled === bitsMessage || !!(bitsEnabled & this.dbg.bitsWarning));
@ -956,15 +956,18 @@ Component.prototype = {
/** /**
* messageDebugger(sMessage, bitsMessage, fAddress) * messageDebugger(sMessage, bitsMessage, fAddress)
* *
* If bitsMessage is not specified, the component's MESSAGE category is used.
* If bitsMessage is true, the message is displayed regardless.
*
* @this {Component} * @this {Component}
* @param {string} sMessage is any caller-defined message string * @param {string} sMessage is any caller-defined message string
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) * @param {number|boolean} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s)
* @param {boolean} [fAddress] is true to display the current address * @param {boolean} [fAddress] is true to display the current address
* @return {boolean} true if Debugger available, false if not * @return {boolean} true if Debugger available, false if not
*/ */
messageDebugger: function(sMessage, bitsMessage, fAddress) { messageDebugger: function(sMessage, bitsMessage, fAddress) {
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
if (bitsMessage == null || this.messageEnabled(bitsMessage)) { if (bitsMessage === true || this.messageEnabled(bitsMessage | 0)) {
this.dbg.message(sMessage, fAddress); this.dbg.message(sMessage, fAddress);
} }
return true; return true;
@ -974,19 +977,25 @@ Component.prototype = {
/** /**
* messagePort(port, bOut, addrFrom, name, bIn, bitsMessage) * messagePort(port, bOut, addrFrom, name, bIn, bitsMessage)
* *
* This is an internal version of the Debugger's messagePort() function, for convenience. * If bitsMessage is not specified, the component's MESSAGE category is used.
* If bitsMessage is true, the message is displayed as long as MESSAGE.PORT is enabled.
* *
* @this {Component} * @this {Component}
* @param {number} port * @param {number} port
* @param {number|null} bOut if an output operation * @param {number|null} bOut if an output operation
* @param {number|null} [addrFrom] * @param {number|null} [addrFrom]
* @param {string|null} [name] of the port, if any * @param {string|null} [name] of the port, if any
* @param {number} [bIn] is the input value, if known, on an input operation * @param {number|null} [bIn] is the input value, if known, on an input operation
* @param {number} [bitsMessage] is one or more Debugger MESSAGE_* category flag(s) * @param {number|boolean} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s)
*/ */
messagePort: function(port, bOut, addrFrom, name, bIn, bitsMessage) { messagePort: function(port, bOut, addrFrom, name, bIn, bitsMessage) {
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
this.dbg.messageIO(this, port, bOut, addrFrom, name, bIn, bitsMessage || this.bitsMessage); if (bitsMessage === true) {
bitsMessage = 0;
} else if (bitsMessage == null) {
bitsMessage = this.bitsMessage;
}
this.dbg.messageIO(this, port, bOut, addrFrom, name, bIn, bitsMessage);
} }
} }
}; };