Improved preservation of read/write breakpoints in dynamic memory regions
The old solution was Debugger-specific (ie, redoBreakpoints), the new solution works for both the Debugger and for Debug register support
This commit is contained in:
parent
5a9348c75f
commit
33d28a29de
3 changed files with 36 additions and 63 deletions
|
|
@ -394,12 +394,12 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
|
|||
}
|
||||
return this.reportError(1, addr, size);
|
||||
}
|
||||
block = this.aMemBlocks[iBlock++] = new Memory(addr, sizeBlock, this.nBlockSize, type, controller);
|
||||
if (DEBUGGER && this.dbg) {
|
||||
block.setDebugger(this.dbg, addr, this.nBlockSize);
|
||||
}
|
||||
size -= sizeBlock;
|
||||
var blockOld = this.aMemBlocks[iBlock];
|
||||
var blockNew = new Memory(addr, sizeBlock, this.nBlockSize, type, controller);
|
||||
blockNew.copyBreakpoints(blockOld, this.dbg);
|
||||
this.aMemBlocks[iBlock++] = blockNew;
|
||||
addr = addrBlock + this.nBlockSize;
|
||||
size -= sizeBlock;
|
||||
}
|
||||
if (size > 0) {
|
||||
return this.reportError(2, addr, size);
|
||||
|
|
@ -563,7 +563,7 @@ Bus.prototype.setMemoryAccess = function(addr, size, afn)
|
|||
/**
|
||||
* removeMemory(addr, size)
|
||||
*
|
||||
* Replaces every block in the specified address range with empty Memory blocks that will ignore all reads/writes.
|
||||
* Replaces every block in the specified address range with empty Memory blocks that ignore all reads/writes.
|
||||
*
|
||||
* TODO: Update the removeMemory() interface to reflect the relaxed requirements of the addMemory() interface.
|
||||
*
|
||||
|
|
@ -577,11 +577,11 @@ Bus.prototype.removeMemory = function(addr, size)
|
|||
if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
|
||||
var iBlock = addr >>> this.nBlockShift;
|
||||
while (size > 0) {
|
||||
var blockOld = this.aMemBlocks[iBlock];
|
||||
var blockNew = new Memory(addr);
|
||||
blockNew.copyBreakpoints(blockOld, this.dbg);
|
||||
this.aMemBlocks[iBlock++] = blockNew;
|
||||
addr = iBlock * this.nBlockSize;
|
||||
var block = this.aMemBlocks[iBlock++] = new Memory(addr);
|
||||
if (DEBUGGER && this.dbg) {
|
||||
block.setDebugger(this.dbg, addr, this.nBlockSize);
|
||||
}
|
||||
size -= this.nBlockSize;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -633,10 +633,7 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
|
|||
if (!block) break;
|
||||
if (type !== undefined) {
|
||||
var blockNew = new Memory(addr);
|
||||
if (DEBUGGER && this.dbg) {
|
||||
blockNew.setDebugger(this.dbg, addr, this.nBlockSize);
|
||||
}
|
||||
blockNew.clone(block, type);
|
||||
blockNew.clone(block, type, this.dbg);
|
||||
block = blockNew;
|
||||
}
|
||||
this.aMemBlocks[iBlock++] = block;
|
||||
|
|
|
|||
|
|
@ -3234,36 +3234,6 @@ if (DEBUGGER) {
|
|||
return aBreak.length - 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* redoBreakpoints()
|
||||
*
|
||||
* This function is for the Memory component: whenever the Bus allocates a new Memory block, it calls
|
||||
* the block's setDebugger() method, which clears the memory block's breakpoint counts. setDebugger(),
|
||||
* in turn, must call this function to re-apply any existing breakpoints to that block.
|
||||
*
|
||||
* This ensures that, even if a memory region is remapped (which creates new Memory blocks in the process),
|
||||
* any breakpoints that were previously applied to that region will still work.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {number} addr of memory block
|
||||
* @param {number} size of memory block
|
||||
* @param {Array} [aBreak]
|
||||
*/
|
||||
Debugger.prototype.redoBreakpoints = function(addr, size, aBreak)
|
||||
{
|
||||
if (aBreak === undefined) {
|
||||
this.redoBreakpoints(addr, size, this.aBreakRead);
|
||||
this.redoBreakpoints(addr, size, this.aBreakWrite);
|
||||
return;
|
||||
}
|
||||
for (var i = 1; i < aBreak.length; i++) {
|
||||
var addrBreak = this.getAddr(aBreak[i]);
|
||||
if (addrBreak >= addr && addrBreak < addr + size) {
|
||||
this.bus.addMemBreak(addrBreak, aBreak == this.aBreakWrite);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* setTempBreakpoint(dbgAddr)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -110,6 +110,7 @@ function Memory(addr, used, size, type, controller, cpu)
|
|||
this.controller = null;
|
||||
this.cpu = cpu; // If a CPU reference is provided, then this must be an UNPAGED Memory block allocation
|
||||
this.fDirty = this.fDirtyEver = false;
|
||||
this.cReadBreakpoints = this.cWriteBreakpoints = 0;
|
||||
this.setPhysBlock();
|
||||
|
||||
if (BACKTRACK) {
|
||||
|
|
@ -265,8 +266,9 @@ Memory.prototype = {
|
|||
* @this {Memory}
|
||||
* @param {Memory} mem
|
||||
* @param {number} [type]
|
||||
* @param {Debugger} [dbg]
|
||||
*/
|
||||
clone: function(mem, type) {
|
||||
clone: function(mem, type, dbg) {
|
||||
/*
|
||||
* Original memory block IDs are even; cloned memory block IDs are odd;
|
||||
* the original ID of the current block is lost, but that's OK, since it was presumably
|
||||
|
|
@ -279,6 +281,7 @@ Memory.prototype = {
|
|||
this.type = type;
|
||||
this.fReadOnly = (type == Memory.TYPE.ROM);
|
||||
}
|
||||
this.dbg = dbg;
|
||||
if (TYPEDARRAYS) {
|
||||
this.buffer = mem.buffer;
|
||||
this.dv = mem.dv;
|
||||
|
|
@ -471,22 +474,6 @@ Memory.prototype = {
|
|||
this.writeShort = this.fReadOnly? this.writeShortDefault : this.writeShortDirect;
|
||||
this.writeLong = this.fReadOnly? this.writeLongDefault : this.writeLongDirect;
|
||||
},
|
||||
/**
|
||||
* setDebugger(dbg, addr, size)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {Debugger} dbg
|
||||
* @param {number} addr of block
|
||||
* @param {number} size of block
|
||||
*/
|
||||
setDebugger: function(dbg, addr, size) {
|
||||
if (DEBUGGER) {
|
||||
this.dbg = dbg;
|
||||
this.cReadBreakpoints = this.cWriteBreakpoints = 0;
|
||||
Component.assert(this.dbg);
|
||||
this.dbg.redoBreakpoints(addr, size);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* getPageBlock(addr, fWrite)
|
||||
*
|
||||
|
|
@ -559,8 +546,8 @@ Memory.prototype = {
|
|||
* existence of a CPU reference only impacts the performance of the "checked" memory access functions, so it's
|
||||
* not critical to eliminate it.
|
||||
*
|
||||
* TODO: Another option would be to count CPU references separately from Debugger references, so that when the
|
||||
* former goes to zero, we can unconditionally remove the CPU reference; UNPAGED blocks would automatically
|
||||
* TODO: Another option would be to count CPU references separately from Debugger references, so that when
|
||||
* the former goes to zero, we can unconditionally remove the CPU reference; UNPAGED blocks would automatically
|
||||
* increment that reference count, so their CPU reference would never go away.
|
||||
*
|
||||
* @this {Memory}
|
||||
|
|
@ -583,6 +570,25 @@ Memory.prototype = {
|
|||
Component.assert(this.cWriteBreakpoints >= 0);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* copyBreakpoints(mem)
|
||||
*
|
||||
* @this {Memory}
|
||||
* @param {Memory|undefined} mem (outgoing Memory block to copy breakpoints from, if any)
|
||||
* @param {Debugger} [dbg]
|
||||
*/
|
||||
copyBreakpoints: function(mem, dbg) {
|
||||
if (mem) {
|
||||
if (dbg) this.dbg = dbg;
|
||||
if (mem.cpu) this.cpu = mem.cpu;
|
||||
if ((this.cReadBreakpoints = mem.cReadBreakpoints)) {
|
||||
this.setReadAccess(Memory.afnChecked, false);
|
||||
}
|
||||
if ((this.cWriteBreakpoints = mem.cWriteBreakpoints)) {
|
||||
this.setWriteAccess(Memory.afnChecked, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* readNone(off)
|
||||
*
|
||||
|
|
|
|||
Loading…
Reference in a new issue