Some Bus and Video tweaks

This commit is contained in:
Jeff Parsons 2015-01-27 15:46:22 -08:00 committed by jeffpar
commit 2637a4ca85
9 changed files with 290 additions and 168 deletions

View file

@ -28,7 +28,7 @@ result is always extended into the entire 52 "significand" bits of the underlyin
impossible to simply "mask away" those additional sign bits, thanks to the fundamental restriction of JavaScript bitwise
operators: they operate *only* on the low 32 bits.
The easiest way to remove the high-order sign bits from a negative 32-bit value is to add 0x100000000:
The easiest way to remove the high-order sign bits from a negative 32-bit value is to add the 33-bit value 0x100000000:
> n = (n < 0? n + 0x100000000 : n)
2147483648
@ -36,15 +36,26 @@ The easiest way to remove the high-order sign bits from a negative 32-bit value
'80000000'
This works because JavaScript is perfectly capable of representing 0x80000000, or any other 32-bit value, as a positive
number. But be careful, because as soon as you perform *any* bitwise operation on a value with bit 31 set, even
an operation as innocuous-looking as:
number, albeit in floating point. And be careful, because as soon as you perform *any* bitwise operation on a value
with bit 31 set, even an operation as innocuous-looking as:
> n |= 0
-2147483648
> n.toString(16)
'-80000000'
Viola: instant negative number! To continue the fun, set bit 0 of 0x80000000, which should give you 0x80000001:
Viola: instant negative number!
This might tempt you to think that the right way to write negative 32-bit constants in hex is to simply precede
them with a minus sign. But that would be wrong. For example, if you wrote the constant 0x80000080 as "-0x80000080",
JavaScript would treat that as negation of 2147483776, resulting in a value whose low 32 bits are 0x7FFFFF80, not
0x80000080.
The safest way to write a 32-bit constant like 0x80000080 is "0x80000080|0", which will produce -2147483520. If you
write all your negative 32-bit constants that way, then you won't have to resort to 33-bit addition and potential
floating point operations.
To continue the fun, try setting bit 0 of 0x80000000, which should give you 0x80000001:
> n |= 1
-2147483647
@ -54,7 +65,8 @@ Viola: instant negative number! To continue the fun, set bit 0 of 0x80000000, w
WTF? Have all the low 32 bits flipped instead?
Actually, no, this time, I'm pulling your leg. The low 32 bits of the internal value are exactly what you would
expect: 0x80000001 (the internal representation is more like 0xFFFFF80000001). But as the [MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString)
expect: 0x80000001 (the internal representation is more like 0xFFFFF80000001). But as the
[MDN Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString)
explain, for a negative number, toString() returns the positive representation of the number, preceded by a - sign,
*not* the "two's complement" of the number.

View file

@ -2,7 +2,7 @@
<panel id="panel" width="100%" padding="8px">
<name>Control Panel</name>
<control type="container" width="100%" height="auto">
<control type="canvas" binding="btpanel" pos="relative" width="2048" height="1024" style="background-color:green;"/>
<control type="canvas" binding="btpanel" pos="relative" width="2048" height="1024" style="color:white; background-color:green;"/>
</control>
<control type="container" class="pcjs-textarea" width="100%" padtop="8px">
<control type="textarea" binding="print" width="100%" height="260px" pos="relative" padbottom="4px" padright="8px" style="resize:vertical;"/>

View file

