Hard disk controller fixes
Still some lingering OS/2 disk-related issues however
This commit is contained in:
parent
a14d22c806
commit
9578faf231
12 changed files with 392 additions and 296 deletions
File diff suppressed because one or more lines are too long
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue