Added optimized memory handlers for paged memory

This commit is contained in:
Jeff Parsons 2015-11-07 18:35:32 -08:00
commit d3a8160ad8
3 changed files with 182 additions and 82 deletions

View file

@ -7670,7 +7670,7 @@ if (DEBUGGER) {
} }
break; break;
} }
this.println((APPNAME || "PCjs") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (FATARRAYS? ",FATARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')'); this.println((APPNAME || "PCjs") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (BYTEARRAYS? ",BYTEARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')');
break; break;
case 'x': case 'x':
this.doExecOptions(asArgs); this.doExecOptions(asArgs);

View file

@ -64,12 +64,12 @@ var PREFETCH = false;
/** /**
* @define {boolean} * @define {boolean}
* *
* FATARRAYS is a Closure Compiler compile-time option that allocates an Array of numbers for every Memory block, * BYTEARRAYS is a Closure Compiler compile-time option that allocates an Array of numbers for every Memory block,
* where each a number represents ONE byte; very wasteful, but potentially slightly faster. * where each a number represents ONE byte; very wasteful, but potentially slightly faster.
* *
* See the Memory component for details. * See the Memory component for details.
*/ */
var FATARRAYS = false; var BYTEARRAYS = false;
/** /**
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've * TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've
@ -147,7 +147,7 @@ if (NODE) {
global.PCJSCLASS = PCJSCLASS; global.PCJSCLASS = PCJSCLASS;
global.DEBUGGER = DEBUGGER; global.DEBUGGER = DEBUGGER;
global.PREFETCH = PREFETCH; global.PREFETCH = PREFETCH;
global.FATARRAYS = FATARRAYS; global.BYTEARRAYS = BYTEARRAYS;
global.TYPEDARRAYS = TYPEDARRAYS; global.TYPEDARRAYS = TYPEDARRAYS;
global.BACKTRACK = BACKTRACK; global.BACKTRACK = BACKTRACK;
global.SYMBOLS = SYMBOLS; global.SYMBOLS = SYMBOLS;

View file

@ -75,7 +75,7 @@ var littleEndian = (TYPEDARRAYS? (function() {
* (LONGARRAYS) and shifting/masking bytes/words to/from dwords; in theory, byte accesses would * (LONGARRAYS) and shifting/masking bytes/words to/from dwords; in theory, byte accesses would
* be faster and word accesses somewhat less faster. * be faster and word accesses somewhat less faster.
* *
* However, preliminary testing of that feature (FATARRAYS) did not yield significantly faster * However, preliminary testing of that feature (BYTEARRAYS) did not yield significantly faster
* performance, so it is OFF by default to minimize our memory consumption. Using TYPEDARRAYS * performance, so it is OFF by default to minimize our memory consumption. Using TYPEDARRAYS
* would seem best, but as discussed in defines.js, it's off by default, because it doesn't perform * would seem best, but as discussed in defines.js, it's off by default, because it doesn't perform
* as well as LONGARRAYS; the other advantage of TYPEDARRAYS is that it should theoretically use * as well as LONGARRAYS; the other advantage of TYPEDARRAYS is that it should theoretically use
@ -110,7 +110,6 @@ function Memory(addr, used, size, type, controller, cpu)
this.controller = null; this.controller = null;
this.cpu = cpu; // if a CPU reference is provided, then this must be an UNPAGED Memory block allocation this.cpu = cpu; // if a CPU reference is provided, then this must be an UNPAGED Memory block allocation
this.fDirty = this.fDirtyEver = false; this.fDirty = this.fDirtyEver = false;
this.setPhysBlock();
this.copyBreakpoints(); // initialize the block's Debugger info (eg, breakpoint totals); the caller will reinitialize this.copyBreakpoints(); // initialize the block's Debugger info (eg, breakpoint totals); the caller will reinitialize
if (BACKTRACK) { if (BACKTRACK) {
@ -170,13 +169,13 @@ function Memory(addr, used, size, type, controller, cpu)
this.ab = new Uint8Array(this.buffer, 0, size); this.ab = new Uint8Array(this.buffer, 0, size);
this.aw = new Uint16Array(this.buffer, 0, size >> 1); this.aw = new Uint16Array(this.buffer, 0, size >> 1);
this.adw = new Int32Array(this.buffer, 0, size >> 2); this.adw = new Int32Array(this.buffer, 0, size >> 2);
this.setAccess(littleEndian? Memory.afnLittleEndian : Memory.afnBigEndian); this.setAccess(littleEndian? Memory.afnArrayLE : Memory.afnArrayBE);
} else { } else {
if (FATARRAYS) { if (BYTEARRAYS) {
this.ab = new Array(size); this.ab = new Array(size);
} else { } else {
/* /*
* NOTE: This is the default mode of operation (!TYPEDARRAYS && !FATARRAYS), because it * NOTE: This is the default mode of operation (!TYPEDARRAYS && !BYTEARRAYS), because it
* seems to provide the best performance; and although in theory, that performance might * seems to provide the best performance; and although in theory, that performance might
* come at twice the overhead of TYPEDARRAYS, it's increasingly likely that the JavaScript * come at twice the overhead of TYPEDARRAYS, it's increasingly likely that the JavaScript
* runtime will notice that all we ever store are 32-bit values, and optimize accordingly. * runtime will notice that all we ever store are 32-bit values, and optimize accordingly.
@ -287,9 +286,9 @@ Memory.prototype = {
this.ab = mem.ab; this.ab = mem.ab;
this.aw = mem.aw; this.aw = mem.aw;
this.adw = mem.adw; this.adw = mem.adw;
this.setAccess(littleEndian? Memory.afnLittleEndian : Memory.afnBigEndian); this.setAccess(littleEndian? Memory.afnArrayLE : Memory.afnArrayBE);
} else { } else {
if (FATARRAYS) { if (BYTEARRAYS) {
this.ab = mem.ab; this.ab = mem.ab;
} else { } else {
this.adw = mem.adw; this.adw = mem.adw;
@ -315,7 +314,7 @@ Memory.prototype = {
if (this.controller) { if (this.controller) {
adw = null; adw = null;
} }
else if (FATARRAYS) { else if (BYTEARRAYS) {
adw = new Array(this.size >> 2); adw = new Array(this.size >> 2);
var off = 0; var off = 0;
for (i = 0; i < adw.length; i++) { for (i = 0; i < adw.length; i++) {
@ -367,11 +366,11 @@ Memory.prototype = {
* memory blocks installed at the programmed address, and so we arrived here at a block with * memory blocks installed at the programmed address, and so we arrived here at a block with
* no controller AND no data. * no controller AND no data.
*/ */
// DEBUG: Component.assert(adw != null); Component.assert(adw != null);
if (adw && this.size == adw.length << 2) { if (adw && this.size == adw.length << 2) {
var i; var i;
if (FATARRAYS) { if (BYTEARRAYS) {
var off = 0; var off = 0;
for (i = 0; i < adw.length; i++) { for (i = 0; i < adw.length; i++) {
this.ab[off] = adw[i] & 0xff; this.ab[off] = adw[i] & 0xff;
@ -399,7 +398,7 @@ Memory.prototype = {
* *
* @this {Memory} * @this {Memory}
* @param {Array.<function()>} [afn] function table * @param {Array.<function()>} [afn] function table
* @param {boolean} [fDirect] * @param {boolean} [fDirect] (true to update direct access functions as well; default is true)
*/ */
setAccess: function(afn, fDirect) { setAccess: function(afn, fDirect) {
if (!afn) { if (!afn) {
@ -495,20 +494,32 @@ Memory.prototype = {
* setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE) * setPhysBlock(blockPhys, blockPDE, offPDE, blockPTE, offPTE)
* *
* @this {Memory} * @this {Memory}
* @param {Memory|null} [blockPhys] * @param {Memory} blockPhys
* @param {Memory|null} [blockPDE] * @param {Memory} blockPDE
* @param {number} [offPDE] * @param {number} offPDE
* @param {Memory|null} [blockPTE] * @param {Memory} blockPTE
* @param {number} [offPTE] * @param {number} offPTE
*/ */
setPhysBlock: function(blockPhys, blockPDE, offPDE, blockPTE, offPTE) { setPhysBlock: function(blockPhys, blockPDE, offPDE, blockPTE, offPTE) {
this.blockPhys = blockPhys;
this.blockPDE = blockPDE; this.blockPDE = blockPDE;
this.iPDE = offPDE >> 2; // convert offPDE into iPDE (an adw index) this.iPDE = offPDE >> 2; // convert offPDE into iPDE (an adw index)
this.blockPTE = blockPTE; this.blockPTE = blockPTE;
this.iPTE = offPTE >> 2; // convert offPTE into iPTE (an adw index) this.iPTE = offPTE >> 2; // convert offPTE into iPTE (an adw index)
this.bitPTEDirty = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY) : 0; /*
this.bitPTEAccessed = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED) : 0; * This is an optimization for "normal" pages, installing paged memory handlers that mimic
* normal memory but also know how to update page tables. If any of the criteria are not met
* for these special handlers, we fall back to the slower default "paged" memory handlers.
*/
if (TYPEDARRAYS && littleEndian && blockPhys.adw && !blockPhys.controller) {
this.ab = blockPhys.ab;
this.aw = blockPhys.aw;
this.adw = blockPhys.adw;
this.setAccess(Memory.afnPagedLE);
} else {
this.blockPhys = blockPhys;
this.bitPTEAccessed = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED) : 0;
this.bitPTEDirty = blockPhys? Memory.adjustEndian(X86.PTE.ACCESSED | X86.PTE.DIRTY) : 0;
}
}, },
/** /**
* printAddr(sMessage) * printAddr(sMessage)
@ -671,7 +682,6 @@ Memory.prototype = {
* @param {number} addr * @param {number} addr
*/ */
writeShortDefault: function writeShortDefault(off, w, addr) { writeShortDefault: function writeShortDefault(off, w, addr) {
// DEBUG: Component.assert(!(w & ~0xffff));
this.writeByte(off++, w & 0xff, addr++); this.writeByte(off++, w & 0xff, addr++);
this.writeByte(off, w >> 8, addr); this.writeByte(off, w >> 8, addr);
}, },
@ -698,8 +708,7 @@ Memory.prototype = {
* @return {number} * @return {number}
*/ */
readByteMemory: function readByteMemory(off, addr) { readByteMemory: function readByteMemory(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size); if (BYTEARRAYS) {
if (FATARRAYS) {
return this.ab[off]; return this.ab[off];
} }
return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff); return ((this.adw[off >> 2] >>> ((off & 0x3) << 3)) & 0xff);
@ -713,8 +722,7 @@ Memory.prototype = {
* @return {number} * @return {number}
*/ */
readShortMemory: function readShortMemory(off, addr) { readShortMemory: function readShortMemory(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1); if (BYTEARRAYS) {
if (FATARRAYS) {
return this.ab[off] | (this.ab[off + 1] << 8); return this.ab[off] | (this.ab[off + 1] << 8);
} }
var w; var w;
@ -737,8 +745,7 @@ Memory.prototype = {
* @return {number} * @return {number}
*/ */
readLongMemory: function readLongMemory(off, addr) { readLongMemory: function readLongMemory(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3); if (BYTEARRAYS) {
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);
} }
var idw = off >> 2; var idw = off >> 2;
@ -759,8 +766,7 @@ Memory.prototype = {
* @param {number} addr * @param {number} addr
*/ */
writeByteMemory: function writeByteMemory(off, b, addr) { writeByteMemory: function writeByteMemory(off, b, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size && (b & 0xff) == b); if (BYTEARRAYS) {
if (FATARRAYS) {
this.ab[off] = b; this.ab[off] = b;
} else { } else {
var idw = off >> 2; var idw = off >> 2;
@ -778,8 +784,7 @@ Memory.prototype = {
* @param {number} addr * @param {number} addr
*/ */
writeShortMemory: function writeShortMemory(off, w, addr) { writeShortMemory: function writeShortMemory(off, w, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1 && (w & 0xffff) == w); if (BYTEARRAYS) {
if (FATARRAYS) {
this.ab[off] = (w & 0xff); this.ab[off] = (w & 0xff);
this.ab[off + 1] = (w >> 8); this.ab[off + 1] = (w >> 8);
} else { } else {
@ -804,8 +809,7 @@ Memory.prototype = {
* @param {number} addr * @param {number} addr
*/ */
writeLongMemory: function writeLongMemory(off, l, addr) { writeLongMemory: function writeLongMemory(off, l, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3); if (BYTEARRAYS) {
if (FATARRAYS) {
this.ab[off] = (l & 0xff); this.ab[off] = (l & 0xff);
this.ab[off + 1] = (l >> 8) & 0xff; this.ab[off + 1] = (l >> 8) & 0xff;
this.ab[off + 2] = (l >> 16) & 0xff; this.ab[off + 2] = (l >> 16) & 0xff;
@ -1071,51 +1075,60 @@ Memory.prototype = {
this.getPageBlock(addr, true).writeLong(off, l, addr); this.getPageBlock(addr, true).writeLong(off, l, addr);
}, },
/** /**
* readByteBigEndian(off, addr) * readByteBE(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @return {number} * @return {number}
*/ */
readByteBigEndian: function readByteBigEndian(off, addr) { readByteBE: function readByteBE(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
return this.ab[off]; return this.ab[off];
}, },
/** /**
* readByteLittleEndian(off, addr) * readByteLE(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @return {number} * @return {number}
*/ */
readByteLittleEndian: function readByteLittleEndian(off, addr) { readByteLE: function readByteLE(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
return this.ab[off]; return this.ab[off];
}, },
/** /**
* readShortBigEndian(off, addr) * readBytePLE(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @return {number} * @return {number}
*/ */
readShortBigEndian: function readShortBigEndian(off, addr) { readBytePLE: function readBytePLE(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1); this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED;
return this.ab[off];
},
/**
* readShortBE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readShortBE: function readShortBE(off, addr) {
return this.dv.getUint16(off, true); return this.dv.getUint16(off, true);
}, },
/** /**
* readShortLittleEndian(off, addr) * readShortLE(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @return {number} * @return {number}
*/ */
readShortLittleEndian: function readShortLittleEndian(off, addr) { readShortLE: function readShortLE(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read * TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts. * vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1123,27 +1136,42 @@ 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, addr) * readShortPLE(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @return {number} * @return {number}
*/ */
readLongBigEndian: function readLongBigEndian(off, addr) { readShortPLE: function readShortPLE(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3); /*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED;
return (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1];
},
/**
* readLongBE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongBE: function readLongBE(off, addr) {
return this.dv.getInt32(off, true); return this.dv.getInt32(off, true);
}, },
/** /**
* readLongLittleEndian(off, addr) * readLongLE(off, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @return {number} * @return {number}
*/ */
readLongLittleEndian: function readLongLittleEndian(off, addr) { readLongLE: function readLongLE(off, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read * TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts. * vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1151,54 +1179,81 @@ 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, addr) * readLongPLE(off, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readLongPLE: function readLongPLE(off, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned read
* vs. always reading the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED;
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];
},
/**
* writeByteBE(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} b * @param {number} b
* @param {number} addr * @param {number} addr
*/ */
writeByteBigEndian: function writeByteBigEndian(off, b, addr) { writeByteBE: function writeByteBE(off, b, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
this.ab[off] = b; this.ab[off] = b;
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeByteLittleEndian(off, b, addr) * writeByteLE(off, b, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @param {number} b * @param {number} b
*/ */
writeByteLittleEndian: function writeByteLittleEndian(off, b, addr) { writeByteLE: function writeByteLE(off, b, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
this.ab[off] = b; this.ab[off] = b;
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeShortBigEndian(off, w, addr) * writeBytePLE(off, b, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} b
*/
writeBytePLE: function writeBytePLE(off, b, addr) {
this.ab[off] = b;
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
},
/**
* writeShortBE(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @param {number} w * @param {number} w
*/ */
writeShortBigEndian: function writeShortBigEndian(off, w, addr) { writeShortBE: function writeShortBE(off, w, addr) {
// DEBUG: 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, addr) * writeShortLE(off, w, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} addr * @param {number} addr
* @param {number} w * @param {number} w
*/ */
writeShortLittleEndian: function writeShortLittleEndian(off, w, addr) { writeShortLE: function writeShortLE(off, w, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 1);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write * TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts. * vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1212,28 +1267,49 @@ Memory.prototype = {
this.fDirty = true; this.fDirty = true;
}, },
/** /**
* writeLongBigEndian(off, l, addr) * writeShortPLE(off, w, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} addr
* @param {number} w
*/
writeShortPLE: function writeShortPLE(off, w, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
if (off & 0x1) {
this.ab[off] = w;
this.ab[off+1] = w >> 8;
} else {
this.aw[off >> 1] = w;
}
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
},
/**
* writeLongBE(off, l, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} l * @param {number} l
* @param {number} addr * @param {number} addr
*/ */
writeLongBigEndian: function writeLongBigEndian(off, l, addr) { writeLongBE: function writeLongBE(off, l, addr) {
// DEBUG: 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, addr) * writeLongLE(off, l, addr)
* *
* @this {Memory} * @this {Memory}
* @param {number} off * @param {number} off
* @param {number} l * @param {number} l
* @param {number} addr * @param {number} addr
*/ */
writeLongLittleEndian: function writeLongLittleEndian(off, l, addr) { writeLongLE: function writeLongLE(off, l, addr) {
// DEBUG: Component.assert(off >= 0 && off < this.size - 3);
/* /*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write * TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts. * vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
@ -1248,6 +1324,31 @@ Memory.prototype = {
} }
this.fDirty = true; this.fDirty = true;
}, },
/**
* writeLongPLE(off, l, addr)
*
* @this {Memory}
* @param {number} off
* @param {number} l
* @param {number} addr
*/
writeLongPLE: function writeLongPLE(off, l, addr) {
/*
* TODO: It remains to be seen if there's any advantage to checking the offset for an aligned write
* vs. always writing the bytes separately; it seems a safe bet for longs, but it's less clear for shorts.
*/
if (off & 0x3) {
this.ab[off] = l;
this.ab[off+1] = (l >> 8);
this.ab[off+2] = (l >> 16);
this.ab[off+3] = (l >> 24);
} else {
this.adw[off >> 2] = l;
}
this.blockPDE.adw[this.iPDE] |= X86.PTE.ACCESSED;
this.blockPTE.adw[this.iPTE] |= X86.PTE.ACCESSED | X86.PTE.DIRTY;
this.fDirty = true;
},
/** /**
* readBackTrackNone(off) * readBackTrackNone(off)
* *
@ -1284,7 +1385,6 @@ Memory.prototype = {
* @return {number} * @return {number}
*/ */
readBackTrackIndex: function readBackTrackIndex(off) { readBackTrackIndex: function readBackTrackIndex(off) {
// DEBUG: Component.assert(off >= 0 && off < this.size);
return this.abtIndexes[off]; return this.abtIndexes[off];
}, },
/** /**
@ -1297,7 +1397,6 @@ Memory.prototype = {
*/ */
writeBackTrackIndex: function writeBackTrackIndex(off, bti) { writeBackTrackIndex: function writeBackTrackIndex(off, bti) {
var btiPrev; var btiPrev;
// DEBUG: Component.assert(off >= 0 && off < this.size);
btiPrev = this.abtIndexes[off]; btiPrev = this.abtIndexes[off];
this.abtIndexes[off] = bti; this.abtIndexes[off] = bti;
return btiPrev; return btiPrev;
@ -1320,21 +1419,22 @@ Memory.prototype = {
* This is the effective definition of afnNone, but we need not fully define it, because setAccess() * This is the effective definition of afnNone, but we need not fully define it, because setAccess()
* uses these defaults when any of the 6 handlers (ie, 3 read handlers and 3 write handlers) are undefined. * uses these defaults when any of the 6 handlers (ie, 3 read handlers and 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.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.readLongDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault, Memory.prototype.writeLongDefault];
*/ */
Memory.afnNone = []; Memory.afnNone = [];
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.readLongMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory, Memory.prototype.writeLongMemory]; 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]; Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
if (PAGEBLOCKS) { if (PAGEBLOCKS) {
Memory.afnPaged = [Memory.prototype.readBytePaged, Memory.prototype.readShortPaged, Memory.prototype.readLongPaged, Memory.prototype.writeBytePaged, Memory.prototype.writeShortPaged, Memory.prototype.writeLongPaged]; 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]; 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.afnArrayBE = [Memory.prototype.readByteBE, Memory.prototype.readShortBE, Memory.prototype.readLongBE, Memory.prototype.writeByteBE, Memory.prototype.writeShortBE, Memory.prototype.writeLongBE];
Memory.afnLittleEndian = [Memory.prototype.readByteLittleEndian, Memory.prototype.readShortLittleEndian, Memory.prototype.readLongLittleEndian, Memory.prototype.writeByteLittleEndian, Memory.prototype.writeShortLittleEndian, Memory.prototype.writeLongLittleEndian]; Memory.afnArrayLE = [Memory.prototype.readByteLE, Memory.prototype.readShortLE, Memory.prototype.readLongLE, Memory.prototype.writeByteLE, Memory.prototype.writeShortLE, Memory.prototype.writeLongLE];
Memory.afnPagedLE = [Memory.prototype.readBytePLE, Memory.prototype.readShortPLE, Memory.prototype.readLongPLE, Memory.prototype.writeBytePLE, Memory.prototype.writeShortPLE, Memory.prototype.writeLongPLE];
} }
if (NODE) module.exports = Memory; if (NODE) module.exports = Memory;