diff --git a/modules/pcjs/lib/bus.js b/modules/pcjs/lib/bus.js index cc3c08914..0f354a528 100644 --- a/modules/pcjs/lib/bus.js +++ b/modules/pcjs/lib/bus.js @@ -404,6 +404,18 @@ Bus.prototype.removeMemory = function(addr, size) return this.reportError(4, addr, size); }; +/** + * getByte(addr) + * + * @this {Bus} + * @param {number} addr is a physical (non-segmented) address + * @return {number} byte (8-bit) value at that address + */ +Bus.prototype.getByte = function(addr) +{ + return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByte(addr & this.blockLimit); +}; + /** * getByteDirect(addr) * @@ -416,6 +428,23 @@ Bus.prototype.getByteDirect = function(addr) return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByteDirect(addr & this.blockLimit); }; +/** + * getWord(addr) + * + * @this {Bus} + * @param {number} addr is a physical (non-segmented) address + * @return {number} word (16-bit) value at that address + */ +Bus.prototype.getWord = function(addr) +{ + var off = addr & this.blockLimit; + var iBlock = (addr & this.addrMask) >> this.blockShift; + if (off != this.blockLimit) { + return this.aMemBlocks[iBlock].readWord(off); + } + return this.aMemBlocks[iBlock++].readByte(off) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0) << 8); +}; + /** * getWordDirect(addr) * @@ -433,6 +462,18 @@ Bus.prototype.getWordDirect = function(addr) return this.aMemBlocks[iBlock++].readByteDirect(off) | (this.aMemBlocks[iBlock & this.blockMask].readByteDirect(0) << 8); }; +/** + * setByte(addr, b) + * + * @this {Bus} + * @param {number} addr is a physical (non-segmented) address + * @param {number} b is the byte (8-bit) value to write (we truncate it to 8 bits to be safe) + */ +Bus.prototype.setByte = function(addr, b) +{ + this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff); +}; + /** * setByteDirect(addr, b) * @@ -445,6 +486,25 @@ Bus.prototype.setByteDirect = function(addr, b) this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff); }; +/** + * setWord(addr, w) + * + * @this {Bus} + * @param {number} addr is a physical (non-segmented) address + * @param {number} w is the word (16-bit) value to write (we truncate it to 16 bits to be safe) + */ +Bus.prototype.setWord = function(addr, w) +{ + var off = addr & this.blockLimit; + var iBlock = (addr & this.addrMask) >> this.blockShift; + if (off != this.blockLimit) { + this.aMemBlocks[iBlock].writeWord(off, w & 0xffff); + return; + } + this.aMemBlocks[iBlock++].writeByte(off, w & 0xff); + this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff); +}; + /** * setWordDirect(addr, w) * @@ -527,8 +587,16 @@ Bus.prototype.setBackTrackIndex = function(addr, bto, off) if (btiPrev) { var slot = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT; var btoPrev = this.abtObjects[slot]; - this.assert(btoPrev && btoPrev.refs > 0); - if (!--btoPrev.refs) { + if (!btoPrev) { + if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.WARN)) { + this.dbg.message("setBackTrackIndex(%" + str.toHex(addr) + "): previous index (" + str.toHex(btiPrev) + ") refers to empty slot"); + } + } + else if (btoPrev.refs <= 0) { + if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.WARN)) { + this.dbg.message("setBackTrackIndex(%" + str.toHex(addr) + "): previous index (" + str.toHex(btiPrev) + ") refers object to with bad ref count (" + btoPrev.refs + ")"); + } + } else if (!--btoPrev.refs) { this.abtObjects[slot] = null; this.cbtDeletions++; } diff --git a/modules/pcjs/lib/chipset.js b/modules/pcjs/lib/chipset.js index 40a2e8d82..dccea2126 100644 --- a/modules/pcjs/lib/chipset.js +++ b/modules/pcjs/lib/chipset.js @@ -2787,7 +2787,7 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) 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.messagePrint("advanceDMA(" + iDMAChannel + ") transferring " + channel.cbDebug + " bytes from " + channel.sAddrDebug, true); - this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); + this.dbg.doDump("db", channel.sAddrDebug, "l" + channel.cbDebug); } } if (channel.xfer == ChipSet.DMA_MODE.XFER_WRITE) { @@ -2807,16 +2807,10 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) b = 0xff; } if (!channel.masked) { - /* - * While it makes sense to call bus.setByteDirect(), since DMA deals with physical memory, - * we lose the ability to trap accesses with write breakpoints by not using chipset.cpu.setByte(). - * - * TODO: Consider providing a Bus memory interface that honors write breakpoints. - */ - chipset.bus.setByteDirect(addrCur, b); + chipset.bus.setByte(addrCur, b); if (BACKTRACK) { if (!off && obj.file) { - chipset.println('loading ' + obj.file.sPath + '[' + obj.offFile + '] @' + str.toHex(addrCur)); + chipset.println('loading ' + obj.file.sPath + '[' + obj.offFile + '] at %' + str.toHex(addrCur)); } bto = chipset.bus.addBackTrackObject(obj, bto, off); chipset.bus.setBackTrackIndex(addrCur, bto, off); @@ -2833,13 +2827,9 @@ ChipSet.prototype.advanceDMA = function(channel, fInit) } else if (channel.xfer == ChipSet.DMA_MODE.XFER_READ) { /* - * While it makes sense to call bus.getByteDirect(), since DMA deals with physical memory, - * we lose the ability to trap accesses with read breakpoints by not using chipset.cpu.getByte(). - * - * TODO: Determine whether we should support async dmaWrite() functions (currently not required), - * and consider providing a Bus memory interface that honors read breakpoints. + * TODO: Determine whether we should support async dmaWrite() functions (currently not required) */ - b = chipset.bus.getByteDirect(addr); + b = chipset.bus.getByte(addr); if (channel.fnTransfer.call(channel.component, channel.obj, b) < 0) { /* * In this case, I think I have no choice but to terminate the DMA operation in response to a failure, @@ -2907,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.messagePrint("updateDMA(" + iDMAChannel + ") transferred " + channel.cbDebug + " bytes to " + channel.sAddrDebug, true); - this.dbg.doDump("db", channel.sAddrDebug, "l" + Math.floor((channel.cbDebug + 15) / 16)); + this.dbg.doDump("db", channel.sAddrDebug, "l" + channel.cbDebug); } if (channel.done) { diff --git a/modules/pcjs/lib/debugger.js b/modules/pcjs/lib/debugger.js index 414668fd4..203742950 100644 --- a/modules/pcjs/lib/debugger.js +++ b/modules/pcjs/lib/debugger.js @@ -2662,7 +2662,7 @@ if (DEBUGGER) { if (aAddrBreak[3]) { this.findBreakpoint(aBreak, aAddrBreak, true); } else if (!fTemp) { - this.println("\nbreakpoint hit: " + this.hexAddr(aAddrBreak) + " (" + aBreak[0] + ")"); + this.println("breakpoint hit: " + this.hexAddr(aAddrBreak) + " (" + aBreak[0] + ")"); } fBreak = true; break; diff --git a/modules/pcjs/lib/disk.js b/modules/pcjs/lib/disk.js index 40d2df499..608611cd1 100644 --- a/modules/pcjs/lib/disk.js +++ b/modules/pcjs/lib/disk.js @@ -231,7 +231,7 @@ if (typeof module !== 'undefined') { */ function Disk(controller, drive, mode) { - Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + Disk.nDisks++}, Disk, Messages.DISK); + Component.call(this, "Disk", {'id': controller.idMachine + ".disk" + ++Disk.nDisks}, Disk, Messages.DISK); /* * Route all non-Debugger messages (eg, notice() and println() calls) through @@ -1014,7 +1014,7 @@ Disk.prototype.buildFileTable = function() var apba = []; for (var lba = dir.lbaRoot; lba < dir.lbaData; lba++) apba.push(dir.pbaVolume + lba); - this.getDir(dir, "", apba); + this.getDir(dir, "\\\\DISK" + Disk.nDisks, apba); /* * Create the sector-to-file mappings now. @@ -1241,9 +1241,10 @@ Disk.prototype.updateSector = function(file, pba, off) var iCylinder = (pba / nSectorsPerCylinder) | 0; var nSectorsRemaining = (pba % nSectorsPerCylinder); var iHead = (nSectorsRemaining / this.nSectors) | 0; - var iSector = (nSectorsRemaining % this.nSectors) + 1; + var iSector = (nSectorsRemaining % this.nSectors); var cylinder, head, sector; if ((cylinder = this.aDiskData[iCylinder]) && (head = cylinder[iHead]) && (sector = head[iSector])) { + this.assert(sector['sector'] == iSector +1); if (sector.file) { if (DEBUG && this.messageEnabled()) { this.messagePrint('"' + sector.file.sPath + '" cross-linked at offset ' + sector.file.offFile + ' with "' + file.sPath + '" at offset ' + off); @@ -1254,6 +1255,7 @@ Disk.prototype.updateSector = function(file, pba, off) sector.offFile = off; return true; } + if (DEBUG && this.messageEnabled()) this.messagePrint("unable to map PBA " + pba + " to CHS"); return false; }; diff --git a/modules/pcjs/lib/fdc.js b/modules/pcjs/lib/fdc.js index 9bb5d5711..1f31608c4 100644 --- a/modules/pcjs/lib/fdc.js +++ b/modules/pcjs/lib/fdc.js @@ -2204,11 +2204,10 @@ FDC.prototype.doRead = function(drive) */ drive.resCode = FDC.REG_DATA.RES.NOT_READY | FDC.REG_DATA.RES.INCOMPLETE; - if (DEBUG && this.messageEnabled()) { - this.messagePrint("FDC.doRead(" + drive.bCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")"); - } - if (drive.disk) { + if (DEBUG && this.messageEnabled()) { + this.messagePrint("FDC.doRead(CHS=" + drive.bCylinder + ':' + drive.bHead + ':' + drive.bSector + ",LBA=" + (drive.bCylinder * (drive.disk.nHeads * drive.disk.nSectors) + drive.bHead * drive.disk.nSectors + drive.bSector-1) + ')'); + } drive.sector = null; drive.resCode = FDC.REG_DATA.RES.NONE; if (this.chipset) { @@ -2228,11 +2227,10 @@ FDC.prototype.doWrite = function(drive) { drive.resCode = FDC.REG_DATA.RES.NOT_READY | FDC.REG_DATA.RES.INCOMPLETE; - if (DEBUG && this.messageEnabled()) { - this.messagePrint("FDC.doWrite(" + drive.bCylinder + ":" + drive.bHead + ":" + drive.bSector + ":" + drive.nBytes + ")"); - } - if (drive.disk) { + if (DEBUG && this.messageEnabled()) { + this.messagePrint("FDC.doWrite(CHS=" + drive.bCylinder + ':' + drive.bHead + ':' + drive.bSector + ",LBA=" + (drive.bCylinder * (drive.disk.nHeads * drive.disk.nSectors) + drive.bHead * drive.disk.nSectors + drive.bSector-1) + ')'); + } if (drive.disk.fWriteProtected) { drive.resCode = FDC.REG_DATA.RES.NOT_WRITABLE | FDC.REG_DATA.RES.INCOMPLETE; return;