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:0505 @ COMMANDO
F000:055C @ COMMAND
F000:055C @ WAIT
F000:05C2 @ WAIT
F000:05F3 @ NOT_BUSY
F000:061A @ WAIT_DRQ
F000:0630 @ CHECK_STATUS

View file

@ -503,16 +503,16 @@ ChipSet.PIC_HI = { // ChipSet.PIC1.PORT_HI or ChipSet.PIC2.PORT_HI
ChipSet.IRQ = {
TIMER0: 0x00,
KBD: 0x01,
SLAVE: 0x02,
SLAVE: 0x02, // MODEL_5170
COM2: 0x03,
COM1: 0x04,
XTC: 0x05, // MODEL_5160 uses IRQ 5 for HDC (XTC version)
LPT2: 0x05, // MODEL_5170 uses IRQ 5 for LPT2
FDC: 0x06,
LPT1: 0x07,
RTC: 0x08,
IRQ2: 0x09,
COPROC: 0x0D,
RTC: 0x08, // MODEL_5170
IRQ2: 0x09, // MODEL_5170
COPROC: 0x0D, // MODEL_5170
ATC: 0x0E // MODEL_5170 uses IRQ 14 for HDC (ATC version)
};
@ -1332,17 +1332,17 @@ ChipSet.prototype.getRTCCycleLimit = function(nCycles)
if (nCyclesUpdate > 0) {
if (nCycles > nCyclesUpdate) {
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;
} else {
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 {
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 b = channel.addrCurrent[controller.bIndex];
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;
/*
@ -2326,7 +2326,7 @@ ChipSet.prototype.outDMAChannelAddr = function outDMAChannelAddr(iDMAC, iChannel
{
var controller = this.aDMACs[iDMAC];
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];
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 b = channel.countCurrent[controller.bIndex];
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;
/*
@ -2390,7 +2390,7 @@ ChipSet.prototype.outDMAChannelCount = function(iDMAC, iChannel, port, bOut, add
{
var controller = this.aDMACs[iDMAC];
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];
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;
controller.bStatus &= ~ChipSet.DMA_STATUS.ALL_TC;
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;
};
@ -2450,7 +2450,7 @@ ChipSet.prototype.inDMAStatus = function(iDMAC, port, addrFrom)
ChipSet.prototype.outDMACmd = function(iDMAC, port, bOut, addrFrom)
{
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;
};
@ -2478,7 +2478,7 @@ ChipSet.prototype.outDMAReq = function(iDMAC, port, bOut, addrFrom)
{
var controller = this.aDMACs[iDMAC];
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
@ -2505,7 +2505,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
{
var controller = this.aDMACs[iDMAC];
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 channel = controller.aChannels[iChannel];
@ -2525,7 +2525,7 @@ ChipSet.prototype.outDMAMask = function(iDMAC, port, bOut, addrFrom)
ChipSet.prototype.outDMAMode = function(iDMAC, port, bOut, addrFrom)
{
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;
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)
{
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;
};
@ -2563,7 +2563,7 @@ ChipSet.prototype.outDMAResetFF = function(iDMAC, port, bOut, addrFrom)
ChipSet.prototype.outDMAMasterClear = function(iDMAC, port, bOut, addrFrom)
{
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
@ -2590,7 +2590,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom)
{
var bIn = this.aDMACs[iDMAC].aChannels[iChannel].bPage;
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;
};
@ -2608,7 +2608,7 @@ ChipSet.prototype.inDMAPageReg = function(iDMAC, iChannel, port, addrFrom)
ChipSet.prototype.outDMAPageReg = function(iDMAC, iChannel, port, bOut, addrFrom)
{
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;
};
@ -2626,7 +2626,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom)
{
var bIn = this.abDMAPageSpare[iSpare];
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;
};
@ -2643,7 +2643,7 @@ ChipSet.prototype.inDMAPageSpare = function(iSpare, port, addrFrom)
ChipSet.prototype.outDMAPageSpare = function(iSpare, port, bOut, addrFrom)
{
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;
};
@ -2713,7 +2713,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
if (!channel.component || !channel.fnTransfer || !channel.obj) {
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);
return;
@ -2730,7 +2730,7 @@ ChipSet.prototype.requestDMA = function(iDMAChannel, done)
if (channel.masked) {
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;
}
@ -2783,7 +2783,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (DEBUG && DEBUGGER && channel.sAddrDebug === null) {
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) {
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));
}
}
@ -2794,7 +2794,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
if (b < 0) {
if (!channel.fWarning) {
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;
}
@ -2843,7 +2843,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit)
}
else {
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;
}
@ -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) {
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));
}
@ -2938,8 +2938,8 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
break;
}
}
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) {
this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, 0, b);
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port, null, addrFrom, "PIC" + iPIC, b, true);
}
return b;
};
@ -2955,8 +2955,8 @@ ChipSet.prototype.inPICLo = function(iPIC, addrFrom)
ChipSet.prototype.outPICLo = function(iPIC, bOut, addrFrom)
{
var pic = this.aPICs[iPIC];
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) {
this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC);
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port, bOut, addrFrom, "PIC" + iPIC, null, true);
}
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);
if (pic.bISR & bIREnd) {
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;
this.checkIRR(iPIC);
this.checkIRR();
} else {
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();
}
}
@ -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)
*/
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();
}
}
@ -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
*/
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();
}
}
@ -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 (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;
@ -3101,8 +3101,8 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
{
var pic = this.aPICs[iPIC];
var b = pic.bIMR;
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) {
this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, 0, b);
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port+1, null, addrFrom, "PIC" + iPIC, b, true);
}
return b;
};
@ -3118,8 +3118,8 @@ ChipSet.prototype.inPICHi = function(iPIC, addrFrom)
ChipSet.prototype.outPICHi = function(iPIC, bOut, addrFrom)
{
var pic = this.aPICs[iPIC];
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT)) {
this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC);
if (this.messageEnabled(Debugger.MESSAGE.PIC | Debugger.MESSAGE.PORT | Debugger.MESSAGE.CHIPSET)) {
this.messagePort(pic.port+1, bOut, addrFrom, "PIC" + iPIC, null, true);
}
if (pic.nICW < pic.aICW.length) {
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
* 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);
}
};
/**
* 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);
this.checkIRR(!iPIC && bOut == 0xFD? 6 : 0);
}
};
@ -3235,6 +3162,101 @@ ChipSet.prototype.checkIMR = function(nIRQ)
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()
*
@ -3283,7 +3305,7 @@ ChipSet.prototype.getIRRVector = function(iPIC)
var bIRNext = 1 << nIRL;
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 #
*/
@ -3297,15 +3319,20 @@ ChipSet.prototype.getIRRVector = function(iPIC)
if (nIDT >= 0) {
pic.bISR |= bIRNext;
pic.bIRR &= ~bIRNext;
}
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));
}
if (MAXDEBUG && DEBUGGER) {
this.acInterrupts[nIRQ]++;
/*
* Setting the ISR implies clearing the IRR, but clearIRR() has side-effects we don't want
* (eg, clearing the slave IRQ, notifying the CPU, etc), so we clear the IRR ourselves.
*/
pic.bIRR &= ~bIRNext;
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;
}
@ -3338,7 +3365,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom)
this.updateTimer(iTimer);
b = timer.countCurrent[timer.countIndex++];
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;
};
@ -3363,7 +3390,7 @@ ChipSet.prototype.inTimer = function(iTimer, addrFrom)
ChipSet.prototype.outTimer = function(iTimer, bOut, addrFrom)
{
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];
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)
{
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);
return null;
};
@ -3432,7 +3459,7 @@ ChipSet.prototype.inTimerCtrl = function(port, addrFrom)
ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
{
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
*/
@ -3490,7 +3517,7 @@ ChipSet.prototype.outTimerCtrl = function(port, bOut, addrFrom)
timer.countStart[1] = timer.countInit[1];
timer.nCyclesStart = this.cpu.getCycles(this.fScaleTimers);
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 (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;
ticksElapsed = 0;
@ -3713,7 +3740,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
if (timer.mode == ChipSet.TIMER_CTRL.MODE0) {
if (count <= 0) count = 0;
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) {
timer.fOUT = true;
@ -3748,7 +3775,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
count = countInit + count;
if (count <= 0) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count);
this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, true);
}
count = countInit;
}
@ -3780,7 +3807,7 @@ ChipSet.prototype.updateTimer = function(iTimer, fCycleReset)
count = countInit + count;
if (count <= 0) {
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.TIMER)) {
this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count);
this.messageDebugger("updateTimer(" + iTimer + "): underflow=" + count, true);
}
count = countInit;
}
@ -3844,7 +3871,7 @@ ChipSet.prototype.inPPIA = function(port, addrFrom)
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;
};
@ -3858,7 +3885,7 @@ ChipSet.prototype.inPPIA = function(port, 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;
};
@ -3873,7 +3900,7 @@ ChipSet.prototype.outPPIA = function(port, bOut, addrFrom)
ChipSet.prototype.inPPIB = function(port, addrFrom)
{
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;
};
@ -3887,7 +3914,7 @@ ChipSet.prototype.inPPIB = function(port, 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);
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
* (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;
};
@ -3978,7 +4005,7 @@ ChipSet.prototype.inPPIC = function(port, 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;
};
@ -3993,7 +4020,7 @@ ChipSet.prototype.outPPIC = function(port, bOut, addrFrom)
ChipSet.prototype.inPPICtrl = function(port, addrFrom)
{
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;
};
@ -4007,7 +4034,7 @@ ChipSet.prototype.inPPICtrl = function(port, 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;
};
@ -4022,7 +4049,7 @@ ChipSet.prototype.outPPICtrl = function(port, bOut, addrFrom)
ChipSet.prototype.in8042OutBuff = function(port, addrFrom)
{
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);
var bNext = this.kbd && this.kbd.readScanCode(true);
if (bNext) this.set8042OutBuff(bNext);
@ -4043,7 +4070,7 @@ ChipSet.prototype.in8042OutBuff = function(port, 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) {
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
* 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;
};
@ -4183,7 +4210,7 @@ ChipSet.prototype.in8042RWReg = function(port, 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);
};
@ -4197,7 +4224,7 @@ ChipSet.prototype.out8042RWReg = function(port, bOut, 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;
/*
* 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)
{
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.b8042InBuff = bOut;
@ -4302,7 +4329,7 @@ ChipSet.prototype.out8042InBuffCmd = function(port, bOut, addrFrom)
default:
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();
}
break;
@ -4379,7 +4406,7 @@ ChipSet.prototype.set8042OutPort = function(b)
* determine if that's what the caller intended.
*/
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.cpu.resetRegs();
@ -4493,7 +4520,7 @@ ChipSet.prototype.notifyKbdData = function(fAvail)
*/
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;
};
@ -4507,7 +4534,7 @@ ChipSet.prototype.inCMOSAddr = function(port, 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.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 bIn = (bAddr <= ChipSet.CMOS.ADDR.STATUSD? this.getRTCByte(bAddr) : this.abCMOSData[bAddr]);
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 (bAddr == ChipSet.CMOS.ADDR.STATUSC) {
@ -4560,7 +4587,7 @@ ChipSet.prototype.outCMOSData = function(port, bOut, addrFrom)
{
var bAddr = this.bCMOSAddr & ChipSet.CMOS.ADDR.MASK;
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];
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)
{
this.messagePort(port, null, addrFrom, "MFG_DATA", Debugger.MESSAGE.CHIPSET, this.bMFGData);
this.messagePort(port, null, addrFrom, "MFG_DATA", this.bMFGData);
return this.bMFGData;
};
@ -4598,7 +4625,7 @@ ChipSet.prototype.inMFGData = function(port, 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;
};
@ -4614,7 +4641,7 @@ ChipSet.prototype.outMFGData = 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;
};
@ -4711,17 +4738,13 @@ ChipSet.prototype.setSpeaker = function(fOn)
if (fOn) {
if (this.sourceAudio) {
this.sourceAudio['frequency']['value'] = freq;
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) {
this.messageDebugger("speaker set to " + freq + "hz");
}
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker set to " + freq + "hz", true);
} else {
this.sourceAudio = this.contextAudio['createOscillator']();
this.sourceAudio['type'] = 1; // 0: sine wave, 1: square wave, 2: sawtooth wave, 3: triangle wave
this.sourceAudio['connect'](this.contextAudio['destination']);
this.sourceAudio['frequency']['value'] = freq;
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) {
this.messageDebugger("speaker on at " + freq + "hz");
}
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker on at " + freq + "hz", true);
this.sourceAudio['noteOn'](0); // aka start()
}
} else {
@ -4729,9 +4752,7 @@ ChipSet.prototype.setSpeaker = function(fOn)
this.sourceAudio['noteOff'](0); // aka stop()
this.sourceAudio['disconnect'](); // QUESTION: is this automatic following a stop(), since this particular source cannot be started again?
delete this.sourceAudio; // QUESTION: ditto?
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) {
this.messageDebugger("speaker off at " + freq + "hz");
}
if (this.messageEnabled(Debugger.MESSAGE.SPEAKER)) this.messageDebugger("speaker off at " + freq + "hz", true);
}
}
} else if (fOn) {
@ -4767,12 +4788,20 @@ ChipSet.prototype.messageBitsDMA = function(iChannel)
ChipSet.prototype.messageBitsIRQ = function(nIRQ)
{
var bitsMessage = Debugger.MESSAGE.PIC;
if (nIRQ == ChipSet.IRQ.TIMER0) {
if (nIRQ == ChipSet.IRQ.TIMER0) { // IRQ 0
bitsMessage |= Debugger.MESSAGE.TIMER;
} else if (nIRQ == ChipSet.IRQ.KBD) {
} else if (nIRQ == ChipSet.IRQ.KBD) { // IRQ 1
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;
} 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;
};

View file

@ -1656,7 +1656,7 @@ if (DEBUGGER) {
* at the moment. If that changes, then this will have to change as well.
*/
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;
};
@ -1684,12 +1684,11 @@ if (DEBUGGER) {
* @param {number|null} bOut if an output operation
* @param {number|null} [addrFrom]
* @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)
*/
Debugger.prototype.messageIO = function(component, port, bOut, addrFrom, name, bIn, bitsMessage)
{
if (!bitsMessage) bitsMessage = 0;
bitsMessage |= Debugger.MESSAGE.PORT;
if (addrFrom == null || (this.bitsMessage & bitsMessage) == bitsMessage) {
var segFrom = null;
@ -1697,7 +1696,7 @@ if (DEBUGGER) {
segFrom = this.cpu.segCS.sel;
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
* 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;
}
if (dc.seekDrive(drive, iSector, nSectors)) {
@ -4539,6 +4538,10 @@ if (DEBUGGER) {
this.incAddr(aAddr, 1);
fRepeat = fPrefix = true;
break;
case X86.OPCODE.INSB:
case X86.OPCODE.INSW:
case X86.OPCODE.OUTSB:
case X86.OPCODE.OUTSW:
case X86.OPCODE.MOVSB:
case X86.OPCODE.MOVSW:
case X86.OPCODE.CMPSB:

View file

@ -36,12 +36,12 @@
* 1) creating an empty disk: create()
* 2) loading a disk image: load()
* 3) getting disk information: info()
* 4) dumping disk contents: dump()
* 5) seeking a disk sector: seek()
* 6) reading data from a sector: read()
* 7) writing data to a sector: write()
* 8) save disk deltas: save()
* 9) restore disk deltas: restore()
* 4) seeking a disk sector: seek()
* 5) reading data from a sector: read()
* 6) writing data to a sector: write()
* 7) save disk deltas: save()
* 8) 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
* 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']];
};
/**
* 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)
*
@ -1653,6 +1620,74 @@ Disk.prototype.restore = function(deltas)
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 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);
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;
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++;
return bCmd;
@ -2080,8 +2080,8 @@ FDC.prototype.beginResult = function()
*/
FDC.prototype.pushResult = function(bResult, name)
{
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT)) {
this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult));
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.FDC)) {
this.messageDebugger("FDC.RES[" + (name || this.regDataTotal) + "]: 0x" + str.toHexByte(bResult), true);
}
this.regDataArray[this.regDataTotal++] = bResult;
};

View file

@ -891,7 +891,7 @@ HDC.prototype.initDrive = function(iDrive, drive, driveConfig, data, fHard)
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.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;
/*
* 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;
}
@ -1261,7 +1261,7 @@ HDC.prototype.outXTCData = function(port, bOut, addrFrom)
*/
this.regStatus |= HDC.XTC.STATUS.IOMODE;
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)
{
var bIn = -1;
var fSuppress = false;
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
* 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;
* 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.regSecCnt = (this.regSecCnt - 1) & 0xff;
/*
@ -1416,13 +1425,11 @@ HDC.prototype.inATCData = function(port, addrFrom)
*/
if (this.drive.nBytes >= this.drive.cbSector) {
var hdc = this;
hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
this.readByte(this.drive, function(b, fAsync) {
if (b >= 0) {
hdc.setATCIRR();
/*
* 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));
hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
} else {
/*
* 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;
};
@ -1453,11 +1459,6 @@ HDC.prototype.inATCData = function(port, 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.nBytes >= this.drive.cbSector) {
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");
}
}
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) {
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.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) {
/*
* 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));
this.regStatus |= HDC.ATC.STATUS.DATA_REQ;
} else {
this.assert(!this.drive.nBytes);
this.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
}
}
} else {
@ -1710,6 +1723,7 @@ HDC.prototype.inATCStatus = function(port, addrFrom)
{
var bIn = this.regStatus;
this.messagePort(port, null, addrFrom, "STATUS", bIn);
if (this.chipset) this.chipset.clearIRR(ChipSet.IRQ.ATC);
return bIn;
};
@ -1726,7 +1740,7 @@ HDC.prototype.outATCCommand = function(port, bOut, addrFrom)
this.messagePort(port, bOut, addrFrom, "COMMAND");
this.regCommand = bOut;
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
*
* @this {HDC}
*/
HDC.prototype.doATCommand = function()
HDC.prototype.doATC = function()
{
var hdc = this;
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
* 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
* reset the current drive's "sector" and "errorCode" properties themselves and then used DMA functions
* that delivered drive data with direct calls to readByte() and writeByte().
* The XTC didn't need this, because it used doDMARead(), doDMAWrite(), doDMAFormat() helper functions,
* which reset the current drive's "sector" and "errorCode" properties themselves and then used DMA
* functions that delivered drive data with direct calls to readByte() and writeByte().
*/
drive.sector = null;
drive.ibSector = 0;
drive.errorCode = 0;
this.drive = drive;
}
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.PORT | Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.doATCommand(" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd]);
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.doATC(0x" + str.toHexByte(bCmd) + "): " + HDC.aATCCommands[bCmd], true);
}
switch (bCmd & HDC.ATC.COMMAND.MASK) {
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
* byte of the next sector, we can signal an interrupt without also consuming the first byte, allowing
* 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) {
if (b >= 0 && hdc.chipset) {
hdc.setATCIRR();
/*
* 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;
hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
} else {
/*
* 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;
case HDC.ATC.COMMAND.WRITE_DATA:
if (this.chipset) {
this.setATCIRR();
/*
* 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;
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.HDC)) {
this.messageDebugger("HDC.doWrite(" + iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + nSectors + ")", true);
}
this.regStatus = HDC.ATC.STATUS.DATA_REQ;
break;
case HDC.ATC.COMMAND.RESTORE:
@ -1853,7 +1865,8 @@ HDC.prototype.doATCommand = function()
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;
break;
@ -1871,8 +1884,8 @@ HDC.prototype.doATCommand = function()
*
* WPREC: 0x4B
* SECCNT: 0x11 (for 17 sectors per track)
* CYL: 0x100 (256 -- uh, what?)
* SECNUM: 0x0C (12 -- uh, what?)
* CYL: 0x100 (256 -- huh?)
* SECNUM: 0x0C (12 -- huh?)
* DRVHD: 0xA3 (max head of 0x03, for 4 total heads)
*
* The importance of SECCNT (nSectors) and DRVHD (nHeads) is controlling how multi-sector operations
@ -1887,7 +1900,7 @@ HDC.prototype.doATCommand = function()
default:
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();
}
break;
@ -1897,25 +1910,33 @@ HDC.prototype.doATCommand = function()
};
/**
* setATCIRR()
* setATCIRR(fWrite)
*
* Raise the ATC's IRQ, provided ATC interrupts are enabled.
*
* @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
*
* @this {HDC}
*/
HDC.prototype.doXTCommand = function()
HDC.prototype.doXTC = function()
{
var hdc = this;
this.regDataIndex = 0;
@ -1985,7 +2006,7 @@ HDC.prototype.doXTCommand = function()
bDataStatus = HDC.XTC.DATA.STATUS_OK;
if (!drive && this.iDriveAllowFail == iDrive) {
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;
}
this.beginResult(bDataStatus | bDrive);
@ -2022,7 +2043,7 @@ HDC.prototype.doXTCommand = function()
case HDC.XTC.DATA.CMD.RECALIBRATE: // 0x01
drive.bControl = bControl;
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);
break;
@ -2035,7 +2056,7 @@ HDC.prototype.doXTCommand = function()
break;
case HDC.XTC.DATA.CMD.READ_DATA: // 0x08
this.doRead(drive, function(bStatus) {
this.doDMARead(drive, function(bStatus) {
hdc.beginResult(bStatus | bDrive);
});
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
* 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);
});
break;
case HDC.XTC.DATA.CMD.WRITE_BUFFER: // 0x0F
this.doWriteToBuffer(drive, function(bStatus) {
this.doDMAWriteBuffer(drive, function(bStatus) {
hdc.beginResult(bStatus | bDrive);
});
break;
@ -2060,7 +2081,7 @@ HDC.prototype.doXTCommand = function()
default:
this.beginResult(HDC.XTC.DATA.STATUS_ERROR | bDrive);
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();
}
break;
@ -2081,7 +2102,7 @@ HDC.prototype.popCmd = function()
if (bCmdIndex < this.regDataTotal) {
bCmd = this.regDataArray[this.regDataIndex++];
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;
@ -2121,7 +2142,7 @@ HDC.prototype.beginResult = function(bResult)
HDC.prototype.pushResult = function(bResult)
{
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;
};
@ -2205,18 +2226,18 @@ HDC.prototype.dmaWriteFormat = function(drive, b)
};
/**
* doRead(drive, done)
* doDMARead(drive, done)
*
* @this {HDC}
* @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)
*/
HDC.prototype.doRead = function(drive, done)
HDC.prototype.doDMARead = function(drive, done)
{
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
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) {
@ -2249,18 +2270,18 @@ HDC.prototype.doRead = function(drive, done)
};
/**
* doWrite(drive, done)
* doDMAWrite(drive, done)
*
* @this {HDC}
* @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)
*/
HDC.prototype.doWrite = function(drive, done)
HDC.prototype.doDMAWrite = function(drive, done)
{
drive.errorCode = HDC.XTC.DATA.ERR.NOT_READY;
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) {
@ -2300,17 +2321,17 @@ HDC.prototype.doWrite = function(drive, done)
};
/**
* doWriteToBuffer(drive, done)
* doDMAWriteBuffer(drive, done)
*
* @this {HDC}
* @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)
*/
HDC.prototype.doWriteToBuffer = function(drive, done)
HDC.prototype.doDMAWriteBuffer = function(drive, done)
{
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) {
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.nBytes (bytes/sector)
@ -2358,7 +2379,7 @@ HDC.prototype.doWriteToBuffer = function(drive, done)
* @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)
*/
HDC.prototype.doFormat = function(drive, done)
HDC.prototype.doDMAFormat = function(drive, done)
{
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.
*/
this.messageDebugger("keyboard reset", Debugger.MESSAGE.PORT);
this.messageDebugger("keyboard reset", Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT);
this.abScanBuffer = [Keyboard.CMDRES.BAT_SUCC];
if (this.chipset) this.chipset.notifyKbdData(true);
};
@ -989,8 +989,8 @@ Keyboard.prototype.setEnable = function(fData, fClock)
{
var fReset = false;
if (this.fClock !== fClock) {
if (DEBUG && this.messageEnabled()) {
this.messageDebugger("keyboard clock line changing to " + fClock, Debugger.MESSAGE.PORT);
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KBD | 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
@ -999,8 +999,8 @@ Keyboard.prototype.setEnable = function(fData, fClock)
this.fClock = this.fResetOnEnable = fClock;
}
if (this.fData !== fData) {
if (DEBUG && this.messageEnabled()) {
this.messageDebugger("keyboard data line changing to " + fData, Debugger.MESSAGE.PORT);
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KBD | Debugger.MESSAGE.PORT)) {
this.messageDebugger("keyboard data line changing to " + fData, true);
}
this.fData = fData;
/*
@ -1637,7 +1637,7 @@ Keyboard.prototype.keyUpDown = function(event, fDown)
}
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;
};
@ -1687,7 +1687,7 @@ Keyboard.prototype.keyPress = function(event)
}
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) {
this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume"));
this.messageDebugger("keyPress(" + keyCode + "): " + (fPass? "pass" : "consume"), true);
}
return fPass;
};
@ -1749,7 +1749,7 @@ Keyboard.prototype.keySimulatePress = function(keyCode, fCheckShift, fQuickRelea
fSimulated = true;
}
if (DEBUG && this.messageEnabled(Debugger.MESSAGE.KEYS)) {
this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false"));
this.messageDebugger("keySimulatePress(" + keyCode + "): " + (fSimulated? "true" : "false"), true);
}
return fSimulated;
};
@ -1836,7 +1836,7 @@ Keyboard.prototype.keySimulateUpOrDown = function(keyCode, fDown, simCode)
fSimulated = true;
}
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;
};

View file

@ -43,16 +43,6 @@ if (typeof module !== 'undefined') {
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)
*
@ -171,14 +161,13 @@ function Video(parmsVideo, canvas, context, textarea)
* 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,
* 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.
*/
this.addrBuffer = this.sizeBuffer = 0;
/*
* aFonts is an array of font objects (ie, arrays) 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.
* 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.
*
* 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
@ -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.UNKNOWN = 0xFF;
/**
* @class Font
* @property {number} cxCell
* @property {number} cyCell
* @property {Array} aCSSColors
* @property {Array} aRGBColors
* @property {Array} aColorMap
* @property {Array} aCanvas
*/
/*
* Supported Fonts
*

View file

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

View file

@ -691,7 +691,7 @@ var X86Help = {
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 fRunning = this.bitField.fRunning;
if (this.messageDebugger(sMessage)) {
if (this.messageDebugger(sMessage, bitsMessage)) {
if (fHalt) {
/*
* 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;
},
/**
* messageEnabled(bitsMessage, fOnly)
* messageEnabled(bitsMessage)
*
* If bitsMessage is not specified, the component's MESSAGE category is used.
*
* @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
*/
messageEnabled: function(bitsMessage) {
if (DEBUGGER && this.dbg) {
if (this === this.dbg) {
bitsMessage = bitsMessage || 0;
bitsMessage |= 0;
} else {
if (!bitsMessage) {
bitsMessage = this.bitsMessage;
}
bitsMessage = bitsMessage || this.bitsMessage;
}
var bitsEnabled = this.dbg.bitsMessage & bitsMessage;
return (bitsEnabled === bitsMessage || !!(bitsEnabled & this.dbg.bitsWarning));
@ -956,15 +956,18 @@ Component.prototype = {
/**
* 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}
* @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
* @return {boolean} true if Debugger available, false if not
*/
messageDebugger: function(sMessage, bitsMessage, fAddress) {
if (DEBUGGER && this.dbg) {
if (bitsMessage == null || this.messageEnabled(bitsMessage)) {
if (bitsMessage === true || this.messageEnabled(bitsMessage | 0)) {
this.dbg.message(sMessage, fAddress);
}
return true;
@ -974,19 +977,25 @@ Component.prototype = {
/**
* 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}
* @param {number} port
* @param {number|null} bOut if an output operation
* @param {number|null} [addrFrom]
* @param {string|null} [name] of the port, if any
* @param {number} [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|null} [bIn] is the input value, if known, on an input operation
* @param {number|boolean} [bitsMessage] is zero or more Debugger MESSAGE_* category flag(s)
*/
messagePort: function(port, bOut, addrFrom, name, bIn, bitsMessage) {
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);
}
}
};