Enable read/write breakpoints on DMA operations
This commit is contained in:
parent
197392bce9
commit
7753bce94c
5 changed files with 88 additions and 30 deletions
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue