Initial scaffolding for paged memory

This commit is contained in:
Jeff Parsons 2015-04-28 17:45:29 -07:00 • committed by jeffpar
commit 6108fb25ab
8 changed files with 431 additions and 276 deletions

View file

@ -99,13 +99,13 @@ function Bus(parmsBus, cpu, dbg)
* Bus Property Old hard-coded values (when nBusWidth was always 20) * Bus Property Old hard-coded values (when nBusWidth was always 20)
* ------------ ---------------------------------------------------- * ------------ ----------------------------------------------------
* this.busLimit 0xfffff * this.busLimit 0xfffff
* this.busMask N/A * this.busMask [same as busLimit]
* this.blockSize 4096 * this.blockSize 4096
* this.blockLen (this.blockSize >> 2) * this.blockLen (this.blockSize >> 2)
* this.blockShift 12 * this.blockShift 12
* this.blockLimit 0xfff * this.blockLimit 0xfff
* this.blockTotal ((this.busLimit + this.blockSize) / this.blockSize) | 0 * this.blockTotal ((this.busLimit + this.blockSize) / this.blockSize) | 0
* this.blockMask (this.blockTotal - 1) (ie, 0xff) * this.blockMask (this.blockTotal - 1) [ie, 0xff]
* *
* Note that we choose a blockShift value (and thus a physical memory block size) based on "buswidth": * Note that we choose a blockShift value (and thus a physical memory block size) based on "buswidth":
* *
@ -120,7 +120,7 @@ function Bus(parmsBus, cpu, dbg)
* requirements. Your choices, for the moment, are either to ensure the allocations are performed in * requirements. Your choices, for the moment, are either to ensure the allocations are performed in
* order, or to choose smaller blockShift values (at the expense of a generating a larger block array). * order, or to choose smaller blockShift values (at the expense of a generating a larger block array).
* *
* However, if PAGEBLOCKS is set, then for a bus width of 32 bits, the block size is fixed at 4Kb. * Note that if PAGEBLOCKS is set, then for a bus width of 32 bits, the block size is fixed at 4Kb.
*/ */
this.addrTotal = Math.pow(2, this.nBusWidth); this.addrTotal = Math.pow(2, this.nBusWidth);
this.busLimit = this.busMask = (this.addrTotal - 1) | 0; this.busLimit = this.busMask = (this.addrTotal - 1) | 0;
@ -171,6 +171,11 @@ function Bus(parmsBus, cpu, dbg)
this.ibtLastDelete = 0; this.ibtLastDelete = 0;
} }
if (PAGEBLOCKS) {
this.addrPD = null;
this.aPhysBlocks = null;
}
this.setReady(); this.setReady();
} }
@ -394,7 +399,9 @@ Bus.prototype.addMemory = function(addr, size, type, controller)
return this.reportError(1, addr, size); return this.reportError(1, addr, size);
} }
block = this.aMemBlocks[iBlock++] = new Memory(addr, sizeBlock, this.blockSize, type, controller); block = this.aMemBlocks[iBlock++] = new Memory(addr, sizeBlock, this.blockSize, type, controller);
if (DEBUGGER && this.dbg) block.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize); if (DEBUGGER && this.dbg) {
block.setDebugger(this.dbg, addr, this.blockSize);
}
size -= sizeBlock; size -= sizeBlock;
addr = addrBlock + this.blockSize; addr = addrBlock + this.blockSize;
} }
@ -478,10 +485,10 @@ Bus.prototype.getA20 = function()
* *
* On 32-bit bus machines, I've adopted the approach that Compaq took with DeskPro 386 machines, * On 32-bit bus machines, I've adopted the approach that Compaq took with DeskPro 386 machines,
* which is to map the 1st Mb to the 2nd Mb whenever A20 is disabled, rather than blindly masking * which is to map the 1st Mb to the 2nd Mb whenever A20 is disabled, rather than blindly masking
* the A20 address bit from all addresses; this is what the DeskPro 386 ROM BIOS requires. * the A20 address bit from all addresses; in fact, this is what the DeskPro 386 ROM BIOS requires.
* *
* For 24-bit bus machines, we take the same approach that most if not all 80286 systems took, which * For 24-bit bus machines, we take the same approach that most if not all 80286 systems took, which
* is simply masking the A20 address bit. * is simply masking the A20 address bit. A lot of 32-bit machines probably took the same approach.
* *
* TODO: On machines with a 32-bit bus, look into whether we can eliminate address masking altogether, * TODO: On machines with a 32-bit bus, look into whether we can eliminate address masking altogether,
* which seems feasible, provided all incoming addresses are already pre-truncated to 32 bits. Also, * which seems feasible, provided all incoming addresses are already pre-truncated to 32 bits. Also,
@ -579,7 +586,9 @@ Bus.prototype.removeMemory = function(addr, size)
while (size > 0) { while (size > 0) {
addr = iBlock * this.blockSize; addr = iBlock * this.blockSize;
var block = this.aMemBlocks[iBlock++] = new Memory(addr); var block = this.aMemBlocks[iBlock++] = new Memory(addr);
if (DEBUGGER && this.dbg) block.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize); if (DEBUGGER && this.dbg) {
block.setDebugger(this.dbg, addr, this.blockSize);
}
size -= this.blockSize; size -= this.blockSize;
} }
return true; return true;
@ -631,7 +640,9 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
if (!block) break; if (!block) break;
if (type !== undefined) { if (type !== undefined) {
var blockNew = new Memory(addr); var blockNew = new Memory(addr);
if (DEBUGGER && this.dbg) blockNew.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize); if (DEBUGGER && this.dbg) {
blockNew.setDebugger(this.dbg, addr, this.blockSize);
}
blockNew.clone(block, type); blockNew.clone(block, type);
block = blockNew; block = blockNew;
} }
@ -640,6 +651,60 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
} }
}; };
/**
* enablePageBlocks(addrPD)
*
* Whenever the CPU turns on paging and/or updates CR3, this function is called to leverage the Bus's
* memory-mapping abilities and simulate the effects of the CPU's page directory and page table entries.
* Whenever the CPU turns paging off, disablePageBlocks() must be called to restore the original physical
* memory mapping.
*
* This also requires that PAGEBLOCKS be true, ensuring that the Bus is preconfigured with 4Kb memory
* mapping granularity.
*
* The first time this function is called, aMemBlocks is stashed in aPhysBlocks, and aMemBlocks is then
* reinitialized with special "unpaged" Memory blocks that know how to perform page directory/page table
* lookup and replace themselves with special "paged" Memory blocks that reference memory from the
* appropriate block in aPhysBlocks. A parallel array, aMemPaged, keeps track of which blocks have been
* "paged", so that whenever CR3 is updated, just those blocks can be "unpaged" again.
*
* @this {Bus}
* @param {number} addrPD is the starting physical address of the CPU's page directory
*/
Bus.prototype.enablePageBlocks = function(addrPD)
{
if (!PAGEBLOCKS) {
Component.error("PAGEBLOCK support missing");
return;
}
this.addrPD = addrPD;
if (!this.aPhysBlocks) {
this.aPhysBlocks = this.aMemBlocks;
var block = new Memory(null, 0, 0, Memory.TYPE.UNPAGED, null, this);
this.aMemBlocks = new Array(this.blockTotal);
for (var iBlock = 0; iBlock < this.blockTotal; iBlock++) {
this.aMemBlocks[iBlock] = block;
}
}
};
/**
* mapPageBlock(addr)
*
* If addr is a valid linear address, then we must obtain the following information:
*
* (1) the physical Memory object corresponding to the linear address in addr
* (2) the physical Memory object containing that memory's PTE
* (3) the offset within the preceding physical Memory object of that memory's PTE
*
* Item (1) allows us to convert an "unpaged" Memory block in to a "paged" Memory block, and the combination of
* (2) and (3) allows us to efficiently update the PTE whenever the page is accesssed and/or modified.
*/
Bus.prototype.mapPageBlock = function(addr)
{
return null;
};
/** /**
* getByte(addr) * getByte(addr)
* *
@ -652,7 +717,7 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
*/ */
Bus.prototype.getByte = function(addr) Bus.prototype.getByte = function(addr)
{ {
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit); return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr);
}; };
/** /**
@ -666,7 +731,7 @@ Bus.prototype.getByte = function(addr)
*/ */
Bus.prototype.getByteDirect = function(addr) Bus.prototype.getByteDirect = function(addr)
{ {
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByteDirect(addr & this.blockLimit); return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByteDirect(addr & this.blockLimit, addr);
}; };
/** /**
@ -685,9 +750,9 @@ Bus.prototype.getShort = function(addr)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) { if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readShort(off); return this.aMemBlocks[iBlock].readShort(off, addr);
} }
return this.aMemBlocks[iBlock++].readByte(off) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0) << 8); return this.aMemBlocks[iBlock++].readByte(off, addr) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0, addr + 1) << 8);
}; };
/** /**
@ -704,9 +769,9 @@ Bus.prototype.getShortDirect = function(addr)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) { if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readShortDirect(off); return this.aMemBlocks[iBlock].readShortDirect(off, addr);
} }
return this.aMemBlocks[iBlock++].readByteDirect(off) | (this.aMemBlocks[iBlock & this.blockMask].readByteDirect(0) << 8); return this.aMemBlocks[iBlock++].readByteDirect(off, addr) | (this.aMemBlocks[iBlock & this.blockMask].readByteDirect(0, addr + 1) << 8);
}; };
/** /**
@ -725,10 +790,10 @@ Bus.prototype.getLong = function(addr)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) { if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLong(off); return this.aMemBlocks[iBlock].readLong(off, addr);
} }
var nShift = (off & 0x3) << 3; var nShift = (off & 0x3) << 3;
return (this.aMemBlocks[iBlock].readLong(off & ~0x3) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLong(0) << (32 - nShift)); return (this.aMemBlocks[iBlock].readLong(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLong(0, addr + 3) << (32 - nShift));
}; };
/** /**
@ -745,10 +810,10 @@ Bus.prototype.getLongDirect = function(addr)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) { if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLongDirect(off); return this.aMemBlocks[iBlock].readLongDirect(off, addr);
} }
var nShift = (off & 0x3) << 3; var nShift = (off & 0x3) << 3;
return (this.aMemBlocks[iBlock].readLongDirect(off & ~0x3) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLongDirect(0) << (32 - nShift)); return (this.aMemBlocks[iBlock].readLongDirect(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLongDirect(0, addr + 3) << (32 - nShift));
}; };
/** /**
@ -763,7 +828,7 @@ Bus.prototype.getLongDirect = function(addr)
*/ */
Bus.prototype.setByte = function(addr, b) Bus.prototype.setByte = function(addr, b)
{ {
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff); this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff, addr);
}; };
/** /**
@ -778,7 +843,7 @@ Bus.prototype.setByte = function(addr, b)
*/ */
Bus.prototype.setByteDirect = function(addr, b) Bus.prototype.setByteDirect = function(addr, b)
{ {
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff); this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff, addr);
}; };
/** /**
@ -797,11 +862,11 @@ Bus.prototype.setShort = function(addr, w)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) { if (off != this.blockLimit) {
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff); this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr);
return; return;
} }
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff); this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr);
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff); this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff, addr + 1);
}; };
/** /**
@ -819,11 +884,11 @@ Bus.prototype.setShortDirect = function(addr, w)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off != this.blockLimit) { if (off != this.blockLimit) {
this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff); this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff, addr);
return; return;
} }
this.aMemBlocks[iBlock++].writeByteDirect(off, w & 0xff); this.aMemBlocks[iBlock++].writeByteDirect(off, w & 0xff, addr);
this.aMemBlocks[iBlock & this.blockMask].writeByteDirect(0, (w >> 8) & 0xff); this.aMemBlocks[iBlock & this.blockMask].writeByteDirect(0, (w >> 8) & 0xff, addr + 1);
}; };
/** /**
@ -847,11 +912,12 @@ Bus.prototype.setLong = function(addr, l)
} }
var lPrev, nShift = (off & 0x3) << 3; var lPrev, nShift = (off & 0x3) << 3;
off &= ~0x3; off &= ~0x3;
lPrev = this.aMemBlocks[iBlock].readLong(off); lPrev = this.aMemBlocks[iBlock].readLong(off, addr);
this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift)); this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift), addr);
iBlock = (iBlock + 1) & this.blockMask; iBlock = (iBlock + 1) & this.blockMask;
lPrev = this.aMemBlocks[iBlock].readLong(0); addr += 3;
this.aMemBlocks[iBlock].writeLong(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift))); lPrev = this.aMemBlocks[iBlock].readLong(0, addr);
this.aMemBlocks[iBlock].writeLong(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift)), addr);
}; };
/** /**
@ -869,16 +935,17 @@ Bus.prototype.setLongDirect = function(addr, l)
var off = addr & this.blockLimit; var off = addr & this.blockLimit;
var iBlock = (addr & this.busMask) >>> this.blockShift; var iBlock = (addr & this.busMask) >>> this.blockShift;
if (off < this.blockLimit - 2) { if (off < this.blockLimit - 2) {
this.aMemBlocks[iBlock].writeLongDirect(off, l); this.aMemBlocks[iBlock].writeLongDirect(off, l, addr);
return; return;
} }
var lPrev, nShift = (off & 0x3) << 3; var lPrev, nShift = (off & 0x3) << 3;
off &= ~0x3; off &= ~0x3;
lPrev = this.aMemBlocks[iBlock].readLongDirect(off); lPrev = this.aMemBlocks[iBlock].readLongDirect(off, addr);
this.aMemBlocks[iBlock].writeLongDirect(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift)); this.aMemBlocks[iBlock].writeLongDirect(off, (lPrev & ~((0xffffffff|0) << nShift)) | (l << nShift), addr);
iBlock = (iBlock + 1) & this.blockMask; iBlock = (iBlock + 1) & this.blockMask;
lPrev = this.aMemBlocks[iBlock].readLongDirect(0); addr += 3;
this.aMemBlocks[iBlock].writeLongDirect(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift))); lPrev = this.aMemBlocks[iBlock].readLongDirect(0, addr);
this.aMemBlocks[iBlock].writeLongDirect(0, (lPrev & ((0xffffffff|0) << nShift)) | (l >>> (32 - nShift)), addr);
}; };
/** /**

View file

@ -2807,7 +2807,7 @@ if (DEBUGGER) {
* redoBreakpoints() * redoBreakpoints()
* *
* This function is for the Memory component: whenever the Bus allocates a new Memory block, it calls * This function is for the Memory component: whenever the Bus allocates a new Memory block, it calls
* the block's setDebugInfo() method, which clears the memory block's breakpoint counts. setDebugInfo(), * 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. * 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), * This ensures that, even if a memory region is remapped (which creates new Memory blocks in the process),

View file

@ -861,7 +861,7 @@ FDC.prototype.initDrive = function(drive, iDrive, data)
/* /*
* resCode used to be an FDC global, but in order to insulate FDC state from the operation of various functions * resCode used to be an FDC global, but in order to insulate FDC state from the operation of various functions
* that operate on drive objects (eg, readByte and writeByte), I've made it a per-drive variable. This choice, * that operate on drive objects (eg, readData and writeData), I've made it a per-drive variable. This choice,
* similar to my choice for handling PCN, may be contrary to how the actual hardware works, but I prefer this * similar to my choice for handling PCN, may be contrary to how the actual hardware works, but I prefer this
* approach, as long as it doesn't expose any incompatibilities that any software actually cares about. * approach, as long as it doesn't expose any incompatibilities that any software actually cares about.
*/ */
@ -1110,7 +1110,7 @@ FDC.prototype.copyDrive = function(iDrive)
* *
* Also note that in an actual FDC request, drive.nBytes is initialized to the size of a single sector; the extent * Also note that in an actual FDC request, drive.nBytes is initialized to the size of a single sector; the extent
* of the entire transfer is actually determined by a count that has been pre-loaded into the DMA controller. The FDC * of the entire transfer is actually determined by a count that has been pre-loaded into the DMA controller. The FDC
* isn't even aware of the extent of the transfer, so in the case of a read request, all readByte() can do is return * isn't even aware of the extent of the transfer, so in the case of a read request, all readData() can do is return
* bytes until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted. * bytes until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* *
* Since seekDrive() is for use with non-DMA requests, we use nBytes to specify the length of the entire transfer. * Since seekDrive() is for use with non-DMA requests, we use nBytes to specify the length of the entire transfer.
@ -1144,7 +1144,7 @@ FDC.prototype.seekDrive = function(drive, iSector, nSectors)
drive.resCode = FDC.REG_DATA.RES.NONE; drive.resCode = FDC.REG_DATA.RES.NONE;
/* /*
* At this point, we've finished simulating what an FDC.REG_DATA.CMD.READ_DATA command would have performed, * At this point, we've finished simulating what an FDC.REG_DATA.CMD.READ_DATA command would have performed,
* up through doRead(). Now it's the caller responsibility to call readByte(), just like the DMA Controller would. * up through doRead(). Now it's the caller responsibility to call readData(), just like the DMA Controller would.
*/ */
return true; return true;
} }
@ -2147,7 +2147,7 @@ FDC.prototype.pushST3 = function(drive)
FDC.prototype.dmaRead = function(drive, b, done) FDC.prototype.dmaRead = function(drive, b, done)
{ {
if (b === undefined || b < 0) { if (b === undefined || b < 0) {
this.readByte(drive, done); this.readData(drive, done);
return; return;
} }
/* /*
@ -2168,7 +2168,7 @@ FDC.prototype.dmaRead = function(drive, b, done)
FDC.prototype.dmaWrite = function(drive, b) FDC.prototype.dmaWrite = function(drive, b)
{ {
if (b !== undefined && b >= 0) if (b !== undefined && b >= 0)
return this.writeByte(drive, b); return this.writeData(drive, b);
/* /*
* The DMA controller should be GIVING us data, not ASKING for data; this suggests an internal DMA miscommunication * The DMA controller should be GIVING us data, not ASKING for data; this suggests an internal DMA miscommunication
*/ */
@ -2285,7 +2285,7 @@ FDC.prototype.doFormat = function(drive)
}; };
/** /**
* readByte(drive, done) * readData(drive, done)
* *
* The following drive properties must have been setup prior to our first call: * The following drive properties must have been setup prior to our first call:
* *
@ -2294,11 +2294,11 @@ FDC.prototype.doFormat = function(drive)
* drive.bSector * drive.bSector
* drive.sector (initialized to null) * drive.sector (initialized to null)
* *
* On the first readByte() request, since drive.sector will be null, we ask the Disk object to look * On the first readData() request, since drive.sector will be null, we ask the Disk object to look
* up the first sector of the request. We then ask the Disk for bytes from that sector until the sector * up the first sector of the request. We then ask the Disk for bytes from that sector until the sector
* is exhausted, and then we look up the next sector and continue the process. * is exhausted, and then we look up the next sector and continue the process.
* *
* NOTE: Since the FDC isn't aware of the extent of the transfer, all readByte() can do is return bytes * NOTE: Since the FDC isn't aware of the extent of the transfer, all readData() can do is return bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted. * until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* *
* TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done. * TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done.
@ -2307,7 +2307,7 @@ FDC.prototype.doFormat = function(drive)
* @param {Object} drive * @param {Object} drive
* @param {function(number,boolean,Object,number)} done (number is next available byte from drive, or -1 if no more bytes available) * @param {function(number,boolean,Object,number)} done (number is next available byte from drive, or -1 if no more bytes available)
*/ */
FDC.prototype.readByte = function(drive, done) FDC.prototype.readData = function(drive, done)
{ {
var b = -1; var b = -1;
var obj = null, off = 0; // these variables are purely for BACKTRACK purposes var obj = null, off = 0; // these variables are purely for BACKTRACK purposes
@ -2332,7 +2332,7 @@ FDC.prototype.readByte = function(drive, done)
drive.ibSector = 0; drive.ibSector = 0;
/* /*
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek(). * We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
* This allows the initial call to readByte() to perform a seek without triggering an unwanted advance. * This allows the initial call to readData() to perform a seek without triggering an unwanted advance.
*/ */
this.advanceSector(drive); this.advanceSector(drive);
} while (true); } while (true);
@ -2341,7 +2341,7 @@ FDC.prototype.readByte = function(drive, done)
}; };
/** /**
* writeByte(drive, b) * writeData(drive, b)
* *
* The following drive properties must have been setup prior to our first call: * The following drive properties must have been setup prior to our first call:
* *
@ -2350,11 +2350,11 @@ FDC.prototype.readByte = function(drive, done)
* drive.bSector * drive.bSector
* drive.sector (initialized to null) * drive.sector (initialized to null)
* *
* On the first writeByte() request, since drive.sector will be null, we ask the Disk object to look * On the first writeData() request, since drive.sector will be null, we ask the Disk object to look
* up the first sector of the request. We then send the Disk bytes for that sector until the sector * up the first sector of the request. We then send the Disk bytes for that sector until the sector
* is full, and then we look up the next sector and continue the process. * is full, and then we look up the next sector and continue the process.
* *
* NOTE: Since the FDC isn't aware of the extent of the transfer, all writeByte() can do is accept bytes * NOTE: Since the FDC isn't aware of the extent of the transfer, all writeData() can do is accept bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted. * until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* *
* TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done. * TODO: Research the requirements, if any, for multi-track I/O and determine what else needs to be done.
@ -2364,7 +2364,7 @@ FDC.prototype.readByte = function(drive, done)
* @param {number} b containing next byte to write * @param {number} b containing next byte to write
* @return {number} (b unchanged; return -1 if command should be terminated) * @return {number} (b unchanged; return -1 if command should be terminated)
*/ */
FDC.prototype.writeByte = function(drive, b) FDC.prototype.writeData = function(drive, b)
{ {
if (drive.resCode || !drive.disk) return -1; if (drive.resCode || !drive.disk) return -1;
do { do {
@ -2387,7 +2387,7 @@ FDC.prototype.writeByte = function(drive, b)
drive.ibSector = 0; drive.ibSector = 0;
/* /*
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek(). * We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
* This allows the initial call to writeByte() to perform a seek without triggering an unwanted advance. * This allows the initial call to writeData() to perform a seek without triggering an unwanted advance.
*/ */
this.advanceSector(drive); this.advanceSector(drive);
} while (true); } while (true);
@ -2441,7 +2441,7 @@ FDC.prototype.writeFormat = function(drive, b)
this.printMessage("writeFormat(head=" + str.toHexByte(drive.bHead) + ",cyl=" + str.toHexByte(drive.bCylinder) + ",sec=" + str.toHexByte(drive.bSector) + ",len=" + str.toHexWord(drive.nBytes) + ")"); this.printMessage("writeFormat(head=" + str.toHexByte(drive.bHead) + ",cyl=" + str.toHexByte(drive.bCylinder) + ",sec=" + str.toHexByte(drive.bSector) + ",len=" + str.toHexWord(drive.nBytes) + ")");
} }
for (var i = 0; i < drive.nBytes; i++) { for (var i = 0; i < drive.nBytes; i++) {
if (this.writeByte(drive, drive.bFiller) < 0) { if (this.writeData(drive, drive.bFiller) < 0) {
return -1; return -1;
} }
} }

View file

@ -814,7 +814,7 @@ HDC.prototype.initDrive = function(iDrive, drive, driveConfig, data, fHard)
/* /*
* errorCode could be an HDC global, but in order to insulate HDC state from the operation of various functions * errorCode could be an HDC global, but in order to insulate HDC state from the operation of various functions
* that operate on drive objects (eg, readByte and writeByte), I've made it a per-drive variable. This choice may * that operate on drive objects (eg, readData and writeData), I've made it a per-drive variable. This choice may
* be contrary to how the actual hardware works, but I prefer this approach, as long as it doesn't expose any * be contrary to how the actual hardware works, but I prefer this approach, as long as it doesn't expose any
* incompatibilities that any software actually cares about. * incompatibilities that any software actually cares about.
*/ */
@ -1039,7 +1039,7 @@ HDC.prototype.verifyDrive = function(drive, type)
* *
* Also note that in an actual HDC request, drive.nBytes is initialized to the size of a single sector; the extent * Also note that in an actual HDC request, drive.nBytes is initialized to the size of a single sector; the extent
* of the entire transfer is actually determined by a count that has been pre-loaded into the DMA controller. The HDC * of the entire transfer is actually determined by a count that has been pre-loaded into the DMA controller. The HDC
* isn't aware of the extent of the transfer, so in the case of a read request, all readByte() can do is return bytes * isn't aware of the extent of the transfer, so in the case of a read request, all readData() can do is return bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted. * until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* *
* Since seekDrive() is for use with non-DMA requests, we use nBytes to specify the length of the entire transfer. * Since seekDrive() is for use with non-DMA requests, we use nBytes to specify the length of the entire transfer.
@ -1082,7 +1082,7 @@ HDC.prototype.seekDrive = function(drive, iSector, nSectors)
drive.errorCode = HDC.XTC.DATA.ERR.NONE; 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, * At this point, we've finished simulating what an HDC.XTC.DATA.CMD.READ_DATA command would have performed,
* up through doDMARead(). 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 readData(), like the DMA Controller would.
*/ */
return true; return true;
} }
@ -1389,13 +1389,13 @@ HDC.prototype.inATCData = function(port, addrFrom)
if (this.drive) { if (this.drive) {
/* /*
* We use the synchronous form of readByte() at this point because we have no choice; an I/O instruction * We use the synchronous form of readData() 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 * has just occurred and cannot be delayed. The good news is that doATCommand() should have already primed
* the pump; all we can do is assert that the pump has something in it. If bIn is inexplicably negative, * the pump; all we can do is assert that the pump has something in it. If bIn is inexplicably negative,
* well, then the caller will get 0xff. * well, then the caller will get 0xff.
*/ */
var hdc = this; var hdc = this;
bIn = this.readByte(this.drive, function(b, fAsync, obj, off) { bIn = this.readData(this.drive, function(b, fAsync, obj, off) {
hdc.assert(!fAsync); hdc.assert(!fAsync);
if (BACKTRACK) { if (BACKTRACK) {
if (!off && obj.file && hdc.messageEnabled(Messages.DISK)) { if (!off && obj.file && hdc.messageEnabled(Messages.DISK)) {
@ -1440,7 +1440,7 @@ HDC.prototype.inATCData = function(port, addrFrom)
*/ */
if (this.drive.nBytes >= this.drive.cbSector) { if (this.drive.nBytes >= this.drive.cbSector) {
hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ; hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
this.readByte(this.drive, function(b, fAsync) { this.readData(this.drive, function(b, fAsync) {
if (b >= 0) { if (b >= 0) {
hdc.setATCIRR(); hdc.setATCIRR();
hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
@ -1475,7 +1475,7 @@ HDC.prototype.outATCData = function(port, bOut, addrFrom)
{ {
if (this.drive) { if (this.drive) {
if (this.drive.nBytes >= this.drive.cbSector) { if (this.drive.nBytes >= this.drive.cbSector) {
if (this.writeByte(this.drive, bOut) < 0) { if (this.writeData(this.drive, bOut) < 0) {
/* /*
* TODO: It would be nice to be a bit more specific about the error (if any) that just occurred. * TODO: It would be nice to be a bit more specific about the error (if any) that just occurred.
* Consult drive.errorCode (it uses older XTC error codes, but mapping those codes should be trivial). * Consult drive.errorCode (it uses older XTC error codes, but mapping those codes should be trivial).
@ -1833,11 +1833,11 @@ HDC.prototype.doATC = function()
/* /*
* Since the ATC doesn't use DMA, we must now set some additional Drive state for the benefit of any * Since the ATC doesn't use DMA, we must now set some additional Drive state for the benefit of any
* follow-up I/O instructions. For example, any subsequent inATCData() and outATCData() calls need to * 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. * know which drive to talk to ("this.drive"), to issue their own readData() and writeData() calls.
* *
* The XTC didn't need this, because it used doDMARead(), doDMAWrite(), doDMAFormat() helper functions, * 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 * 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(). * functions that delivered drive data with direct calls to readData() and writeData().
*/ */
drive.sector = null; drive.sector = null;
drive.ibSector = 0; drive.ibSector = 0;
@ -1856,7 +1856,7 @@ HDC.prototype.doATC = function()
this.printMessage("HDC.doRead(" + iDrive + ',' + drive.wCylinder + ':' + drive.bHead + ':' + drive.bSector + ',' + nSectors + ")", true); this.printMessage("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 * We're using a call to readData() 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 * byte of the next sector, we can signal an interrupt without also consuming the first byte, allowing
* inATCData() to begin with that byte. * inATCData() to begin with that byte.
* *
@ -1865,7 +1865,7 @@ HDC.prototype.doATC = function()
*/ */
hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ; hdc.regStatus = HDC.ATC.STATUS.BUSY | HDC.ATC.STATUS.DATA_REQ;
this.readByte(drive, function(b, fAsync) { this.readData(drive, function(b, fAsync) {
if (b >= 0 && hdc.chipset) { if (b >= 0 && hdc.chipset) {
hdc.setATCIRR(); hdc.setATCIRR();
hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK; hdc.regStatus = HDC.ATC.STATUS.READY | HDC.ATC.STATUS.SEEK_OK;
@ -2211,7 +2211,7 @@ HDC.prototype.pushResult = function(bResult)
HDC.prototype.dmaRead = function(drive, b, done) HDC.prototype.dmaRead = function(drive, b, done)
{ {
if (b === undefined || b < 0) { if (b === undefined || b < 0) {
this.readByte(drive, done); this.readData(drive, done);
return; return;
} }
/* /*
@ -2232,7 +2232,7 @@ HDC.prototype.dmaRead = function(drive, b, done)
HDC.prototype.dmaWrite = function(drive, b) HDC.prototype.dmaWrite = function(drive, b)
{ {
if (b !== undefined && b >= 0) if (b !== undefined && b >= 0)
return this.writeByte(drive, b); return this.writeData(drive, b);
/* /*
* The DMA controller should be GIVING us data, not ASKING for data; this suggests an internal DMA miscommunication * The DMA controller should be GIVING us data, not ASKING for data; this suggests an internal DMA miscommunication
*/ */
@ -2298,7 +2298,7 @@ HDC.prototype.doDMARead = function(drive, done)
if (this.chipset) { if (this.chipset) {
/* /*
* We need to reverse the original logic, and default to success unless/until an actual error occurs; * We need to reverse the original logic, and default to success unless/until an actual error occurs;
* otherwise dmaRead()/readByte() will bail on us. The original approach used to work because requestDMA() * otherwise dmaRead()/readData() will bail on us. The original approach used to work because requestDMA()
* would immediately call us back with fComplete set to true EVEN if the DMA channel was not yet unmasked; * would immediately call us back with fComplete set to true EVEN if the DMA channel was not yet unmasked;
* now the callback is deferred until the DMA channel has been unmasked and the DMA request has finished. * now the callback is deferred until the DMA channel has been unmasked and the DMA request has finished.
*/ */
@ -2342,7 +2342,7 @@ HDC.prototype.doDMAWrite = function(drive, done)
if (this.chipset) { if (this.chipset) {
/* /*
* We need to reverse the original logic, and default to success unless/until an actual error occurs; * We need to reverse the original logic, and default to success unless/until an actual error occurs;
* otherwise dmaWrite()/writeByte() will bail on us. The original approach would work because requestDMA() * otherwise dmaWrite()/writeData() will bail on us. The original approach would work because requestDMA()
* would immediately call us back with fComplete set to true EVEN if the DMA channel was not yet unmasked; * would immediately call us back with fComplete set to true EVEN if the DMA channel was not yet unmasked;
* now the callback is deferred until the DMA channel has been unmasked and the DMA request has finished. * now the callback is deferred until the DMA channel has been unmasked and the DMA request has finished.
*/ */
@ -2474,7 +2474,7 @@ HDC.prototype.doDMAFormat = function(drive, done)
*/ */
/** /**
* readByte(drive, done) * readData(drive, done)
* *
* The following drive variable properties must have been setup prior to our first call: * The following drive variable properties must have been setup prior to our first call:
* *
@ -2483,11 +2483,11 @@ HDC.prototype.doDMAFormat = function(drive, done)
* drive.bSector * drive.bSector
* drive.sector (initialized to null) * drive.sector (initialized to null)
* *
* On the first readByte() request, since drive.sector will be null, we ask the Disk object to look * On the first readData() request, since drive.sector will be null, we ask the Disk object to look
* up the first sector of the request. We then ask the Disk for bytes from that sector until the sector * up the first sector of the request. We then ask the Disk for bytes from that sector until the sector
* is exhausted, and then we look up the next sector and continue the process. * is exhausted, and then we look up the next sector and continue the process.
* *
* NOTE: Since the HDC isn't aware of the extent of the transfer, all readByte() can do is return bytes * NOTE: Since the HDC isn't aware of the extent of the transfer, all readData() can do is return bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted. * until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* *
* @this {HDC} * @this {HDC}
@ -2496,7 +2496,7 @@ HDC.prototype.doDMAFormat = function(drive, done)
* @param {boolean} [fAutoInc] (default is true to auto-increment) * @param {boolean} [fAutoInc] (default is true to auto-increment)
* @return {number} the requested byte, or -1 if unavailable * @return {number} the requested byte, or -1 if unavailable
*/ */
HDC.prototype.readByte = function(drive, done, fAutoInc) HDC.prototype.readData = function(drive, done, fAutoInc)
{ {
var b = -1; var b = -1;
var obj = null, off = 0; // these variables are purely for BACKTRACK purposes var obj = null, off = 0; // these variables are purely for BACKTRACK purposes
@ -2535,7 +2535,7 @@ HDC.prototype.readByte = function(drive, done, fAutoInc)
off = drive.ibSector = 0; off = drive.ibSector = 0;
/* /*
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek(). * We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
* This allows the initial call to readByte() to perform a seek without triggering an unwanted advance. * This allows the initial call to readData() to perform a seek without triggering an unwanted advance.
*/ */
hdc.advanceSector(drive); hdc.advanceSector(drive);
b = drive.disk.read(drive.sector, drive.ibSector); b = drive.disk.read(drive.sector, drive.ibSector);
@ -2554,7 +2554,7 @@ HDC.prototype.readByte = function(drive, done, fAutoInc)
}; };
/** /**
* writeByte(drive, b) * writeData(drive, b)
* *
* The following drive variable properties must have been setup prior to our first call: * The following drive variable properties must have been setup prior to our first call:
* *
@ -2563,11 +2563,11 @@ HDC.prototype.readByte = function(drive, done, fAutoInc)
* drive.bSector * drive.bSector
* drive.sector (initialized to null) * drive.sector (initialized to null)
* *
* On the first writeByte() request, since drive.sector will be null, we ask the Disk object to look * On the first writeData() request, since drive.sector will be null, we ask the Disk object to look
* up the first sector of the request. We then send the Disk bytes for that sector until the sector * up the first sector of the request. We then send the Disk bytes for that sector until the sector
* is full, and then we look up the next sector and continue the process. * is full, and then we look up the next sector and continue the process.
* *
* NOTE: Since the HDC isn't aware of the extent of the transfer, all writeByte() can do is accept bytes * NOTE: Since the HDC isn't aware of the extent of the transfer, all writeData() can do is accept bytes
* until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted. * until the current track (or, in the case of a multi-track request, the current cylinder) has been exhausted.
* *
* @this {HDC} * @this {HDC}
@ -2575,7 +2575,7 @@ HDC.prototype.readByte = function(drive, done, fAutoInc)
* @param {number} b containing next byte to write * @param {number} b containing next byte to write
* @return {number} (b unchanged; return -1 if command should be terminated) * @return {number} (b unchanged; return -1 if command should be terminated)
*/ */
HDC.prototype.writeByte = function(drive, b) HDC.prototype.writeData = function(drive, b)
{ {
if (drive.errorCode) return -1; if (drive.errorCode) return -1;
do { do {
@ -2603,7 +2603,7 @@ HDC.prototype.writeByte = function(drive, b)
drive.ibSector = 0; drive.ibSector = 0;
/* /*
* We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek(). * We "pre-advance" bSector et al now, instead of waiting to advance it right before the seek().
* This allows the initial call to writeByte() to perform a seek without triggering an unwanted advance. * This allows the initial call to writeData() to perform a seek without triggering an unwanted advance.
*/ */
this.advanceSector(drive); this.advanceSector(drive);
} while (true); } while (true);
@ -2691,7 +2691,7 @@ HDC.prototype.writeFormat = function(drive, b)
} }
for (var i = 0; i < drive.nBytes; i++) { for (var i = 0; i < drive.nBytes; i++) {
if (this.writeByte(drive, drive.bFiller) < 0) { if (this.writeData(drive, drive.bFiller) < 0) {
return -1; return -1;
} }
} }

View file

@ -30,22 +30,6 @@
* any copyright as to their contents. * any copyright as to their contents.
*/ */
/*
* Historical Notes
*
* To minimize possible future confusion with regard to the 80386's page tables
* and page-based virtual memory, the original Page component was converted into
* this new Memory component, which provides callers with "blocks" of physical
* memory rather than "pages". Callers have been updated to refer to their Memory
* allocations as "blocks" as well.
*
* Note that the Bus component continues to specify a default block size of 4Kb (for
* the default "buswidth" of 20), but only because that seems to strike a good balance
* between data structure overhead and the memory granularity requirements of most
* system components. For larger bus widths, larger physical block sizes may be used;
* see the Bus constructor for details.
*/
"use strict"; "use strict";
if (typeof module !== 'undefined') { if (typeof module !== 'undefined') {
@ -104,13 +88,14 @@ var littleEndian = (TYPEDARRAYS? (function() {
* is available). * is available).
* *
* @constructor * @constructor
* @param {number} [addr] of lowest used address in block * @param {number|null} [addr] of lowest used address in block
* @param {number} [used] portion of block in bytes (0 for none); must be a multiple of 4 * @param {number} [used] portion of block in bytes (0 for none); must be a multiple of 4
* @param {number} [size] of block's buffer in bytes (0 for none); must be a multiple of 4 * @param {number} [size] of block's buffer in bytes (0 for none); must be a multiple of 4
* @param {number} [type] is one of the Memory.TYPE constants (default is Memory.TYPE.NONE) * @param {number} [type] is one of the Memory.TYPE constants (default is Memory.TYPE.NONE)
* @param {Object} [controller] is an optional memory controller component * @param {Object} [controller] is an optional memory controller component
* @param {Bus} [bus]
*/ */
function Memory(addr, used, size, type, controller) function Memory(addr, used, size, type, controller, bus)
{ {
var i; var i;
this.id = (Memory.idBlock += 2); this.id = (Memory.idBlock += 2);
@ -122,6 +107,7 @@ function Memory(addr, used, size, type, controller)
this.type = type || Memory.TYPE.NONE; this.type = type || Memory.TYPE.NONE;
this.fReadOnly = (type == Memory.TYPE.ROM); this.fReadOnly = (type == Memory.TYPE.ROM);
this.controller = null; this.controller = null;
this.bus = bus;
this.fDirty = this.fDirtyEver = false; this.fDirty = this.fDirtyEver = false;
if (BACKTRACK) { if (BACKTRACK) {
@ -142,7 +128,7 @@ function Memory(addr, used, size, type, controller)
/* /*
* For empty memory blocks, all we need to do is ensure all access functions * For empty memory blocks, all we need to do is ensure all access functions
* are mapped to "none" handlers. * are mapped to "none" handlers (or "unpaged" handlers if paging is enabled).
*/ */
if (!size) { if (!size) {
this.setAccess(); this.setAccess();
@ -168,7 +154,7 @@ function Memory(addr, used, size, type, controller)
* know how to deal with this simple 1-1 mapping of addresses to bytes and words. * know how to deal with this simple 1-1 mapping of addresses to bytes and words.
* *
* TODO: Consider initializing the memory array to random (or pseudo-random) values in DEBUG * TODO: Consider initializing the memory array to random (or pseudo-random) values in DEBUG
* mode; pseudo-random might be best, because if it uncovers a bug, the bug should be reproducible. * mode; pseudo-random might be best, to help make any bugs reproducible.
*/ */
if (TYPEDARRAYS) { if (TYPEDARRAYS) {
this.buffer = new ArrayBuffer(size); this.buffer = new ArrayBuffer(size);
@ -220,6 +206,7 @@ Memory.TYPE = {
ROM: 2, ROM: 2,
VIDEO: 3, VIDEO: 3,
CTRL: 4, CTRL: 4,
UNPAGED:5,
NAMES: ["NONE", "RAM", "ROM", "VIDEO", "H/W"], NAMES: ["NONE", "RAM", "ROM", "VIDEO", "H/W"],
COLORS: ["black", "blue", "green", "cyan"] COLORS: ["black", "blue", "green", "cyan"]
}; };
@ -367,12 +354,14 @@ Memory.prototype = {
/** /**
* setAccess(afn) * setAccess(afn)
* *
* If no afn is specified, a default is selected based on the Memory type.
*
* @this {Memory} * @this {Memory}
* @param {Array.<function()>} [afn] * @param {Array.<function()>} [afn]
* @param {boolean} [fDirect] * @param {boolean} [fDirect]
*/ */
setAccess: function(afn, fDirect) { setAccess: function(afn, fDirect) {
if (!afn) afn = []; afn = afn || (this.type == Memory.TYPE.UNPAGED? Memory.afnUnpaged : Memory.afnNone);
if (fDirect === undefined) fDirect = true; // TODO: Verify that this is desired default behavior if (fDirect === undefined) fDirect = true; // TODO: Verify that this is desired default behavior
this.setReadAccess(afn, fDirect); this.setReadAccess(afn, fDirect);
this.setWriteAccess(afn, fDirect); this.setWriteAccess(afn, fDirect);
@ -432,23 +421,31 @@ Memory.prototype = {
this.writeLong = this.fReadOnly? this.writeNone : this.writeLongDirect; this.writeLong = this.fReadOnly? this.writeNone : this.writeLongDirect;
}, },
/** /**
* setDebugInfo(cpu, dbg, addr, size) * setDebugger(dbg, addr, size)
* *
* @this {Memory} * @this {Memory}
* @param {X86CPU|Component} cpu
* @param {Debugger|Component} dbg * @param {Debugger|Component} dbg
* @param {number} addr of block * @param {number} addr of block
* @param {number} size of block * @param {number} size of block
*/ */
setDebugInfo: function(cpu, dbg, addr, size) { setDebugger: function(dbg, addr, size) {
if (DEBUGGER) { if (DEBUGGER) {
this.cpu = cpu;
this.dbg = dbg; this.dbg = dbg;
this.cReadBreakpoints = this.cWriteBreakpoints = 0; this.cReadBreakpoints = this.cWriteBreakpoints = 0;
Component.assert(this.dbg); Component.assert(this.dbg);
this.dbg.redoBreakpoints(addr, size); this.dbg.redoBreakpoints(addr, size);
} }
}, },
/**
* setPageBlock(addr)
*
* @this {Memory}
* @param {number} addr
* @return {Memory}
*/
setPageBlock: function(addr) {
return this.bus.mapPageBlock(addr);
},
/** /**
* addBreakpoint(off, fWrite) * addBreakpoint(off, fWrite)
* *
@ -514,85 +511,86 @@ Memory.prototype = {
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readNone: function readNone(off) { readNone: function readNone(off, addr) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.MEM) /* && !off */) { if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr) + " from " + this.dbg.hexOffset(this.cpu.getIP(), this.cpu.getCS())); this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr), true);
} }
return 0xff; return 0xff;
}, },
/** /**
* writeNone(off, v) * writeNone(off, v, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses) * @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
* @param {number} addr
*/ */
writeNone: function writeNone(off, v) writeNone: function writeNone(off, v, addr) {
{
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.MEM) /* && !off */) { if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.MEM) /* && !off */) {
this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true); this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
} }
}, },
/** /**
* readShortDefault(off) * readShortDefault(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readShortDefault: function readShortDefault(off) readShortDefault: function readShortDefault(off, addr) {
{ return this.readByteDirect(off, addr) | (this.readByteDirect(off + 1, addr) << 8);
return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8);
}, },
/** /**
* readLongDefault(off) * readLongDefault(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readLongDefault: function readLongDefault(off) readLongDefault: function readLongDefault(off, addr) {
{ return this.readByteDirect(off, addr) | (this.readByteDirect(off + 1, addr) << 8) | (this.readByteDirect(off + 2, addr) << 16) | (this.readByteDirect(off + 3, addr) << 24);
return this.readByteDirect(off) | (this.readByteDirect(off + 1) << 8) | (this.readByteDirect(off + 2) << 16) | (this.readByteDirect(off + 3) << 24);
}, },
/** /**
* writeShortDefault(off, w) * writeShortDefault(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} w * @param {number} w
* @param {number} addr
*/ */
writeShortDefault: function writeShortDefault(off, w) writeShortDefault: function writeShortDefault(off, w, addr) {
{
Component.assert(!(w & ~0xffff)); Component.assert(!(w & ~0xffff));
this.writeByteDirect(off, w & 0xff); this.writeByteDirect(off, w & 0xff);
this.writeByteDirect(off + 1, w >> 8); this.writeByteDirect(off + 1, w >> 8);
}, },
/** /**
* writeLongDefault(off, w) * writeLongDefault(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} w * @param {number} w
* @param {number} addr
*/ */
writeLongDefault: function writeLongDefault(off, w) writeLongDefault: function writeLongDefault(off, w, addr) {
{
this.writeByteDirect(off, w & 0xff); this.writeByteDirect(off, w & 0xff);
this.writeByteDirect(off + 1, (w >> 8) & 0xff); this.writeByteDirect(off + 1, (w >> 8) & 0xff);
this.writeByteDirect(off + 2, (w >> 16) & 0xff); this.writeByteDirect(off + 2, (w >> 16) & 0xff);
this.writeByteDirect(off + 3, (w >>> 24)); this.writeByteDirect(off + 3, (w >>> 24));
}, },
/** /**
* readByteMemory(off) * readByteMemory(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readByteMemory: function readByteMemory(off) readByteMemory: function readByteMemory(off, addr) {
{
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
if (FATARRAYS) { if (FATARRAYS) {
return this.ab[off]; return this.ab[off];
@ -600,14 +598,14 @@ Memory.prototype = {
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff); return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
}, },
/** /**
* readShortMemory(off) * readShortMemory(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readShortMemory: function readShortMemory(off) readShortMemory: function readShortMemory(off, addr) {
{
Component.assert(off >= 0 && off < this.size - 1); Component.assert(off >= 0 && off < this.size - 1);
if (FATARRAYS) { if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8); return this.ab[off] | (this.ab[off + 1] << 8);
@ -624,14 +622,14 @@ Memory.prototype = {
return w; return w;
}, },
/** /**
* readLongMemory(off) * readLongMemory(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readLongMemory: function readLongMemory(off) readLongMemory: function readLongMemory(off, addr) {
{
Component.assert(off >= 0 && off < this.size - 3); Component.assert(off >= 0 && off < this.size - 3);
if (FATARRAYS) { if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24); return this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24);
@ -646,14 +644,14 @@ Memory.prototype = {
return l; return l;
}, },
/** /**
* writeByteMemory(off, b) * writeByteMemory(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b * @param {number} b
* @param {number} addr
*/ */
writeByteMemory: function writeByteMemory(off, b) writeByteMemory: function writeByteMemory(off, b, addr) {
{
Component.assert(off >= 0 && off < this.size && (b & 0xff) == b); Component.assert(off >= 0 && off < this.size && (b & 0xff) == b);
if (FATARRAYS) { if (FATARRAYS) {
this.ab[off] = b; this.ab[off] = b;
@ -665,14 +663,14 @@ Memory.prototype = {
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeShortMemory(off, w) * writeShortMemory(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} w * @param {number} w
* @param {number} addr
*/ */
writeShortMemory: function writeShortMemory(off, w) writeShortMemory: function writeShortMemory(off, w, addr) {
{
Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w); Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w);
if (FATARRAYS) { if (FATARRAYS) {
this.ab[off] = (w & 0xff); this.ab[off] = (w & 0xff);
@ -696,14 +694,14 @@ Memory.prototype = {
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeLongMemory(off, l) * writeLongMemory(off, l, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} l * @param {number} l
* @param {number} addr
*/ */
writeLongMemory: function writeLongMemory(off, l) writeLongMemory: function writeLongMemory(off, l, addr) {
{
Component.assert(off >= 0 && off < this.size - 3); Component.assert(off >= 0 && off < this.size - 3);
if (FATARRAYS) { if (FATARRAYS) {
this.ab[off] = (l & 0xff); this.ab[off] = (l & 0xff);
@ -730,85 +728,85 @@ Memory.prototype = {
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* readByteChecked(off) * readByteChecked(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readByteChecked: function readByteChecked(off) readByteChecked: function readByteChecked(off, addr) {
{ if (DEBUGGER && this.dbg) this.dbg.checkMemoryRead(addr);
if (DEBUGGER && this.dbg) this.dbg.checkMemoryRead(this.addr + off); return this.readByteDirect(off, addr);
return this.readByteDirect(off);
}, },
/** /**
* readShortChecked(off) * readShortChecked(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readShortChecked: function readShortChecked(off) readShortChecked: function readShortChecked(off, addr) {
{
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
this.dbg.checkMemoryRead(this.addr + off) || this.dbg.checkMemoryRead(addr) ||
this.dbg.checkMemoryRead(this.addr + off + 1); this.dbg.checkMemoryRead(addr + 1);
} }
return this.readShortDirect(off); return this.readShortDirect(off, addr);
}, },
/** /**
* readLongChecked(off) * readLongChecked(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readLongChecked: function readLongChecked(off) readLongChecked: function readLongChecked(off, addr) {
{
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
this.dbg.checkMemoryRead(this.addr + off) || this.dbg.checkMemoryRead(addr) ||
this.dbg.checkMemoryRead(this.addr + off + 1) || this.dbg.checkMemoryRead(addr + 1) ||
this.dbg.checkMemoryRead(this.addr + off + 2) || this.dbg.checkMemoryRead(addr + 2) ||
this.dbg.checkMemoryRead(this.addr + off + 3); this.dbg.checkMemoryRead(addr + 3);
} }
return this.readLongDirect(off); return this.readLongDirect(off, addr);
}, },
/** /**
* writeByteChecked(off, b) * writeByteChecked(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @param {number} b * @param {number} b
*/ */
writeByteChecked: function writeByteChecked(off, b) writeByteChecked: function writeByteChecked(off, b, addr) {
{ if (DEBUGGER && this.dbg) this.dbg.checkMemoryWrite(addr);
if (DEBUGGER && this.dbg) this.dbg.checkMemoryWrite(this.addr + off); this.writeByteDirect(off, b, addr);
this.writeByteDirect(off, b);
}, },
/** /**
* writeShortChecked(off, w) * writeShortChecked(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @param {number} w * @param {number} w
*/ */
writeShortChecked: function writeShortChecked(off, w) writeShortChecked: function writeShortChecked(off, w, addr) {
{
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
this.dbg.checkMemoryWrite(this.addr + off) || this.dbg.checkMemoryWrite(addr) ||
this.dbg.checkMemoryWrite(this.addr + off + 1); this.dbg.checkMemoryWrite(addr + 1);
} }
this.writeShortDirect(off, w); this.writeShortDirect(off, w, addr);
}, },
/** /**
* writeLongChecked(off, l) * writeLongChecked(off, l, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} l * @param {number} l
* @param {number} addr
*/ */
writeLongChecked: function writeLongChecked(off, l) writeLongChecked: function writeLongChecked(off, l, addr) {
{
if (DEBUGGER && this.dbg) { if (DEBUGGER && this.dbg) {
this.dbg.checkMemoryWrite(this.addr + off) || this.dbg.checkMemoryWrite(this.addr + off) ||
this.dbg.checkMemoryWrite(this.addr + off + 1) || this.dbg.checkMemoryWrite(this.addr + off + 1) ||
@ -818,50 +816,116 @@ Memory.prototype = {
this.writeLongDirect(off, l); this.writeLongDirect(off, l);
}, },
/** /**
* readByteBigEndian(off) * readByteUnpaged(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readByteBigEndian: function readByteBigEndian(off) readByteUnpaged: function readByteUnpaged(off, addr) {
{ return this.setPageBlock(addr).readByte(off, addr);
},
/**
* readShortUnpaged(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readShortUnpaged: function readShortUnpaged(off, addr) {
return this.setPageBlock(addr).readShort(off, addr);
},
/**
* readLongUnpaged(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongUnpaged: function readLongUnpaged(off, addr) {
return this.setPageBlock(addr).readLong(off, addr);
},
/**
* writeByteUnpaged(off, b, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} b
* @param {number} addr
*/
writeByteUnpaged: function writeByteUnpaged(off, b, addr) {
this.setPageBlock(addr).writeByte(off, b, addr);
},
/**
* writeShortUnpaged(off, w, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} w
* @param {number} addr
*/
writeShortUnpaged: function writeShortUnpaged(off, w, addr) {
this.setPageBlock(addr).writeShort(off, w, addr);
},
/**
* writeLongUnpaged(off, l, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} l
* @param {number} addr
*/
writeLongUnpaged: function writeLongUnpaged(off, l, addr) {
this.setPageBlock(addr).writeLong(off, l, addr);
},
/**
* readByteBigEndian(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readByteBigEndian: function readByteBigEndian(off, addr) {
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
return this.ab[off]; return this.ab[off];
}, },
/** /**
* readByteLittleEndian(off) * readByteLittleEndian(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readByteLittleEndian: function readByteLittleEndian(off) readByteLittleEndian: function readByteLittleEndian(off, addr) {
{
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
return this.ab[off]; return this.ab[off];
}, },
/** /**
* readShortBigEndian(off) * readShortBigEndian(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readShortBigEndian: function readShortBigEndian(off) readShortBigEndian: function readShortBigEndian(off, addr) {
{
Component.assert(off >= 0 && off < this.size - 1); Component.assert(off >= 0 && off < this.size - 1);
return this.dv.getUint16(off, true); return this.dv.getUint16(off, true);
}, },
/** /**
* readShortLittleEndian(off) * readShortLittleEndian(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readShortLittleEndian: function readShortLittleEndian(off) readShortLittleEndian: function readShortLittleEndian(off, addr) {
{
Component.assert(off >= 0 && off < this.size - 1); Component.assert(off >= 0 && off < this.size - 1);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset * TODO: It remains to be seen if there's any advantage to checking the offset
@ -871,26 +935,26 @@ Memory.prototype = {
return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1]; return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1];
}, },
/** /**
* readLongBigEndian(off) * readLongBigEndian(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readLongBigEndian: function readLongBigEndian(off) readLongBigEndian: function readLongBigEndian(off, addr) {
{
Component.assert(off >= 0 && off < this.size - 3); Component.assert(off >= 0 && off < this.size - 3);
return this.dv.getInt32(off, true); return this.dv.getInt32(off, true);
}, },
/** /**
* readLongLittleEndian(off) * readLongLittleEndian(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @return {number} * @return {number}
*/ */
readLongLittleEndian: function readLongLittleEndian(off) readLongLittleEndian: function readLongLittleEndian(off, addr) {
{
Component.assert(off >= 0 && off < this.size - 3); Component.assert(off >= 0 && off < this.size - 3);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset * TODO: It remains to be seen if there's any advantage to checking the offset
@ -900,53 +964,53 @@ Memory.prototype = {
return (off & 0x3)? (this.ab[off] | (this.ab[off+1] << 8) | (this.ab[off+2] << 16) | (this.ab[off+3] << 24)) : this.adw[off >> 2]; return (off & 0x3)? (this.ab[off] | (this.ab[off+1] << 8) | (this.ab[off+2] << 16) | (this.ab[off+3] << 24)) : this.adw[off >> 2];
}, },
/** /**
* writeByteBigEndian(off, b) * writeByteBigEndian(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b * @param {number} b
* @param {number} addr
*/ */
writeByteBigEndian: function writeByteBigEndian(off, b) writeByteBigEndian: function writeByteBigEndian(off, b, addr) {
{
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
this.ab[off] = b; this.ab[off] = b;
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeByteLittleEndian(off, b) * writeByteLittleEndian(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @param {number} b * @param {number} b
*/ */
writeByteLittleEndian: function writeByteLittleEndian(off, b) writeByteLittleEndian: function writeByteLittleEndian(off, b, addr) {
{
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
this.ab[off] = b; this.ab[off] = b;
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeShortBigEndian(off, w) * writeShortBigEndian(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @param {number} w * @param {number} w
*/ */
writeShortBigEndian: function writeShortBigEndian(off, w) writeShortBigEndian: function writeShortBigEndian(off, w, addr) {
{
Component.assert(off >= 0 && off < this.size - 1); Component.assert(off >= 0 && off < this.size - 1);
this.dv.setUint16(off, w, true); this.dv.setUint16(off, w, true);
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeShortLittleEndian(off, w) * writeShortLittleEndian(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr
* @param {number} w * @param {number} w
*/ */
writeShortLittleEndian: function writeShortLittleEndian(off, w) writeShortLittleEndian: function writeShortLittleEndian(off, w, addr) {
{
Component.assert(off >= 0 && off < this.size - 1); Component.assert(off >= 0 && off < this.size - 1);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset * TODO: It remains to be seen if there's any advantage to checking the offset
@ -962,27 +1026,27 @@ Memory.prototype = {
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeLongBigEndian(off, l) * writeLongBigEndian(off, l, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} l * @param {number} l
* @param {number} addr
*/ */
writeLongBigEndian: function writeLongBigEndian(off, l) writeLongBigEndian: function writeLongBigEndian(off, l, addr) {
{
Component.assert(off >= 0 && off < this.size - 3); Component.assert(off >= 0 && off < this.size - 3);
this.dv.setInt32(off, l, true); this.dv.setInt32(off, l, true);
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeLongLittleEndian(off, l) * writeLongLittleEndian(off, l, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} l * @param {number} l
* @param {number} addr
*/ */
writeLongLittleEndian: function writeLongLittleEndian(off, l) writeLongLittleEndian: function writeLongLittleEndian(off, l, addr) {
{
Component.assert(off >= 0 && off < this.size - 3); Component.assert(off >= 0 && off < this.size - 3);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset * TODO: It remains to be seen if there's any advantage to checking the offset
@ -1006,8 +1070,7 @@ Memory.prototype = {
* @param {number} off * @param {number} off
* @return {number} * @return {number}
*/ */
readBackTrackNone: function readBackTrackNone(off) readBackTrackNone: function readBackTrackNone(off) {
{
return 0; return 0;
}, },
/** /**
@ -1017,8 +1080,7 @@ Memory.prototype = {
* @param {number} off * @param {number} off
* @param {number} bti * @param {number} bti
*/ */
writeBackTrackNone: function writeBackTrackNone(off, bti) writeBackTrackNone: function writeBackTrackNone(off, bti) {
{
}, },
/** /**
* modBackTrackNone(fMod) * modBackTrackNone(fMod)
@ -1026,8 +1088,7 @@ Memory.prototype = {
* @this {Memory} * @this {Memory}
* @param {boolean} fMod * @param {boolean} fMod
*/ */
modBackTrackNone: function modBackTrackNone(fMod) modBackTrackNone: function modBackTrackNone(fMod) {
{
return false; return false;
}, },
/** /**
@ -1037,8 +1098,7 @@ Memory.prototype = {
* @param {number} off * @param {number} off
* @return {number} * @return {number}
*/ */
readBackTrackIndex: function readBackTrackIndex(off) readBackTrackIndex: function readBackTrackIndex(off) {
{
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
return this.abtIndexes[off]; return this.abtIndexes[off];
}, },
@ -1050,8 +1110,7 @@ Memory.prototype = {
* @param {number} bti * @param {number} bti
* @return {number} previous bti (0 if none) * @return {number} previous bti (0 if none)
*/ */
writeBackTrackIndex: function writeBackTrackIndex(off, bti) writeBackTrackIndex: function writeBackTrackIndex(off, bti) {
{
var btiPrev; var btiPrev;
Component.assert(off >= 0 && off < this.size); Component.assert(off >= 0 && off < this.size);
btiPrev = this.abtIndexes[off]; btiPrev = this.abtIndexes[off];
@ -1065,20 +1124,32 @@ Memory.prototype = {
* @param {boolean} fMod * @param {boolean} fMod
* @return {boolean} previous value * @return {boolean} previous value
*/ */
modBackTrackIndex: function modBackTrackIndex(fMod) modBackTrackIndex: function modBackTrackIndex(fMod) {
{
var fModPrev = this.fModBackTrack; var fModPrev = this.fModBackTrack;
this.fModBackTrack = fMod; this.fModBackTrack = fMod;
return fModPrev; return fModPrev;
} }
}; };
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.readLongMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory, Memory.prototype.writeLongMemory]; /*
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked]; * This is the effective definition of afnNone, but we need not fully define it, because setAccess() already
* uses these defaults when any of the 6 handlers (ie, 3 read handlers followed by 3 write handlers) are undefined.
*
Memory.afnNone = [Memory.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.readLongDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault, Memory.prototype.writeLongDefault];
*/
Memory.afnNone = [];
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.readLongMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory, Memory.prototype.writeLongMemory];
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
if (PAGEBLOCKS) {
// Memory.afnPaged = [Memory.prototype.readBytePaged, Memory.prototype.readShortPaged, Memory.prototype.readLongPaged, Memory.prototype.writeBytePaged, Memory.prototype.writeShortPaged, Memory.prototype.writeLongPaged];
Memory.afnUnpaged = [Memory.prototype.readByteUnpaged, Memory.prototype.readShortUnpaged, Memory.prototype.readLongUnpaged, Memory.prototype.writeByteUnpaged, Memory.prototype.writeShortUnpaged, Memory.prototype.writeLongUnpaged];
}
if (TYPEDARRAYS) { if (TYPEDARRAYS) {
Memory.afnBigEndian = [Memory.prototype.readByteBigEndian, Memory.prototype.readShortBigEndian, Memory.prototype.readLongBigEndian, Memory.prototype.writeByteBigEndian, Memory.prototype.writeShortBigEndian, Memory.prototype.writeLongBigEndian]; Memory.afnBigEndian = [Memory.prototype.readByteBigEndian, Memory.prototype.readShortBigEndian, Memory.prototype.readLongBigEndian, Memory.prototype.writeByteBigEndian, Memory.prototype.writeShortBigEndian, Memory.prototype.writeLongBigEndian];
Memory.afnLittleEndian = [Memory.prototype.readByteLittleEndian, Memory.prototype.readShortLittleEndian, Memory.prototype.readLongLittleEndian, Memory.prototype.writeByteLittleEndian, Memory.prototype.writeShortLittleEndian, Memory.prototype.writeLongLittleEndian]; Memory.afnLittleEndian = [Memory.prototype.readByteLittleEndian, Memory.prototype.readShortLittleEndian, Memory.prototype.readLongLittleEndian, Memory.prototype.writeByteLittleEndian, Memory.prototype.writeShortLittleEndian, Memory.prototype.writeLongLittleEndian];
} }
if (typeof module !== 'undefined') module.exports = Memory; if (typeof module !== 'undefined') module.exports = Memory;

View file

@ -383,13 +383,14 @@ CompaqController.RAMSETUP = {
}; };
/** /**
* readByte(off) * readByte(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off (relative to 0x80C00000) * @param {number} off (relative to 0x80C00000)
* @param {number} [addr]
* @return {number} * @return {number}
*/ */
CompaqController.readByte = function readCompaqControllerByte(off) CompaqController.readByte = function readCompaqControllerByte(off, addr)
{ {
var b = 0xff; var b = 0xff;
if (off < 0x02) { if (off < 0x02) {
@ -400,19 +401,20 @@ CompaqController.readByte = function readCompaqControllerByte(off)
} }
if (DEBUG) { if (DEBUG) {
this.controller.ram.printMessage("CompaqController.readByte(" + str.toHexWord(off) + ") returned " + str.toHexByte(b), true, true); this.controller.ram.printMessage("CompaqController.readByte(" + str.toHexWord(off) + ") returned " + str.toHexByte(b), true, true);
if (MAXDEBUG && DEBUGGER && off >= 0x2) this.cpu.stopCPU(); if (MAXDEBUG && DEBUGGER && off >= 0x2) this.dbg.stopCPU();
} }
return b; return b;
}; };
/** /**
* writeByte(off, b) * writeByte(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off (relative to 0x80C00000) * @param {number} off (relative to 0x80C00000)
* @param {number} b * @param {number} b
* @param {number} [addr]
*/ */
CompaqController.writeByte = function writeCompaqControllerByte(off, b) CompaqController.writeByte = function writeCompaqControllerByte(off, b, addr)
{ {
var controller = this.controller; var controller = this.controller;
@ -443,7 +445,7 @@ CompaqController.writeByte = function writeCompaqControllerByte(off, b)
} }
} }
controller.wMappings = (controller.wMappings & ~0xff) | b; controller.wMappings = (controller.wMappings & ~0xff) | b;
if (MAXDEBUG && DEBUGGER) this.cpu.stopCPU(); if (MAXDEBUG && DEBUGGER) this.dbg.stopCPU();
} }
} }
/* /*
@ -451,7 +453,7 @@ CompaqController.writeByte = function writeCompaqControllerByte(off, b)
*/ */
else if (off == 0x2) { else if (off == 0x2) {
controller.wRAMSetup = (controller.wRAMSetup & ~0xff) | b; controller.wRAMSetup = (controller.wRAMSetup & ~0xff) | b;
if (MAXDEBUG && DEBUGGER) this.cpu.stopCPU(); if (MAXDEBUG && DEBUGGER) this.dbg.stopCPU();
} }
/* /*
* All bits in 0x80C00001 and 0x80C00003 are reserved, so we can simply ignore those writes. * All bits in 0x80C00001 and 0x80C00003 are reserved, so we can simply ignore those writes.

View file

@ -1241,13 +1241,14 @@ Card.ACCESS.WRITE.MODE2XOR = 0xE000;
Card.ACCESS.WRITE.MASK = 0xff00; Card.ACCESS.WRITE.MASK = 0xff00;
/** /**
* readByteMode0(off) * readByteMode0(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} [addr]
* @return {number} * @return {number}
*/ */
Card.ACCESS.readByteMode0 = function readByteMode0(off) Card.ACCESS.readByteMode0 = function readByteMode0(off, addr)
{ {
off += this.offset; off += this.offset;
var dw = this.controller.latches = this.adw[off]; var dw = this.controller.latches = this.adw[off];
@ -1255,13 +1256,14 @@ Card.ACCESS.readByteMode0 = function readByteMode0(off)
}; };
/** /**
* readByteMode0EvenOdd(off) * readByteMode0EvenOdd(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} [addr]
* @return {number} * @return {number}
*/ */
Card.ACCESS.readByteMode0EvenOdd = function readByteMode0EvenOdd(off) Card.ACCESS.readByteMode0EvenOdd = function readByteMode0EvenOdd(off, addr)
{ {
off += this.offset; off += this.offset;
var idw = off & ~0x1; var idw = off & ~0x1;
@ -1269,13 +1271,14 @@ Card.ACCESS.readByteMode0EvenOdd = function readByteMode0EvenOdd(off)
}; };
/** /**
* readByteMode1(off) * readByteMode1(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} [addr]
* @return {number} * @return {number}
*/ */
Card.ACCESS.readByteMode1 = function readByteMode1(off) Card.ACCESS.readByteMode1 = function readByteMode1(off, addr)
{ {
off += this.offset; off += this.offset;
var dw = this.adw[off]; var dw = this.adw[off];
@ -1290,13 +1293,14 @@ Card.ACCESS.readByteMode1 = function readByteMode1(off)
}; };
/** /**
* writeByteMode0(off, b) * writeByteMode0(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode0 = function writeByteMode0(off, b) Card.ACCESS.writeByteMode0 = function writeByteMode0(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
var dw = b | (b << 8) | (b << 16) | (b << 24); var dw = b | (b << 8) | (b << 16) | (b << 24);
@ -1309,13 +1313,14 @@ Card.ACCESS.writeByteMode0 = function writeByteMode0(off, b)
}; };
/** /**
* writeByteMode0EvenOdd(off, b) * writeByteMode0EvenOdd(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode0EvenOdd = function writeByteMode0EvenOdd(off, b) Card.ACCESS.writeByteMode0EvenOdd = function writeByteMode0EvenOdd(off, b, addr)
{ {
off += this.offset; off += this.offset;
var dw = b | (b << 8) | (b << 16) | (b << 24); var dw = b | (b << 8) | (b << 16) | (b << 24);
@ -1334,7 +1339,7 @@ Card.ACCESS.writeByteMode0EvenOdd = function writeByteMode0EvenOdd(off, b)
}; };
/** /**
* writeByteMode0Rot(off, b) * writeByteMode0Rot(off, b, addr)
* *
* Supporting Set/Reset means that for every plane for which Set/Reset is enabled, we must * Supporting Set/Reset means that for every plane for which Set/Reset is enabled, we must
* replace the corresponding byte in "dw" with a byte of zeros or ones. This is accomplished with * replace the corresponding byte in "dw" with a byte of zeros or ones. This is accomplished with
@ -1352,8 +1357,9 @@ Card.ACCESS.writeByteMode0EvenOdd = function writeByteMode0EvenOdd(off, b)
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode0Rot = function writeByteMode0Rot(off, b) Card.ACCESS.writeByteMode0Rot = function writeByteMode0Rot(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff); b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff);
@ -1368,13 +1374,14 @@ Card.ACCESS.writeByteMode0Rot = function writeByteMode0Rot(off, b)
}; };
/** /**
* writeByteMode0And(off, b) * writeByteMode0And(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode0And = function writeByteMode0And(off, b) Card.ACCESS.writeByteMode0And = function writeByteMode0And(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff); b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff);
@ -1390,13 +1397,14 @@ Card.ACCESS.writeByteMode0And = function writeByteMode0And(off, b)
}; };
/** /**
* writeByteMode0Or(off, b) * writeByteMode0Or(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode0Or = function writeByteMode0Or(off, b) Card.ACCESS.writeByteMode0Or = function writeByteMode0Or(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff); b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff);
@ -1412,13 +1420,14 @@ Card.ACCESS.writeByteMode0Or = function writeByteMode0Or(off, b)
}; };
/** /**
* writeByteMode0Xor(off, b) * writeByteMode0Xor(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode0Xor = function writeByteMode0Xor(off, b) Card.ACCESS.writeByteMode0Xor = function writeByteMode0Xor(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff); b = ((b >> this.controller.nDataRotate) | (b << (8 - this.controller.nDataRotate)) & 0xff);
@ -1434,13 +1443,14 @@ Card.ACCESS.writeByteMode0Xor = function writeByteMode0Xor(off, b)
}; };
/** /**
* writeByteMode1(off, b) * writeByteMode1(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (ignored; the EGA latches provide the source data) * @param {number} b (ignored; the EGA latches provide the source data)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode1 = function writeByteMode1(off, b) Card.ACCESS.writeByteMode1 = function writeByteMode1(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
var dw = (this.adw[idw] & ~this.controller.nWriteMapMask) | (this.controller.latches & this.controller.nWriteMapMask); var dw = (this.adw[idw] & ~this.controller.nWriteMapMask) | (this.controller.latches & this.controller.nWriteMapMask);
@ -1451,13 +1461,14 @@ Card.ACCESS.writeByteMode1 = function writeByteMode1(off, b)
}; };
/** /**
* writeByteMode2(off, b) * writeByteMode2(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode2 = function writeByteMode2(off, b) Card.ACCESS.writeByteMode2 = function writeByteMode2(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
var dw = Video.aEGAByteToDW[b & 0xf]; var dw = Video.aEGAByteToDW[b & 0xf];
@ -1470,13 +1481,14 @@ Card.ACCESS.writeByteMode2 = function writeByteMode2(off, b)
}; };
/** /**
* writeByteMode2And(off, b) * writeByteMode2And(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode2And = function writeByteMode2And(off, b) Card.ACCESS.writeByteMode2And = function writeByteMode2And(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
var dw = Video.aEGAByteToDW[b & 0xf]; var dw = Video.aEGAByteToDW[b & 0xf];
@ -1490,13 +1502,14 @@ Card.ACCESS.writeByteMode2And = function writeByteMode2And(off, b)
}; };
/** /**
* writeByteMode2Or(off, b) * writeByteMode2Or(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode2Or = function writeByteMode2Or(off, b) Card.ACCESS.writeByteMode2Or = function writeByteMode2Or(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
var dw = Video.aEGAByteToDW[b & 0xf]; var dw = Video.aEGAByteToDW[b & 0xf];
@ -1510,13 +1523,14 @@ Card.ACCESS.writeByteMode2Or = function writeByteMode2Or(off, b)
}; };
/** /**
* writeByteMode2Xor(off, b) * writeByteMode2Xor(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect) * @param {number} b (which should already be pre-masked to 8 bits; see Bus.prototype.setByteDirect)
* @param {number} [addr]
*/ */
Card.ACCESS.writeByteMode2Xor = function writeByteMode2Xor(off, b) Card.ACCESS.writeByteMode2Xor = function writeByteMode2Xor(off, b, addr)
{ {
var idw = off + this.offset; var idw = off + this.offset;
var dw = Video.aEGAByteToDW[b & 0xf]; var dw = Video.aEGAByteToDW[b & 0xf];

View file

@ -2525,7 +2525,7 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
X86CPU.prototype.getByte = function(addr) X86CPU.prototype.getByte = function(addr)
{ {
if (BACKTRACK) this.backTrack.btiMemLo = this.bus.readBackTrack(addr); if (BACKTRACK) this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit); return this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr);
}; };
/** /**
@ -2550,9 +2550,9 @@ X86CPU.prototype.getShort = function(addr)
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1); this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
} }
if (off < this.blockLimit) { if (off < this.blockLimit) {
return this.aMemBlocks[iBlock].readShort(off); return this.aMemBlocks[iBlock].readShort(off, addr);
} }
return this.aMemBlocks[iBlock].readByte(off) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readByte(0) << 8); return this.aMemBlocks[iBlock].readByte(off, addr) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readByte(0, addr + 1) << 8);
}; };
/** /**
@ -2571,10 +2571,10 @@ X86CPU.prototype.getLong = function(addr)
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1); this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
} }
if (off < this.blockLimit - 2) { if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLong(off); return this.aMemBlocks[iBlock].readLong(off, addr);
} }
var nShift = (off & 0x3) << 3; var nShift = (off & 0x3) << 3;
return (this.aMemBlocks[iBlock].readLong(off & ~0x3) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLong(0) << (32 - nShift)); return (this.aMemBlocks[iBlock].readLong(off & ~0x3, addr) >>> nShift) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readLong(0, addr + 3) << (32 - nShift));
}; };
/** /**
@ -2587,7 +2587,7 @@ X86CPU.prototype.getLong = function(addr)
X86CPU.prototype.setByte = function(addr, b) X86CPU.prototype.setByte = function(addr, b)
{ {
if (BACKTRACK) this.bus.writeBackTrack(addr, this.backTrack.btiMemLo); if (BACKTRACK) this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff); this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff, addr);
}; };
/** /**
@ -2612,11 +2612,11 @@ X86CPU.prototype.setShort = function(addr, w)
this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi); this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi);
} }
if (off < this.blockLimit) { if (off < this.blockLimit) {
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff); this.aMemBlocks[iBlock].writeShort(off, w & 0xffff, addr);
return; return;
} }
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff); this.aMemBlocks[iBlock++].writeByte(off, w & 0xff, addr);
this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff); this.aMemBlocks[iBlock & this.blockMask].writeByte(0, (w >> 8) & 0xff, addr + 1);
}; };
/** /**
@ -2637,16 +2637,17 @@ X86CPU.prototype.setLong = function(addr, l)
this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi); this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi);
} }
if (off < this.blockLimit - 2) { if (off < this.blockLimit - 2) {
this.aMemBlocks[iBlock].writeLong(off, l); this.aMemBlocks[iBlock].writeLong(off, l, addr);
return; return;
} }
var lPrev, nShift = (off & 0x3) << 3; var lPrev, nShift = (off & 0x3) << 3;
off &= ~0x3; off &= ~0x3;
lPrev = this.aMemBlocks[iBlock].readLong(off); lPrev = this.aMemBlocks[iBlock].readLong(off, addr);
this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~(-1 << nShift)) | (l << nShift)); this.aMemBlocks[iBlock].writeLong(off, (lPrev & ~(-1 << nShift)) | (l << nShift), addr);
iBlock = (iBlock + 1) & this.blockMask; iBlock = (iBlock + 1) & this.blockMask;
lPrev = this.aMemBlocks[iBlock].readLong(0); addr += 3;
this.aMemBlocks[iBlock].writeLong(0, (lPrev & (-1 << nShift)) | (l >>> (32 - nShift))); lPrev = this.aMemBlocks[iBlock].readLong(0, addr);
this.aMemBlocks[iBlock].writeLong(0, (lPrev & (-1 << nShift)) | (l >>> (32 - nShift)), addr);
}; };
/** /**
@ -2950,7 +2951,7 @@ X86CPU.prototype.getBytePrefetch = function(addr)
* with side-effects we may not want, and in any case, while it seemed to improve Safari's performance slightly, * with side-effects we may not want, and in any case, while it seemed to improve Safari's performance slightly,
* it did nothing for the oddball Chrome performance I'm seeing with PREFETCH enabled. * it did nothing for the oddball Chrome performance I'm seeing with PREFETCH enabled.
* *
* b = this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit); * b = this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr);
* this.nBusCycles += 4; * this.nBusCycles += 4;
* this.cbPrefetchValid = 0; * this.cbPrefetchValid = 0;
* this.addrPrefetchHead = (addr + 1) & this.busMask; * this.addrPrefetchHead = (addr + 1) & this.busMask;
@ -3027,7 +3028,7 @@ X86CPU.prototype.fillPrefetch = function(n)
{ {
while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) { while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) {
var addr = this.addrPrefetchHead; var addr = this.addrPrefetchHead;
var b = this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit); var b = this.aMemBlocks[(addr & this.busMask) >>> this.blockShift].readByte(addr & this.blockLimit, addr);
this.aPrefetch[this.iPrefetchHead] = b | (addr << 8); this.aPrefetch[this.iPrefetchHead] = b | (addr << 8);
if (MAXDEBUG) this.printMessage(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b)); if (MAXDEBUG) this.printMessage(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
this.addrPrefetchHead = (addr + 1) & this.busMask; this.addrPrefetchHead = (addr + 1) & this.busMask;