Enable read/write breakpoints on DMA operations

This commit is contained in:
Jeff Parsons 2014-12-27 22:52:18 -08:00 committed by jeffpar
commit 7753bce94c
5 changed files with 88 additions and 30 deletions

View file

@ -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++;
}

View file

@ -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) {

View file

@ -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;

View file

@ -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;
};

View file

@ -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;