@ -98,19 +98,19 @@ function Bus(parmsBus, cpu, dbg)
*
* iBlock & this.blockMask
*
* While we *could* say that we mask addresses with this.addrMask to simulate "A20 wrap", the simple
* While we *could* say that we mask addresses with this.busMask to simulate "A20 wrap", the simple
* fact is it relieves us from bounds-checking every aMemBlocks index. Address wrapping at the 1Mb
* boundary (ie, the A20 address line) is something we'll have to deal with more carefully on the 80286.
*
* New property Old property Old hard-coded values (when nBusWidth was always 20)
* ------------ ------------ ----------------------------------------------------
* this.addrLimit Bus.ADDR.LIMIT 0xfffff
* this.addrMask N/A N/A
* this.busLimit Bus.ADDR.LIMIT 0xfffff
* this.busMask N/A N/A
* this.blockSize Bus.BLOCK.SIZE 4096
* this.blockLen Bus.BLOCK.LEN (this.blockSize >> 2)
* this.blockShift Bus.BLOCK.SHIFT 12
* this.blockLimit Bus.BLOCK.LIMIT 0xfff
* this.blockTotal Bus.BLOCK.TOTAL ((this.addrLimit + this.blockSize) / this.blockSize) | 0
* this.blockTotal Bus.BLOCK.TOTAL ((this.busLimit + this.blockSize) / this.blockSize) | 0
* this.blockMask Bus.BLOCK.MASK (this.blockTotal - 1) (ie, 0xff)
*
* Note that the blockShift calculation below chooses a 4Kb physical memory block size for a 20-bit bus
@ -123,13 +123,14 @@ function Bus(parmsBus, cpu, dbg)
* memory implementation detail, which should have no bearing on segment or page granularity of any future
* virtual memory implementation.
*/
this.addrLimit = this.addrMask = (1 << this.nBusWidth) - 1;
this.busLimit = this.busMask = (1 << this.nBusWidth) - 1;
this.blockShift = (this.nBusWidth <= 20? 12 : 14);
this.blockSize = 1 << this.blockShift;
this.blockLen = this.blockSize >> 2;
this.blockLimit = this.blockSize - 1;
this.blockTotal = ((this.addrLimit + this.blockSize) / this.blockSize) | 0;
this.blockTotal = ((this.busLimit + this.blockSize) / this.blockSize) | 0;
this.blockMask = this.blockTotal - 1;
this.assert(this.blockTotal <= Bus.BLOCK.MASK);
/*
* Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by
@ -235,6 +236,15 @@ if (BACKTRACK) {
};
}
/*
* scanMemory() records block numbers in bits 0-14, a BackTrack "mod" bit in bit 15, and the block type at bit 16.
*/
Bus.BLOCK = {
MASK: 0x7fff,
BTMOD_SHIFT: 15,
TYPE_SHIFT: 16
};
/**
* initMemory()
*
@ -250,8 +260,8 @@ Bus.prototype.initMemory = function()
var block = this.aMemBlocks[iBlock] = new Memory(addr);
if (DEBUGGER) block.setDebugInfo(this.cpu, this.dbg, addr, this.blockSize);
}
this.cpu.initMemory(this.aMemBlocks, this.addrLimit, this.blockShift, this.blockLimit, this.blockMask);
this.cpu.setAddressMask(this.addrMask);
this.cpu.initMemory(this.aMemBlocks, this.blockShift, this.blockLimit, this.blockMask);
this.cpu.setAddressMask(this.busMask);
};
/**
@ -300,7 +310,7 @@ Bus.prototype.powerUp = function(data, fRepower)
*
* @this {Bus}
* @param {number} addr is the starting physical address of the memory address range
* @param {number} size of the length in bytes of the range; must be a multiple of BLOCK_SIZE
* @param {number} size of the length in bytes of the range; must be a multiple of blockSize
* @param {number} type is one of the Memory.TYPE constants
* @param {Object} [controller] is an optional memory controller component
* @return {boolean} true if successful, false if not
@ -348,27 +358,49 @@ Bus.prototype.cleanMemory = function(addr, size)
};
/**
* scanMemory(addr, size, stats)
* scanMemory(stats, addr, size)
*
* Returns a Stats object for the specified address range with the following properties:
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* aBlocks is preallocated to its maximum size, so don't rely on its length; at any given moment,
* only the first cBlocks entries will be valid.
*
* @this {Bus}
* @param {number} [addr]
* @param {number} [size]
* @param {Object} [stats]
* @return {number} bytes allocated
* @param {Object} [stats] previous stats, if any
* @param {number} [addr] starting address of range (0 if none provided)
* @param {number} [size] size of range, in bytes (up to end of address space if none provided)
* @return {Object} updated stats (or new stats if no previous stats provided)
*/
Bus.prototype.scanMemory = function(addr, size, stats)
Bus.prototype.scanMemory = function(stats, addr, size)
{
var cbTotal = 0;
if (addr === undefined) addr = 0;
if (size === undefined) size = (this.addrLimit + 1) - addr;
if (addr == null) addr = 0;
if (size == null) size = (this.busLimit + 1) - addr;
if (stats == null) stats = {cbTotal: 0, cBlocks: 0, aBlocks: new Array(this.blockTotal)};
var iBlock = addr >>> this.blockShift;
var iBlockMax = ((addr + size - 1) >>> this.blockShift);
stats.cbTotal = 0;
stats.cBlocks = 0;
while (iBlock <= iBlockMax) {
var block = this.aMemBlocks[iBlock];
cbTotal += block.size;
stats.cbTotal += block.size;
if (block.size) {
var nBlock = iBlock;
nBlock |= (block.type << Bus.BLOCK.TYPE_SHIFT);
if (BACKTRACK) {
var fMod = block.modBackTrack(false);
if (fMod) nBlock |= (1 << Bus.BLOCK.BTMOD_SHIFT);
}
stats.aBlocks[stats.cBlocks++] = nBlock;
}
iBlock++;
}
return cbTotal;
return stats;
};
/**
@ -379,7 +411,7 @@ Bus.prototype.scanMemory = function(addr, size, stats)
*/
Bus.prototype.getA20 = function()
{
return this.addrLimit == this.addrMask;
return this.busLimit == this.busMask;
};
/**
@ -393,9 +425,9 @@ Bus.prototype.setA20 = function(fEnable)
this.assert(fEnable !== undefined);
if (fEnable !== undefined) {
if (this.nBusWidth > 20) {
var addrMask = (this.addrMask & ~0x100000) | (fEnable? 0x100000 : 0);
if (addrMask != this.addrMask) {
this.addrMask = addrMask;
var addrMask = (this.busMask & ~0x100000) | (fEnable? 0x100000 : 0);
if (addrMask != this.busMask) {
this.busMask = addrMask;
/*
* This callback is required only because the CPU "insists" on using its own memory access functions.
*/
@ -484,7 +516,7 @@ Bus.prototype.removeMemory = function(addr, size)
*/
Bus.prototype.getByte = function(addr)
{
return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByte(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
};
/**
@ -498,7 +530,7 @@ Bus.prototype.getByte = function(addr)
*/
Bus.prototype.getByteDirect = function(addr)
{
return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readByteDirect(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByteDirect(addr & this.blockLimit);
};
/**
@ -515,9 +547,9 @@ Bus.prototype.getByteDirect = function(addr)
Bus.prototype.getShort = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readWord(off);
return this.aMemBlocks[iBlock].readShort(off);
}
return this.aMemBlocks[iBlock++].readByte(off) | (this.aMemBlocks[iBlock & this.blockMask].readByte(0) << 8);
};
@ -534,9 +566,9 @@ Bus.prototype.getShort = function(addr)
Bus.prototype.getShortDirect = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off != this.blockLimit) {
return this.aMemBlocks[iBlock].readWordDirect(off);
return this.aMemBlocks[iBlock].readShortDirect(off);
}
return this.aMemBlocks[iBlock++].readByteDirect(off) | (this.aMemBlocks[iBlock & this.blockMask].readByteDirect(0) << 8);
};
@ -555,7 +587,7 @@ Bus.prototype.getShortDirect = function(addr)
Bus.prototype.getLong = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLong(off);
}
@ -575,7 +607,7 @@ Bus.prototype.getLong = function(addr)
Bus.prototype.getLongDirect = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off < this.blockLimit - 2) {
return this.aMemBlocks[iBlock].readLongDirect(off);
}
@ -595,7 +627,7 @@ Bus.prototype.getLongDirect = function(addr)
*/
Bus.prototype.setByte = function(addr, b)
{
this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
/**
@ -610,7 +642,7 @@ Bus.prototype.setByte = function(addr, b)
*/
Bus.prototype.setByteDirect = function(addr, b)
{
this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeByteDirect(addr & this.blockLimit, b & 0xff);
};
/**
@ -627,9 +659,9 @@ Bus.prototype.setByteDirect = function(addr, b)
Bus.prototype.setShort = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off != this.blockLimit) {
this.aMemBlocks[iBlock].writeWord(off, w & 0xffff);
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff);
return;
}
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff);
@ -649,9 +681,9 @@ Bus.prototype.setShort = function(addr, w)
Bus.prototype.setShortDirect = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off != this.blockLimit) {
this.aMemBlocks[iBlock].writeWordDirect(off, w & 0xffff);
this.aMemBlocks[iBlock].writeShortDirect(off, w & 0xffff);
return;
}
this.aMemBlocks[iBlock++].writeByteDirect(off, w & 0xff);
@ -672,7 +704,7 @@ Bus.prototype.setShortDirect = function(addr, w)
Bus.prototype.setLong = function(addr, l)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off < this.blockLimit - 2) {
this.aMemBlocks[iBlock].writeLong(off, l);
return;
@ -699,7 +731,7 @@ Bus.prototype.setLong = function(addr, l)
Bus.prototype.setLongDirect = function(addr, l)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (off < this.blockLimit - 2) {
this.aMemBlocks[iBlock].writeLongDirect(off, l);
return;
@ -819,7 +851,7 @@ Bus.prototype.writeBackTrackObject = function(addr, bto, off)
Bus.prototype.readBackTrack = function(addr)
{
if (BACKTRACK) {
return this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].readBackTrack(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readBackTrack(addr & this.blockLimit);
}
return 0;
};
@ -835,9 +867,11 @@ Bus.prototype.writeBackTrack = function(addr, bti)
{
if (BACKTRACK) {
var slot = bti >>> Bus.BACKTRACK.SLOT_SHIFT;
var btiPrev = this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
var iBlock = (addr & this.busMask) >> this.blockShift;
var btiPrev = this.aMemBlocks[iBlock].writeBackTrack(addr & this.blockLimit, bti);
var slotPrev = btiPrev >>> Bus.BACKTRACK.SLOT_SHIFT;
if (slot != slotPrev) {
this.aMemBlocks[iBlock].modBackTrack(true);
if (btiPrev && slotPrev) {
var btoPrev = this.abtObjects[slotPrev-1];
if (!btoPrev) {
@ -935,7 +969,7 @@ Bus.prototype.updateBackTrackCode = function(addr, bti)
} else {
return;
}
this.aMemBlocks[(addr & this.addrMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeBackTrack(addr & this.blockLimit, bti);
}
};

View file

@ -3076,7 +3076,7 @@ if (DEBUGGER) {
* done later, by getAddr(), which returns a negative result (-1) for invalid segments, out-of-range offsets,
* etc. The Debugger's low-level get/set memory functions verify all getAddr() results, but even if an
* invalid address is passed through to the Bus memory interfaces, the address will simply be masked with
* Bus.addrLimit; in the case of -1, that will generally refer to the last byte of physical address space.
* Bus.busLimit; in the case of -1, that will generally refer to the last byte of physical address space.
*
* @this {Debugger}
* @param {string|undefined} sAddr
@ -4596,7 +4596,7 @@ if (DEBUGGER) {
return;
if (n === undefined) n = 1;
var aAddrEnd = this.newAddr(0xffff, aAddr[1], this.bus.addrLimit);
var aAddrEnd = this.newAddr(0xffff, aAddr[1], this.bus.busLimit);
if (sAddrEnd !== undefined) {
aAddrEnd = this.parseAddr(sAddrEnd, Debugger.ADDR_CODE);

View file

@ -1167,7 +1167,7 @@ HDC.prototype.loadDisk = function(iDrive, sDiskName, sDiskPath, fAutoMount)
* @param {string} sDiskName
* @param {string} sDiskPath
*/
HDC.prototype.doneLoadDisk = function onHDCLoadNotify(drive, disk, sDiskName, sDiskPath)
HDC.prototype.doneLoadDisk = function(drive, disk, sDiskName, sDiskPath)
{
drive.fBusy = false;
if ((drive.disk = disk)) {

View file

@ -74,7 +74,7 @@ if (typeof module !== 'undefined') {
* The Bus allocates empty blocks for the entire address space during initialization, so that
* any reads/writes to undefined addresses will have no effect. Later, the ROM and RAM
* components will ask the Bus to allocate memory for specific ranges, and the Bus will allocate
* as many new BLOCK_SIZE Memory objects as the ranges require. Partial Memory blocks could
* as many new blockSize Memory objects as the ranges require. Partial Memory blocks could
* also be supported in theory, but in practice, they're not.
*
* Because Memory blocks now allow us to have a "sparse" address space, we could choose to
@ -105,9 +105,9 @@ if (typeof module !== 'undefined') {
function Memory(addr, size, type, controller)
{
var i;
this.cb = size || 0;
this.adw = null;
this.offset = 0;
this.size = size || 0;
this.type = type || Memory.TYPE.NONE;
this.fReadOnly = (type == Memory.TYPE.ROM);
this.controller = null;
@ -115,11 +115,15 @@ function Memory(addr, size, type, controller)
if (BACKTRACK) {
if (!size || controller) {
this.fModBackTrack = false;
this.readBackTrack = Memory.readBackTrackNone;
this.writeBackTrack = Memory.writeBackTrackNone;
this.modBackTrack = Memory.modBackTrackNone;
} else {
this.fModBackTrack = true;
this.readBackTrack = Memory.readBackTrackIndex;
this.writeBackTrack = Memory.writeBackTrackIndex;
this.modBackTrack = Memory.modBackTrackIndex;
this.abtIndexes = new Array(size);
for (i = 0; i < size; i++) this.abtIndexes[i] = 0;
}
@ -153,7 +157,7 @@ function Memory(addr, size, type, controller)
* 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
* mode; pseudo-random might be best, because if that uncovers a bug, it might be reproducible.
* mode; pseudo-random might be best, because if it uncovers a bug, the bug should be reproducible.
*/
if (TYPEDARRAYS) {
this.buffer = new ArrayBuffer(size);
@ -203,6 +207,10 @@ Memory.TYPE = {
VIDEO: 3
};
if (DEBUG) {
Memory.TYPE.NAMES = ["NONE", "RAM", "ROM", "VIDEO"];
}
/**
* readNone(off)
*
@ -241,7 +249,7 @@ Memory.writeNone = function writeNone(off, v)
*/
Memory.readByteMemory = function readByteMemory(off)
{
Component.assert(off >= 0 && off < this.cb);
Component.assert(off >= 0 && off < this.size);
if (FATARRAYS) {
return this.ab[off];
}
@ -249,15 +257,15 @@ Memory.readByteMemory = function readByteMemory(off)
};
/**
* readWordMemory(off)
* readShortMemory(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readWordMemory = function readWordMemory(off)
Memory.readShortMemory = function readShortMemory(off)
{
Component.assert(off >= 0 && off < this.cb - 1);
Component.assert(off >= 0 && off < this.size - 1);
if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8);
}
@ -282,7 +290,7 @@ Memory.readWordMemory = function readWordMemory(off)
*/
Memory.readLongMemory = function readLongMemory(off)
{
Component.assert(off >= 0 && off < this.cb - 3);
Component.assert(off >= 0 && off < this.size - 3);
if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24);
}
@ -305,7 +313,7 @@ Memory.readLongMemory = function readLongMemory(off)
*/
Memory.writeByteMemory = function writeByteMemory(off, b)
{
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
Component.assert(off >= 0 && off < this.size && (b & 0xff) == b);
if (FATARRAYS) {
this.ab[off] = b;
} else {
@ -317,15 +325,15 @@ Memory.writeByteMemory = function writeByteMemory(off, b)
};
/**
* writeWordMemory(off, w)
* writeShortMemory(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Memory.writeWordMemory = function writeWordMemory(off, w)
Memory.writeShortMemory = function writeShortMemory(off, w)
{
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w);
if (FATARRAYS) {
this.ab[off] = (w & 0xff);
this.ab[off + 1] = (w >> 8);
@ -352,7 +360,7 @@ Memory.writeWordMemory = function writeWordMemory(off, w)
*/
Memory.writeLongMemory = function writeLongMemory(off, l)
{
Component.assert(off >= 0 && off < this.cb - 3);
Component.assert(off >= 0 && off < this.size - 3);
if (FATARRAYS) {
this.ab[off] = (l & 0xff);
this.ab[off + 1] = (l >> 8) & 0xff;
@ -386,19 +394,19 @@ Memory.readByteChecked = function readByteChecked(off)
};
/**
* readWordChecked(off)
* readShortChecked(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readWordChecked = function readWordChecked(off)
Memory.readShortChecked = function readShortChecked(off)
{
if (DEBUGGER) {
this.dbg.checkMemoryRead(this.addr + off) ||
this.dbg.checkMemoryRead(this.addr + off + 1);
}
return this.readWordDirect(off);
return this.readShortDirect(off);
};
/**
@ -433,19 +441,19 @@ Memory.writeByteChecked = function writeByteChecked(off, b)
};
/**
* writeWordChecked(off, w)
* writeShortChecked(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Memory.writeWordChecked = function writeWordChecked(off, w)
Memory.writeShortChecked = function writeShortChecked(off, w)
{
if (DEBUGGER) {
this.dbg.checkMemoryWrite(this.addr + off) ||
this.dbg.checkMemoryWrite(this.addr + off + 1);
}
this.writeWordDirect(off, w);
this.writeShortDirect(off, w);
};
/**
@ -475,20 +483,20 @@ Memory.writeLongChecked = function writeLongChecked(off, l)
*/
Memory.readByteTypedArray = function readByteTypedArray(off)
{
Component.assert(off >= 0 && off < this.cb);
Component.assert(off >= 0 && off < this.size);
return this.ab[off];
};
/**
* readWordTypedArray(off)
* readShortTypedArray(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Memory.readWordTypedArray = function readWordTypedArray(off)
Memory.readShortTypedArray = function readShortTypedArray(off)
{
Component.assert(off >= 0 && off < this.cb - 1);
Component.assert(off >= 0 && off < this.size - 1);
return this.dv.getUint16(off, true);
};
@ -501,7 +509,7 @@ Memory.readWordTypedArray = function readWordTypedArray(off)
*/
Memory.readLongTypedArray = function readLongTypedArray(off)
{
Component.assert(off >= 0 && off < this.cb - 3);
Component.assert(off >= 0 && off < this.size - 3);
return this.dv.getInt32(off, true);
};
@ -514,21 +522,21 @@ Memory.readLongTypedArray = function readLongTypedArray(off)
*/
Memory.writeByteTypedArray = function writeByteTypedArray(off, b)
{
Component.assert(off >= 0 && off < this.cb && (b & 0xff) == b);
Component.assert(off >= 0 && off < this.size && (b & 0xff) == b);
this.ab[off] = b;
this.fDirty = true;
};
/**
* writeWordTypedArray(off, w)
* writeShortTypedArray(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Memory.writeWordTypedArray = function writeWordTypedArray(off, w)
Memory.writeShortTypedArray = function writeShortTypedArray(off, w)
{
Component.assert(off >= 0 && off < this.cb - 1 && (w & 0xffff) == w);
Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w);
this.dv.setUint16(off, w, true);
this.fDirty = true;
};
@ -542,7 +550,7 @@ Memory.writeWordTypedArray = function writeWordTypedArray(off, w)
*/
Memory.writeLongTypedArray = function writeLongTypedArray(off, l)
{
Component.assert(off >= 0 && off < this.cb - 3);
Component.assert(off >= 0 && off < this.size - 3);
this.dv.setInt32(off, l, true);
this.fDirty = true;
};
@ -570,6 +578,17 @@ Memory.writeBackTrackNone = function writeBackTrackNone(off, bti)
{
};
/**
* modBackTrackNone(fMod)
*
* @this {Memory}
* @param {boolean} fMod
*/
Memory.modBackTrackNone = function modBackTrackNone(fMod)
{
return false;
};
/**
* readBackTrackIndex(off)
*
@ -579,7 +598,7 @@ Memory.writeBackTrackNone = function writeBackTrackNone(off, bti)
*/
Memory.readBackTrackIndex = function readBackTrackIndex(off)
{
Component.assert(off >= 0 && off < this.cb);
Component.assert(off >= 0 && off < this.size);
return this.abtIndexes[off];
};
@ -594,17 +613,31 @@ Memory.readBackTrackIndex = function readBackTrackIndex(off)
Memory.writeBackTrackIndex = function writeBackTrackIndex(off, bti)
{
var btiPrev;
Component.assert(off >= 0 && off < this.cb);
Component.assert(off >= 0 && off < this.size);
btiPrev = this.abtIndexes[off];
this.abtIndexes[off] = bti;
return btiPrev;
};
Memory.afnMemory = [Memory.readByteMemory, Memory.readWordMemory, Memory.readLongMemory, Memory.writeByteMemory, Memory.writeWordMemory, Memory.writeLongMemory];
Memory.afnChecked = [Memory.readByteChecked, Memory.readWordChecked, Memory.readLongChecked, Memory.writeByteChecked, Memory.writeWordChecked, Memory.writeLongChecked];
/**
* modBackTrackIndex(fMod)
*
* @this {Memory}
* @param {boolean} fMod
* @return {boolean} previous value
*/
Memory.modBackTrackIndex = function modBackTrackIndex(fMod)
{
var fModPrev = this.fModBackTrack;
this.fModBackTrack = fMod;
return fModPrev;
};
Memory.afnMemory = [Memory.readByteMemory, Memory.readShortMemory, Memory.readLongMemory, Memory.writeByteMemory, Memory.writeShortMemory, Memory.writeLongMemory];
Memory.afnChecked = [Memory.readByteChecked, Memory.readShortChecked, Memory.readLongChecked, Memory.writeByteChecked, Memory.writeShortChecked, Memory.writeLongChecked];
if (TYPEDARRAYS) {
Memory.afnTypedArray = [Memory.readByteTypedArray, Memory.readWordTypedArray, Memory.readLongTypedArray, Memory.writeByteTypedArray, Memory.writeWordTypedArray, Memory.writeLongTypedArray];
Memory.afnTypedArray = [Memory.readByteTypedArray, Memory.readShortTypedArray, Memory.readLongTypedArray, Memory.writeByteTypedArray, Memory.writeShortTypedArray, Memory.writeLongTypedArray];
}
Memory.prototype = {
@ -628,7 +661,7 @@ Memory.prototype = {
adw = null;
}
else if (FATARRAYS) {
adw = new Array(this.cb >> 2);
adw = new Array(this.size >> 2);
var off = 0;
for (i = 0; i < adw.length; i++) {
adw[i] = this.ab[off] | (this.ab[off + 1] << 8) | (this.ab[off + 2] << 16) | (this.ab[off + 3] << 24);
@ -637,7 +670,7 @@ Memory.prototype = {
}
else if (TYPEDARRAYS) {
/*
* It might be tempting to just return a copy of Int32Array(this.buffer, 0, this.cb >> 2),
* It might be tempting to just return a copy of Int32Array(this.buffer, 0, this.size >> 2),
* but we can't be sure of the "endianness" of an Int32Array -- which would be OK if the array
* was always saved/restored on the same machine, but there's no guarantee of that, either.
* So we use getInt32() and require little-endian values.
@ -646,7 +679,7 @@ Memory.prototype = {
* a normal array; it's serialized as an Object rather than an Array, so it lacks a "length"
* property and causes problems for State.store() and State.parse().
*/
adw = new Array(this.cb >> 2);
adw = new Array(this.size >> 2);
for (i = 0; i < adw.length; i++) {
adw[i] = this.dv.getInt32(i << 2, true);
}
@ -680,7 +713,7 @@ Memory.prototype = {
* no controller AND no data.
*/
Component.assert(adw != null);
if (adw && this.cb == adw.length << 2) {
if (adw && this.size == adw.length << 2) {
var i;
if (FATARRAYS) {
var off = 0;
@ -725,11 +758,11 @@ Memory.prototype = {
*/
setReadAccess: function(afn, fDirect) {
this.readByte = afn[0] || Memory.readNone;
this.readWord = afn[1] || Memory.readNone;
this.readShort = afn[1] || Memory.readNone;
this.readLong = afn[2] || Memory.readNone;
if (fDirect) {
this.readByteDirect = afn[0] || Memory.readNone;
this.readWordDirect = afn[1] || Memory.readNone;
this.readShortDirect = afn[1] || Memory.readNone;
this.readLongDirect = afn[2] || Memory.readNone;
}
},
@ -742,11 +775,11 @@ Memory.prototype = {
*/
setWriteAccess: function(afn, fDirect) {
this.writeByte = !this.fReadOnly && afn[3] || Memory.writeNone;
this.writeWord = !this.fReadOnly && afn[4] || Memory.writeNone;
this.writeShort = !this.fReadOnly && afn[4] || Memory.writeNone;
this.writeLong = !this.fReadOnly && afn[5] || Memory.writeNone;
if (fDirect) {
this.writeByteDirect = afn[3] || Memory.writeNone;
this.writeWordDirect = afn[4] || Memory.writeNone;
this.writeShortDirect = afn[4] || Memory.writeNone;
this.writeLongDirect = afn[5] || Memory.writeNone;
}
},
@ -757,7 +790,7 @@ Memory.prototype = {
*/
resetReadAccess: function() {
this.readByte = this.readByteDirect;
this.readWord = this.readWordDirect;
this.readShort = this.readShortDirect;
this.readLong = this.readLongDirect;
},
/**
@ -767,7 +800,7 @@ Memory.prototype = {
*/
resetWriteAccess: function() {
this.writeByte = this.fReadOnly? Memory.writeNone : this.writeByteDirect;
this.writeWord = this.fReadOnly? Memory.writeNone : this.writeWordDirect;
this.writeShort = this.fReadOnly? Memory.writeNone : this.writeShortDirect;
this.writeLong = this.fReadOnly? Memory.writeNone : this.writeLongDirect;
},
/**

View file

@ -35,6 +35,8 @@
if (typeof module !== 'undefined') {
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Bus = require("./bus");
var Memory = require("./memory");
}
/**
@ -49,7 +51,10 @@ if (typeof module !== 'undefined') {
function Panel(parmsPanel) {
Component.call(this, "Panel", parmsPanel, Panel);
this.canvas = null;
if (BACKTRACK) this.fBackTrack = false;
if (BACKTRACK) {
this.stats = null;
this.fBackTrack = false;
}
}
Component.subclass(Component, Panel);
@ -82,7 +87,7 @@ Panel.prototype.setBinding = function(sHTMLType, sBinding, control)
this.canvas = control;
this.canvasContext = this.canvas.getContext("2d");
/*
* this.canvas.width and this.canvas.height contain the width and height of the canvas, in pixels
* NOTE: this.canvas.width and this.canvas.height contain the width and height of the canvas, in pixels
*/
this.fRedraw = true;
return true;
@ -121,25 +126,6 @@ Panel.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
Panel.init();
if (this.canvas) {
if (this.fBackTrack) {
/*
* We need to calculate some parameters based on the canvas pixel dimensions. For now, we're
* going to use 100% of the canvas height, and 75% of the canvas width (starting with the left edge),
* for the live memory display.
*
* For a 640x350 canvas, that means 480x350 pixels for the live memory display, or 168,000 pixels.
* For a 16Mb (24-bit) address space, with 16,777,216 locations, the worst case would mean each pixel
* represents roughly 100 memory locations. But in a machine with only 1152Kb of RAM, 32Kb of Video RAM,
* and 128Kb of ROM, that's only 1,343,488 locations we need to worry about, because we can ignore all
* the unallocated regions.
*
* So to start, we need a function that scans the entire address space, and reports how many bytes are
* actually allocated. At the same time, we should also count how many different objects exist.
*/
this.bus.scanMemory()
}
}
}
return true;
};
@ -156,11 +142,6 @@ Panel.prototype.powerDown = function(fSave)
return true;
};
Panel.prototype.scanMemory = function()
{
};
/**
* updateAnimation()
*
@ -175,7 +156,11 @@ Panel.prototype.updateAnimation = function()
if (this.fRedraw) {
if (BACKTRACK && this.fBackTrack) {
context.font = "40px Arial";
context.fillStyle = "#FFFFFF";
/*
* Even when the canvas from whence the context came has an explicit "color" style,
* the context still defaults to "black", so we must manually propagate the canvas color.
*/
context.fillStyle = this.canvas.style.color;
context.fillText("BackTrack Panel",10,50);
}
this.fRedraw = false;
@ -194,6 +179,62 @@ Panel.prototype.updateAnimation = function()
*/
Panel.prototype.updateStatus = function()
{
if (this.canvas) {
if (this.fBackTrack) {
if (MAXDEBUG) this.log("begin scanMemory()");
this.stats = this.bus.scanMemory(this.stats);
this.findRegions();
if (MAXDEBUG) this.log("end scanMemory(): total bytes: " + this.stats.cbTotal + ", total blocks: " + this.stats.cBlocks + ", total regions: " + this.stats.cRegions);
}
}
};
/**
* findRegions()
*
* This takes the stats object produced by scanMemory() and adds the following:
*
* cRegions: number of contiguous memory regions
* aRegions: array of aBlocks indexes (bits 0-15) combined with block counts (bits 16-31)
*
* It calls addRegion() for each discrete region (set of contiguous blocks with the same type) that it finds.
*
* @this {Panel}
*/
Panel.prototype.findRegions = function()
{
this.stats.cRegions = 0;
if (!this.stats.aRegions) this.stats.aRegions = [];
var typeRegion = -1, iBlockRegion = 0, addrRegion = 0, nBlockPrev = -1;
for (var iBlock = 0; iBlock < this.stats.cBlocks; iBlock++) {
var nBlock = this.stats.aBlocks[iBlock];
var type = nBlock >>> Bus.BLOCK.TYPE_SHIFT;
var nBlockCurr = (nBlock & Bus.BLOCK.MASK);
if (type != typeRegion || nBlockCurr != nBlockPrev + 1) {
var cBlocks = iBlock - iBlockRegion;
if (cBlocks) this.addRegion(addrRegion, iBlockRegion, cBlocks, typeRegion);
typeRegion = type;
iBlockRegion = iBlock;
addrRegion = (nBlock & Bus.BLOCK.MASK) << this.bus.blockShift;
}
nBlockPrev = nBlockCurr;
}
this.addRegion(addrRegion, iBlockRegion, iBlock - iBlockRegion, typeRegion);
};
/**
* addRegion(addr, iBlock, cBlocks, type)
*
* @this {Panel}
* @param {number} addr
* @param {number} iBlock
* @param {number} cBlocks
* @param {number} type
*/
Panel.prototype.addRegion = function(addr, iBlock, cBlocks, type)
{
this.stats.aRegions[this.stats.cRegions++] = (iBlock | cBlocks << 16);
if (MAXDEBUG) this.log("region " + this.stats.cRegions + " (addr " + str.toHex(addr) + ", type " + Memory.TYPE.NAMES[type] + ") contains " + cBlocks + " blocks");
};
/**

View file

@ -710,10 +710,10 @@ Video.aCGAColorSet2 = [Video.ATTRS.FGND_CYAN, Video.ATTRS.FGND_MAGENTA, Video.A
Video.aEGAPalDef = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F];
Video.aEGAByteToDW = [
0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
0xff000000|0, 0xff0000ff|0, 0xff00ff00|0, 0xff00ffff|0,
0xffff0000|0, 0xffff00ff|0, 0xffffff00|0, 0xffffffff|0
];
Video.aEGADWToByte = [];
@ -725,14 +725,14 @@ Video.aEGADWToByte[0x00800000] = 0x4;
Video.aEGADWToByte[0x00800080] = 0x5;
Video.aEGADWToByte[0x00808000] = 0x6;
Video.aEGADWToByte[0x00808080] = 0x7;
Video.aEGADWToByte[0x80000000] = 0x8;
Video.aEGADWToByte[0x80000080] = 0x9;
Video.aEGADWToByte[0x80008000] = 0xa;
Video.aEGADWToByte[0x80008080] = 0xb;
Video.aEGADWToByte[0x80800000] = 0xc;
Video.aEGADWToByte[0x80800080] = 0xd;
Video.aEGADWToByte[0x80808000] = 0xe;
Video.aEGADWToByte[0x80808080] = 0xf;
Video.aEGADWToByte[0x80000000|0] = 0x8;
Video.aEGADWToByte[0x80000080|0] = 0x9;
Video.aEGADWToByte[0x80008000|0] = 0xa;
Video.aEGADWToByte[0x80008080|0] = 0xb;
Video.aEGADWToByte[0x80800000|0] = 0xc;
Video.aEGADWToByte[0x80800080|0] = 0xd;
Video.aEGADWToByte[0x80808000|0] = 0xe;
Video.aEGADWToByte[0x80808080|0] = 0xf;
/**
* Card(video, iCard, data, cbMemory)
@ -1241,13 +1241,13 @@ Card.ACCESS.WRITE.MODE2XOR = 0xE000;
Card.ACCESS.WRITE.MASK = 0xff00;
/**
* readWord(off)
* readShort(off)
*
* @this {Memory}
* @param {number} off
* @return {number}
*/
Card.ACCESS.readWord = function readWord(off)
Card.ACCESS.readShort = function readShort(off)
{
return this.readByte(off) | (this.readByte(off + 1) << 8);
};
@ -1265,13 +1265,13 @@ Card.ACCESS.readLong = function readLong(off)
};
/**
* writeWord(off, w)
* writeShort(off, w)
*
* @this {Memory}
* @param {number} off
* @param {number} w
*/
Card.ACCESS.writeWord = function writeWord(off, w)
Card.ACCESS.writeShort = function writeShort(off, w)
{
Component.assert(!(w & ~0xffff));
this.writeByte(off, w & 0xff);
@ -1655,11 +1655,11 @@ Card.prototype.initEGA = function(data, nMonitorType)
*/
/*15*/ Card.ACCESS.READ.MODE0 | Card.ACCESS.READ.EVENODD | Card.ACCESS.WRITE.MODE0 | Card.ACCESS.WRITE.EVENODD,
/*16*/ 0,
/*17*/ 0xffffffff,
/*17*/ 0xffffffff|0,
/*18*/ 0,
/*19*/ 0xffffffff,
/*19*/ 0xffffffff|0,
/*20*/ 0,
/*21*/ 0xffffffff,
/*21*/ 0xffffffff|0,
/*22*/ 0,
/*23*/ 0,
/*24*/ 0
@ -1953,7 +1953,7 @@ Card.prototype.setMemoryAccess = function(nAccess)
}
}
if (!this.afnAccess) {
this.afnAccess = [null, Card.ACCESS.readWord, Card.ACCESS.readLong, null, Card.ACCESS.writeWord, Card.ACCESS.writeLong];
this.afnAccess = [null, Card.ACCESS.readShort, Card.ACCESS.readLong, null, Card.ACCESS.writeShort, Card.ACCESS.writeLong];
}
this.afnAccess[0] = fnReadByte;
this.afnAccess[3] = fnWriteByte;
@ -4340,8 +4340,8 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit)
if (x < xDirty) xDirty = x;
for (var iPixel = 0; iPixel < nPixelsPerCell; iPixel++) {
/*
* JavaScript Alert: if adwMemory contains a 32-bit value such as -1526726656, and then we mask it
* with 0x80808080, we end up with -2147483648, which in a perfect 32-bit world, would be equivalent
* JavaScript Alert: if adwMemory contains a 32-bit value such as -1526726656, and then we mask
* it with 0x80808080, we end up with -2147483648, which in a perfect 32-bit world, would be equal
* to 0x80000000, which means that when we look up "Video.aEGADWToByte[0x80000000]", we should get
* the entry containing 0x8. But no, in JavaScript, since the original value was negative, the
* masked value is still negative, because there are 52 "significand" bits in JavaScript numbers,
@ -4349,13 +4349,17 @@ Video.prototype.updateScreenGraphicsEGA = function(addrScreen, addrScreenLimit)
*
* This can be confirmed by looking at dwPixel.toString(16), which returns "-80000000". One solution
* is to add 4294967296 (0x100000000) to any negative 32-bit value for which we need the positive
* representation.
* representation. A better solution (ie, one that doesn't require 33-bit values, triggering floating
* point arithmetic) is storing negative indexes in the lookup array (aEGADWToByte). However, you CANNOT
* do that by simply writing a value like 0x80000080 as "-0x80000080", because JavaScript will interpret
* that as the negation of 2147483776, yielding -2147483776, the low 32 bits of which are 0x7FFFFFF80,
* not 0x80000080 as intended. So, the safest way to write a constant like that is "0x80000080|0".
*
* And, since assertions don't fix problems (only catch them, and only in DEBUG builds), I'm also
* ensuring that bPixel will always default to 0 if an undefined value ever slips through again.
*/
var dwPixel = data & 0x80808080;
if (dwPixel < 0) dwPixel += 0x100000000;
// if (dwPixel < 0) dwPixel += 0x100000000;
this.assert(Video.aEGADWToByte[dwPixel] !== undefined);
var bPixel = Video.aEGADWToByte[dwPixel] || 0;
this.setPixel(this.imageScreenBuffer, x++, y, aPixelColors[bPixel]);

View file

@ -167,7 +167,7 @@ function X86CPU(parmsCPU) {
* when the Bus is initialized.
*/
this.aMemBlocks = [];
this.addrMemMask = this.blockShift = this.blockLimit = this.blockMask = 0;
this.busMask = this.blockShift = this.blockLimit = this.blockMask = 0;
if (SAMPLER) {
/*
@ -442,7 +442,7 @@ X86CPU.PREFETCH = {
};
/**
* initMemory(aMemBlocks, addrLimit, blockShift, blockLimit, blockMask)
* initMemory(aMemBlocks, busMask, blockShift, blockLimit, blockMask)
*
* Notification from Bus.initMemory(), giving us direct access to the entire memory space
* (aMemBlocks).
@ -485,15 +485,13 @@ X86CPU.PREFETCH = {
*
* @this {X86CPU}
* @param {Array} aMemBlocks
* @param {number} addrLimit
* @param {number} blockShift
* @param {number} blockLimit
* @param {number} blockMask
*/
X86CPU.prototype.initMemory = function(aMemBlocks, addrLimit, blockShift, blockLimit, blockMask)
X86CPU.prototype.initMemory = function(aMemBlocks, blockShift, blockLimit, blockMask)
{
this.aMemBlocks = aMemBlocks;
this.addrMemMask = addrLimit;
this.blockShift = blockShift;
this.blockLimit = blockLimit;
this.blockMask = blockMask;
@ -508,16 +506,16 @@ X86CPU.prototype.initMemory = function(aMemBlocks, addrLimit, blockShift, blockL
};
/**
* setAddressMask(addrMask)
* setAddressMask(busMask)
*
* Notification from Bus.setA20(), called whenever the A20 line changes.
*
* @this {X86CPU}
* @param {number} addrMask
* @param {number} busMask
*/
X86CPU.prototype.setAddressMask = function(addrMask)
X86CPU.prototype.setAddressMask = function(busMask)
{
this.addrMemMask = addrMask;
this.busMask = busMask;
};
/**
@ -1879,7 +1877,7 @@ X86CPU.prototype.setBinding = function(sHTMLType, sBinding, control)
X86CPU.prototype.getByte = function(addr)
{
if (BACKTRACK) this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
return this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
return this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
};
/**
@ -1892,7 +1890,7 @@ X86CPU.prototype.getByte = function(addr)
X86CPU.prototype.getShort = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
/*
* On the 8088, it takes 4 cycles to read the additional byte REGARDLESS whether the address is odd or even.
* TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
@ -1904,7 +1902,7 @@ X86CPU.prototype.getShort = function(addr)
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
}
if (off < this.blockLimit) {
return this.aMemBlocks[iBlock].readWord(off);
return this.aMemBlocks[iBlock].readShort(off);
}
return this.aMemBlocks[iBlock].readByte(off) | (this.aMemBlocks[(iBlock + 1) & this.blockMask].readByte(0) << 8);
};
@ -1919,7 +1917,7 @@ X86CPU.prototype.getShort = function(addr)
X86CPU.prototype.getLong = function(addr)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
if (BACKTRACK) {
this.backTrack.btiMemLo = this.bus.readBackTrack(addr);
this.backTrack.btiMemHi = this.bus.readBackTrack(addr + 1);
@ -1941,7 +1939,7 @@ X86CPU.prototype.getLong = function(addr)
X86CPU.prototype.setByte = function(addr, b)
{
if (BACKTRACK) this.bus.writeBackTrack(addr, this.backTrack.btiMemLo);
this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
this.aMemBlocks[(addr & this.busMask) >> this.blockShift].writeByte(addr & this.blockLimit, b & 0xff);
};
/**
@ -1954,7 +1952,7 @@ X86CPU.prototype.setByte = function(addr, b)
X86CPU.prototype.setShort = function(addr, w)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
/*
* On the 8088, it takes 4 cycles to write the additional byte REGARDLESS whether the address is odd or even.
* TODO: For the 8086, the penalty is actually "(addr & 0x1) << 2" (4 additional cycles only when the address is odd).
@ -1966,7 +1964,7 @@ X86CPU.prototype.setShort = function(addr, w)
this.bus.writeBackTrack(addr + 1, this.backTrack.btiMemHi);
}
if (off < this.blockLimit) {
this.aMemBlocks[iBlock].writeWord(off, w & 0xffff);
this.aMemBlocks[iBlock].writeShort(off, w & 0xffff);
return;
}
this.aMemBlocks[iBlock++].writeByte(off, w & 0xff);
@ -1983,7 +1981,7 @@ X86CPU.prototype.setShort = function(addr, w)
X86CPU.prototype.setLong = function(addr, l)
{
var off = addr & this.blockLimit;
var iBlock = (addr & this.addrMemMask) >> this.blockShift;
var iBlock = (addr & this.busMask) >> this.blockShift;
this.nStepCycles -= this.CYCLES.nWordCyclePenalty;
if (BACKTRACK) {
@ -2292,10 +2290,10 @@ 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,
* it did nothing for the oddball Chrome performance I'm seeing with PREFETCH enabled.
*
* b = this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
* b = this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
* this.nBusCycles += 4;
* this.cbPrefetchValid = 0;
* this.addrPrefetchHead = (addr + 1) & this.addrMemMask;
* this.addrPrefetchHead = (addr + 1) & this.busMask;
* return b;
*/
}
@ -2342,10 +2340,10 @@ X86CPU.prototype.fillPrefetch = function(n)
{
while (n-- > 0 && this.cbPrefetchQueued < X86CPU.PREFETCH.QUEUE) {
var addr = this.addrPrefetchHead;
var b = this.aMemBlocks[(addr & this.addrMemMask) >> this.blockShift].readByte(addr & this.blockLimit);
var b = this.aMemBlocks[(addr & this.busMask) >> this.blockShift].readByte(addr & this.blockLimit);
this.aPrefetch[this.iPrefetchHead] = b | (addr << 8);
if (MAXDEBUG) this.printMessage(" fillPrefetch[" + this.iPrefetchHead + "]: " + str.toHex(addr) + ":" + str.toHexByte(b));
this.addrPrefetchHead = (addr + 1) & this.addrMemMask;
this.addrPrefetchHead = (addr + 1) & this.busMask;
this.iPrefetchHead = (this.iPrefetchHead + 1) & X86CPU.PREFETCH.MASK;
this.cbPrefetchQueued++;
/*