New improved I/O handler functions for the PDP-11

This commit is contained in:
Jeff 2016-09-21 12:44:25 -07:00 committed by Jeff Parsons
commit dfe367f53d
18 changed files with 847 additions and 1059 deletions

View file

@ -59,11 +59,6 @@ if (NODE) {
* addMemory(). If the component needs something more than simple read/write storage,
* it must provide a custom controller.
*
* All port (I/O) operations are defined by external handlers; they register with us,
* and we manage those registrations and provide support for I/O breakpoints, but the
* only default I/O behavior we provide is ignoring writes to any unregistered output
* ports and returning 0xff from any unregistered input ports.
*
* @constructor
* @extends Component
* @param {Object} parmsBus
@ -80,35 +75,16 @@ function Bus(parmsBus, cpu, dbg)
this.nBusWidth = parmsBus['busWidth'] || 16;
/*
* Compute all Bus memory block parameters, based on the width of the bus.
*
* Regarding blockTotal, we want to avoid using block overflow expressions like:
*
* iBlock < this.nBlockTotal? iBlock : 0
*
* As long as we know that blockTotal is a power of two (eg, 256 or 0x100, in the case of
* nBusWidth == 20 and blockSize == 4096), we can define blockMask as (blockTotal - 1) and
* rewrite the previous expression as:
*
* iBlock & this.nBlockMask
*
* Bus Property Old hard-coded values (when nBusWidth was always 20)
* ------------ ----------------------------------------------------
* this.nBusLimit 0xfffff
* this.nBusMask [same as busLimit]
* this.nBlockSize 4096
* this.nBlockLen (this.nBlockSize >> 2)
* this.nBlockShift 12
* this.nBlockLimit 0xfff
* this.nBlockTotal ((this.nBusLimit + this.nBlockSize) / this.nBlockSize) | 0
* this.nBlockMask (this.nBlockTotal - 1) [ie, 0xff]
*
* Note that we choose a nBlockShift value (and thus a physical memory block size) based on "buswidth":
* Compute all Bus6502 memory block parameters, based on the width of the bus. The entire
* address space is divided into blocks, using a block size that is (hopefully) appropriate to
* the bus width. The following table summarizes our simplistic calculations.
*
* Bus Width Block Shift Block Size
* --------- ----------- ----------
* 16 bits (64Kb address space): 10 1Kb (64 maximum blocks)
* 18 bits (256Kb address space): 11 2Kb (128 maximum blocks)
* 20 bits (1Mb address space): 12 4Kb (256 maximum blocks)
* 22 bits (4Mb address space): 13 8Kb (512 maximum blocks)
* 24 bits (16Mb address space): 14 16Kb (1K maximum blocks)
* 32 bits (4Gb address space); 15 32Kb (128K maximum blocks)
*
@ -119,7 +95,9 @@ function Bus(parmsBus, cpu, dbg)
*/
this.addrTotal = Math.pow(2, this.nBusWidth);
this.nBusLimit = this.nBusMask = (this.addrTotal - 1) | 0;
this.nBlockShift = (this.nBusWidth <= 16)? 10 : ((this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15));
this.nBlockShift = (this.nBusWidth >> 1) + 2;
if (this.nBlockShift < 10) this.nBlockShift = 10;
if (this.nBlockShift > 15) this.nBlockShift = 15;
this.nBlockSize = 1 << this.nBlockShift;
this.nBlockLen = this.nBlockSize >> 2;
this.nBlockLimit = this.nBlockSize - 1;
@ -127,39 +105,6 @@ function Bus(parmsBus, cpu, dbg)
this.nBlockMask = this.nBlockTotal - 1;
this.assert(this.nBlockMask <= Bus.BlockInfo.num.mask);
/*
* Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by
* port, of sub-arrays which contain:
*
* [0]: registered function to call for every I/O access
*
* The registered function is called with the port address, and if the access was triggered by the CPU,
* the instruction pointer (IP) at the point of access.
*
* WARNING: Unlike the (old) read and write memory notification functions, these support only one
* pair of input/output functions per port. A more sophisticated architecture could support a list
* of chained functions across multiple components, but I doubt that will be necessary here.
*
* UPDATE: The Debugger now piggy-backs on these arrays to indicate ports for which it wants notification
* of I/O. In those cases, the registered component/function elements may or may not be set, but the
* following additional element will be set:
*
* [1]: true to break on I/O, false to ignore I/O
*
* The false case is important if fPortInputBreakAll and/or fPortOutputBreakAll is set, because it allows the
* Debugger to selectively ignore specific ports.
*/
this.aPortInputNotify = [];
this.aPortOutputNotify = [];
this.fPortInputBreakAll = this.fPortOutputBreakAll = false;
/*
* By default, all I/O ports are 1 byte wide; ports that are wider must add themselves to one or both of
* these lists, using addPortInputWidth() and/or addPortOutputWidth().
*/
this.aPortInputWidth = [];
this.aPortOutputWidth = [];
/*
* Allocate empty Memory blocks to span the entire physical address space.
*/
@ -177,38 +122,6 @@ Bus.ERROR = {
REM_MEM_BADRANGE: 5
};
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
Bus.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo;
/**
* initMemory()
*
@ -365,6 +278,42 @@ Bus.prototype.cleanMemory = function(addr, size)
return fClean;
};
/*
* Data types used by scanMemory()
*/
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
Bus.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo;
/**
* scanMemory(info, addr, size)
*
@ -741,309 +690,6 @@ Bus.prototype.restoreMemory = function(a)
return true;
};
/**
* addPortInputBreak(port)
*
* @this {Bus}
* @param {number} [port]
* @return {boolean} true if break on port input enabled, false if disabled
*/
Bus.prototype.addPortInputBreak = function(port)
{
if (port === undefined) {
this.fPortInputBreakAll = !this.fPortInputBreakAll;
return this.fPortInputBreakAll;
}
if (this.aPortInputNotify[port] === undefined) {
this.aPortInputNotify[port] = [null, false];
}
this.aPortInputNotify[port][1] = !this.aPortInputNotify[port][1];
return this.aPortInputNotify[port][1];
};
/**
* addPortInputNotify(start, end, fn)
*
* Add a port input-notification handler to the list of such handlers.
*
* @this {Bus}
* @param {number} start port address
* @param {number} end port address
* @param {function(number,number)} fn is called with the port and IP values at the time of the input
*/
Bus.prototype.addPortInputNotify = function(start, end, fn)
{
if (fn !== undefined) {
for (var port = start; port <= end; port++) {
if (this.aPortInputNotify[port] !== undefined) {
Component.warning("Input port " + str.toHexWord(port) + " already registered");
continue;
}
this.aPortInputNotify[port] = [fn, false];
if (MAXDEBUG) this.log("addPortInputNotify(" + str.toHexWord(port) + ")");
}
}
};
/**
* addPortInputTable(component, table, offset)
*
* Add port input-notification handlers from the specified table (a batch version of addPortInputNotify)
*
* @this {Bus}
* @param {Component} component
* @param {Object} table
* @param {number} [offset] is an optional port offset
*/
Bus.prototype.addPortInputTable = function(component, table, offset)
{
if (offset === undefined) offset = 0;
for (var port in table) {
this.addPortInputNotify(+port + offset, +port + offset, table[port].bind(component));
}
};
/**
* addPortInputWidth(port, size)
*
* By default, all input ports are 1 byte wide; ports that are wider must call this function.
*
* @this {Bus}
* @param {number} port
* @param {number} size (1, 2 or 4)
*/
Bus.prototype.addPortInputWidth = function(port, size)
{
this.aPortInputWidth[port] = size;
};
/**
* checkPortInputNotify(port, size, addrIP)
*
* @this {Bus}
* @param {number} port
* @param {number} size (1, 2 or 4)
* @param {number} [addrIP] is the IP value at the time of the input
* @return {number} simulated port data
*
* NOTE: It seems that parts of the ROM BIOS (like the RS-232 probes around F000:E5D7 in the 5150 BIOS)
* assume that ports for non-existent hardware return 0xff rather than 0x00, hence my new default (0xff) below.
*/
Bus.prototype.checkPortInputNotify = function(port, size, addrIP)
{
var data = 0, shift = 0;
while (size > 0) {
var aNotify = this.aPortInputNotify[port];
var sizePort = this.aPortInputWidth[port] || 1;
var maskPort = (sizePort == 1? 0xff : (sizePort == 2? 0xffff : -1));
var dataPort = maskPort;
/*
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port (ditto for 16-bit I/O
* to a 32-bit port). We probably should pass the size through to the aNotify[0] handler,
* and let it decide what to do, but I don't feel like changing all the I/O handlers right now.
* The good news, at least, is that the 8-bit handlers would not have to do anything special.
* This assert will warn us if this is a pressing need.
*/
this.assert(size >= sizePort);
if (aNotify !== undefined) {
if (aNotify[0]) {
dataPort = aNotify[0](port, addrIP);
if (dataPort === undefined) {
dataPort = maskPort;
} else {
dataPort &= maskPort;
}
}
if (DEBUGGER && this.dbg && this.fPortInputBreakAll != aNotify[1]) {
this.dbg.checkPortInput(port, size, dataPort);
}
}
else {
if (DEBUGGER && this.dbg) {
this.dbg.messageIO(this, port, null, addrIP);
if (this.fPortInputBreakAll) this.dbg.checkPortInput(port, size, dataPort);
}
}
data |= dataPort << shift;
shift += (sizePort << 3);
port += sizePort;
size -= sizePort;
}
this.assert(!size);
return data;
};
/**
* removePortInputNotify(start, end)
*
* Remove port input-notification handler(s) (to be ENABLED later if needed)
*
* @this {Bus}
* @param {number} start address
* @param {number} end address
*
Bus.prototype.removePortInputNotify = function(start, end)
{
for (var port = start; port < end; port++) {
if (this.aPortInputNotify[port]) {
delete this.aPortInputNotify[port];
}
}
};
*/
/**
* addPortOutputBreak(port)
*
* @this {Bus}
* @param {number} [port]
* @return {boolean} true if break on port output enabled, false if disabled
*/
Bus.prototype.addPortOutputBreak = function(port)
{
if (port === undefined) {
this.fPortOutputBreakAll = !this.fPortOutputBreakAll;
return this.fPortOutputBreakAll;
}
if (this.aPortOutputNotify[port] === undefined) {
this.aPortOutputNotify[port] = [null, false];
}
this.aPortOutputNotify[port][1] = !this.aPortOutputNotify[port][1];
return this.aPortOutputNotify[port][1];
};
/**
* addPortOutputNotify(start, end, fn)
*
* Add a port output-notification handler to the list of such handlers.
*
* @this {Bus}
* @param {number} start port address
* @param {number} end port address
* @param {function(number,number)} fn is called with the port and IP values at the time of the output
*/
Bus.prototype.addPortOutputNotify = function(start, end, fn)
{
if (fn !== undefined) {
for (var port = start; port <= end; port++) {
if (this.aPortOutputNotify[port] !== undefined) {
Component.warning("Output port " + str.toHexWord(port) + " already registered");
continue;
}
this.aPortOutputNotify[port] = [fn, false];
if (MAXDEBUG) this.log("addPortOutputNotify(" + str.toHexWord(port) + ")");
}
}
};
/**
* addPortOutputTable(component, table, offset)
*
* Add port output-notification handlers from the specified table (a batch version of addPortOutputNotify)
*
* @this {Bus}
* @param {Component} component
* @param {Object} table
* @param {number} [offset] is an optional port offset
*/
Bus.prototype.addPortOutputTable = function(component, table, offset)
{
if (offset === undefined) offset = 0;
for (var port in table) {
this.addPortOutputNotify(+port + offset, +port + offset, table[port].bind(component));
}
};
/**
* addPortOutputWidth(port, size)
*
* By default, all output ports are 1 byte wide; ports that are wider must call this function.
*
* @this {Bus}
* @param {number} port
* @param {number} size (1, 2 or 4)
*/
Bus.prototype.addPortOutputWidth = function(port, size)
{
this.aPortOutputWidth[port] = size;
};
/**
* checkPortOutputNotify(port, size, data, addrIP)
*
* @this {Bus}
* @param {number} port
* @param {number} size
* @param {number} data
* @param {number} [addrIP] is the IP value at the time of the output
*/
Bus.prototype.checkPortOutputNotify = function(port, size, data, addrIP)
{
var shift = 0;
while (size > 0) {
var aNotify = this.aPortOutputNotify[port];
var sizePort = this.aPortOutputWidth[port] || 1;
var maskPort = (sizePort == 1? 0xff : (sizePort == 2? 0xffff : -1));
var dataPort = (data >>>= shift) & maskPort;
/*
* TODO: We need to decide what to do about 8-bit I/O to a 16-bit port (ditto for 16-bit I/O
* to a 32-bit port). We probably should pass the size through to the aNotify[0] handler,
* and let it decide what to do, but I don't feel like changing all the I/O handlers right now.
* The good news, at least, is that the 8-bit handlers would not have to do anything special.
* This assert will warn us if this is a pressing need.
*/
this.assert(size >= sizePort);
if (aNotify !== undefined) {
if (aNotify[0]) {
aNotify[0](port, dataPort, addrIP);
}
if (DEBUGGER && this.dbg && this.fPortOutputBreakAll != aNotify[1]) {
this.dbg.checkPortOutput(port, size, dataPort);
}
}
else {
if (DEBUGGER && this.dbg) {
this.dbg.messageIO(this, port, dataPort, addrIP);
if (this.fPortOutputBreakAll) this.dbg.checkPortOutput(port, size, dataPort);
}
}
shift += (sizePort << 3);
port += sizePort;
size -= sizePort;
}
this.assert(!size);
};
/**
* removePortOutputNotify(start, end)
*
* Remove port output-notification handler(s) (to be ENABLED later if needed)
*
* @this {Bus}
* @param {number} start address
* @param {number} end address
*
Bus.prototype.removePortOutputNotify = function(start, end)
{
for (var port = start; port < end; port++) {
if (this.aPortOutputNotify[port]) {
delete this.aPortOutputNotify[port];
}
}
};
*/
/**
* reportError(op, addr, size, fQuiet)
*

View file

@ -807,18 +807,45 @@ Memory.prototype = {
/*
* 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 4 handlers (ie, 2 byte handlers and 2 short handlers) are undefined.
*
Memory.afnNone = [Memory.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault];
Memory.afnNone = [
Memory.prototype.readNone,
Memory.prototype.writeNone,
Memory.prototype.readShortDefault,
Memory.prototype.writeShortDefault
];
*/
Memory.afnNone = [];
Memory.afnNone = [];
Memory.afnMemory = [Memory.prototype.readByteMemory, Memory.prototype.readShortMemory, Memory.prototype.writeByteMemory, Memory.prototype.writeShortMemory];
Memory.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked];
Memory.afnMemory = [
Memory.prototype.readByteMemory,
Memory.prototype.writeByteMemory,
Memory.prototype.readShortMemory,
Memory.prototype.writeShortMemory
];
Memory.afnChecked = [
Memory.prototype.readByteChecked,
Memory.prototype.writeByteChecked,
Memory.prototype.readShortChecked,
Memory.prototype.writeShortChecked
];
if (TYPEDARRAYS) {
Memory.afnArrayBE = [Memory.prototype.readByteBE, Memory.prototype.readShortBE, Memory.prototype.writeByteBE, Memory.prototype.writeShortBE];
Memory.afnArrayLE = [Memory.prototype.readByteLE, Memory.prototype.readShortLE, Memory.prototype.writeByteLE, Memory.prototype.writeShortLE];
Memory.afnArrayBE = [
Memory.prototype.readByteBE,
Memory.prototype.writeByteBE,
Memory.prototype.readShortBE,
Memory.prototype.writeShortBE
];
Memory.afnArrayLE = [
Memory.prototype.readByteLE,
Memory.prototype.writeByteLE,
Memory.prototype.readShortLE,
Memory.prototype.writeShortLE
];
}
if (NODE) module.exports = Memory;

View file

@ -76,35 +76,16 @@ function Bus8080(parmsBus, cpu, dbg)
this.nBusWidth = parmsBus['busWidth'] || 16;
/*
* Compute all Bus8080 memory block parameters, based on the width of the bus.
*
* Regarding blockTotal, we want to avoid using block overflow expressions like:
*
* iBlock < this.nBlockTotal? iBlock : 0
*
* As long as we know that blockTotal is a power of two (eg, 256 or 0x100, in the case of
* nBusWidth == 20 and blockSize == 4096), we can define blockMask as (blockTotal - 1) and
* rewrite the previous expression as:
*
* iBlock & this.nBlockMask
*
* Bus Property Old hard-coded values (when nBusWidth was always 20)
* ------------ ----------------------------------------------------
* this.nBusLimit 0xfffff
* this.nBusMask [same as busLimit]
* this.nBlockSize 4096
* this.nBlockLen (this.nBlockSize >> 2)
* this.nBlockShift 12
* this.nBlockLimit 0xfff
* this.nBlockTotal ((this.nBusLimit + this.nBlockSize) / this.nBlockSize) | 0
* this.nBlockMask (this.nBlockTotal - 1) [ie, 0xff]
*
* Note that we choose a nBlockShift value (and thus a physical memory block size) based on "buswidth":
* Compute all Bus8080 memory block parameters, based on the width of the bus. The entire
* address space is divided into blocks, using a block size that is (hopefully) appropriate to
* the bus width. The following table summarizes our simplistic calculations.
*
* Bus Width Block Shift Block Size
* --------- ----------- ----------
* 16 bits (64Kb address space): 10 1Kb (64 maximum blocks)
* 18 bits (256Kb address space): 11 2Kb (128 maximum blocks)
* 20 bits (1Mb address space): 12 4Kb (256 maximum blocks)
* 22 bits (4Mb address space): 13 8Kb (512 maximum blocks)
* 24 bits (16Mb address space): 14 16Kb (1K maximum blocks)
* 32 bits (4Gb address space); 15 32Kb (128K maximum blocks)
*
@ -115,7 +96,9 @@ function Bus8080(parmsBus, cpu, dbg)
*/
this.addrTotal = Math.pow(2, this.nBusWidth);
this.nBusLimit = this.nBusMask = (this.addrTotal - 1) | 0;
this.nBlockShift = (this.nBusWidth <= 16)? 10 : ((this.nBusWidth <= 20)? 12 : (this.nBusWidth <= 24? 14 : 15));
this.nBlockShift = (this.nBusWidth >> 1) + 2;
if (this.nBlockShift < 10) this.nBlockShift = 10;
if (this.nBlockShift > 15) this.nBlockShift = 15;
this.nBlockSize = 1 << this.nBlockShift;
this.nBlockLen = this.nBlockSize >> 2;
this.nBlockLimit = this.nBlockSize - 1;
@ -173,38 +156,6 @@ Bus8080.ERROR = {
REM_MEM_BADRANGE: 5
};
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
Bus8080.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo8080 object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo8080;
/**
* initMemory()
*
@ -361,6 +312,42 @@ Bus8080.prototype.cleanMemory = function(addr, size)
return fClean;
};
/*
* Data types used by scanMemory()
*/
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
Bus8080.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo8080 object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo8080;
/**
* scanMemory(info, addr, size)
*

View file

@ -384,11 +384,11 @@ Memory8080.prototype = {
setReadAccess: function(afn, fDirect) {
if (!fDirect || !this.cReadBreakpoints) {
this.readByte = afn[0] || this.readNone;
this.readShort = afn[1] || this.readShortDefault;
this.readShort = afn[2] || this.readShortDefault;
}
if (fDirect || fDirect === undefined) {
this.readByteDirect = afn[0] || this.readNone;
this.readShortDirect = afn[1] || this.readShortDefault;
this.readShortDirect = afn[2] || this.readShortDefault;
}
},
/**
@ -400,11 +400,11 @@ Memory8080.prototype = {
*/
setWriteAccess: function(afn, fDirect) {
if (!fDirect || !this.cWriteBreakpoints) {
this.writeByte = !this.fReadOnly && afn[2] || this.writeNone;
this.writeByte = !this.fReadOnly && afn[1] || this.writeNone;
this.writeShort = !this.fReadOnly && afn[3] || this.writeShortDefault;
}
if (fDirect || fDirect === undefined) {
this.writeByteDirect = afn[2] || this.writeNone;
this.writeByteDirect = afn[1] || this.writeNone;
this.writeShortDirect = afn[3] || this.writeShortDefault;
}
},
@ -807,18 +807,45 @@ Memory8080.prototype = {
/*
* 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 4 handlers (ie, 2 byte handlers and 2 short handlers) are undefined.
*
Memory8080.afnNone = [Memory8080.prototype.readNone, Memory8080.prototype.readShortDefault, Memory8080.prototype.writeNone, Memory8080.prototype.writeShortDefault];
Memory8080.afnNone = [
Memory8080.prototype.readNone,
Memory8080.prototype.writeNone,
Memory8080.prototype.readShortDefault,
Memory8080.prototype.writeShortDefault
];
*/
Memory8080.afnNone = [];
Memory8080.afnNone = [];
Memory8080.afnMemory = [Memory8080.prototype.readByteMemory, Memory8080.prototype.readShortMemory, Memory8080.prototype.writeByteMemory, Memory8080.prototype.writeShortMemory];
Memory8080.afnChecked = [Memory8080.prototype.readByteChecked, Memory8080.prototype.readShortChecked, Memory8080.prototype.writeByteChecked, Memory8080.prototype.writeShortChecked];
Memory8080.afnMemory = [
Memory8080.prototype.readByteMemory,
Memory8080.prototype.writeByteMemory,
Memory8080.prototype.readShortMemory,
Memory8080.prototype.writeShortMemory
];
Memory8080.afnChecked = [
Memory8080.prototype.readByteChecked,
Memory8080.prototype.writeByteChecked,
Memory8080.prototype.readShortChecked,
Memory8080.prototype.writeShortChecked
];
if (TYPEDARRAYS) {
Memory8080.afnArrayBE = [Memory8080.prototype.readByteBE, Memory8080.prototype.readShortBE, Memory8080.prototype.writeByteBE, Memory8080.prototype.writeShortBE];
Memory8080.afnArrayLE = [Memory8080.prototype.readByteLE, Memory8080.prototype.readShortLE, Memory8080.prototype.writeByteLE, Memory8080.prototype.writeShortLE];
Memory8080.afnArrayBE = [
Memory8080.prototype.readByteBE,
Memory8080.prototype.writeByteBE,
Memory8080.prototype.readShortBE,
Memory8080.prototype.writeShortBE
];
Memory8080.afnArrayLE = [
Memory8080.prototype.readByteLE,
Memory8080.prototype.writeByteLE,
Memory8080.prototype.readShortLE,
Memory8080.prototype.writeShortLE
];
}
if (NODE) module.exports = Memory8080;

View file

@ -259,38 +259,6 @@ Bus.ERROR = {
REM_MEM_BADRANGE: 5
};
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
Bus.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo;
/**
* initMemory()
*
@ -463,6 +431,42 @@ Bus.prototype.cleanMemory = function(addr, size)
return fClean;
};
/*
* Data types used by scanMemory()
*/
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
Bus.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo;
/**
* scanMemory(info, addr, size)
*

View file

@ -417,7 +417,19 @@ Memory.prototype = {
/**
* setAccess(afn, fDirect)
*
* If no function table is specified, a default is selected based on the Memory type.
* The afn parameter should be a 6-entry function table containing two byte handlers, two
* short handlers, and two long handlers. See the static afnMemory table for an example.
*
* If no function table is specified, a default is selected based on the Memory type;
* similarly, any undefined entries in the table are filled with default handlers that fall
* back to the byte handlers, and if one or both byte handlers are undefined, they default
* to handlers that simply ignore the access.
*
* fDirect indicates that both the default AND the direct handlers should be updated. Direct
* handlers normally match the default handlers, except when "checked" handlers are installed;
* this allows "checked" handlers to know where to dispatch the call after performing checks.
* Examples of checks are read/write breakpoints, but it's really up to the Debugger to decide
* what the check consists of.
*
* @this {Memory}
* @param {Array.<function()>} [afn] function table
@ -448,13 +460,13 @@ Memory.prototype = {
setReadAccess: function(afn, fDirect) {
if (!fDirect || !this.cReadBreakpoints) {
this.readByte = afn[0] || this.readNone;
this.readShort = afn[1] || this.readShortDefault;
this.readLong = afn[2] || this.readLongDefault;
this.readShort = afn[2] || this.readShortDefault;
this.readLong = afn[4] || this.readLongDefault;
}
if (fDirect || fDirect === undefined) {
this.readByteDirect = afn[0] || this.readNone;
this.readShortDirect = afn[1] || this.readShortDefault;
this.readLongDirect = afn[2] || this.readLongDefault;
this.readShortDirect = afn[2] || this.readShortDefault;
this.readLongDirect = afn[4] || this.readLongDefault;
}
},
/**
@ -466,13 +478,13 @@ Memory.prototype = {
*/
setWriteAccess: function(afn, fDirect) {
if (!fDirect || !this.cWriteBreakpoints) {
this.writeByte = !this.fReadOnly && afn[3] || this.writeNone;
this.writeShort = !this.fReadOnly && afn[4] || this.writeShortDefault;
this.writeByte = !this.fReadOnly && afn[1] || this.writeNone;
this.writeShort = !this.fReadOnly && afn[3] || this.writeShortDefault;
this.writeLong = !this.fReadOnly && afn[5] || this.writeLongDefault;
}
if (fDirect || fDirect === undefined) {
this.writeByteDirect = afn[3] || this.writeNone;
this.writeShortDirect = afn[4] || this.writeShortDefault;
this.writeByteDirect = afn[1] || this.writeNone;
this.writeShortDirect = afn[3] || this.writeShortDefault;
this.writeLongDirect = afn[5] || this.writeLongDefault;
}
},
@ -1507,25 +1519,85 @@ Memory.prototype = {
};
/*
* 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.
* 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, 2 byte handlers, 2 short handlers, and 2 long 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.writeNone,
Memory.prototype.readShortDefault,
Memory.prototype.writeShortDefault,
Memory.prototype.readLongDefault,
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.afnChecked = [Memory.prototype.readByteChecked, Memory.prototype.readShortChecked, Memory.prototype.readLongChecked, Memory.prototype.writeByteChecked, Memory.prototype.writeShortChecked, Memory.prototype.writeLongChecked];
Memory.afnMemory = [
Memory.prototype.readByteMemory,
Memory.prototype.writeByteMemory,
Memory.prototype.readShortMemory,
Memory.prototype.writeShortMemory,
Memory.prototype.readLongMemory,
Memory.prototype.writeLongMemory
];
Memory.afnChecked = [
Memory.prototype.readByteChecked,
Memory.prototype.writeByteChecked,
Memory.prototype.readShortChecked,
Memory.prototype.writeShortChecked,
Memory.prototype.readLongChecked,
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];
Memory.afnPaged = [
Memory.prototype.readBytePaged,
Memory.prototype.writeBytePaged,
Memory.prototype.readShortPaged,
Memory.prototype.writeShortPaged,
Memory.prototype.readLongPaged,
Memory.prototype.writeLongPaged
];
Memory.afnUnpaged = [
Memory.prototype.readByteUnpaged,
Memory.prototype.writeByteUnpaged,
Memory.prototype.readShortUnpaged,
Memory.prototype.writeShortUnpaged,
Memory.prototype.readLongUnpaged,
Memory.prototype.writeLongUnpaged
];
}
if (TYPEDARRAYS) {
Memory.afnArrayBE = [Memory.prototype.readByteBE, Memory.prototype.readShortBE, Memory.prototype.readLongBE, Memory.prototype.writeByteBE, Memory.prototype.writeShortBE, Memory.prototype.writeLongBE];
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];
Memory.afnArrayBE = [
Memory.prototype.readByteBE,
Memory.prototype.writeByteBE,
Memory.prototype.readShortBE,
Memory.prototype.writeShortBE,
Memory.prototype.readLongBE,
Memory.prototype.writeLongBE
];
Memory.afnArrayLE = [
Memory.prototype.readByteLE,
Memory.prototype.writeByteLE,
Memory.prototype.readShortLE,
Memory.prototype.writeShortLE,
Memory.prototype.readLongLE,
Memory.prototype.writeLongLE
];
Memory.afnPagedLE = [
Memory.prototype.readBytePLE,
Memory.prototype.writeBytePLE,
Memory.prototype.readShortPLE,
Memory.prototype.writeShortPLE,
Memory.prototype.readLongPLE,
Memory.prototype.writeLongPLE
];
}
if (NODE) module.exports = Memory;

View file

@ -2797,7 +2797,7 @@ Card.prototype.setMemoryAccess = function(nAccess)
}
if (!this.afnAccess) this.afnAccess = new Array(6);
this.afnAccess[0] = fnReadByte;
this.afnAccess[3] = fnWriteByte;
this.afnAccess[1] = fnWriteByte;
this.nAccess = nAccess;
}
};

View file

@ -73,30 +73,9 @@ function BusPDP11(parmsBus, cpu, dbg)
this.nBusWidth = parmsBus['busWidth'] || 16;
/*
* Compute all BusPDP11 memory block parameters, based on the width of the bus.
*
* Regarding blockTotal, we want to avoid using block overflow expressions like:
*
* iBlock < this.nBlockTotal? iBlock : 0
*
* As long as we know that blockTotal is a power of two (eg, 256 or 0x100, in the case of
* nBusWidth == 20 and blockSize == 4096), we can define blockMask as (blockTotal - 1) and
* rewrite the previous expression as:
*
* iBlock & this.nBlockMask
*
* Bus Property Old hard-coded values (when nBusWidth was always 20)
* ------------ ----------------------------------------------------
* this.nBusLimit 0xfffff
* this.nBusMask [same as busLimit]
* this.nBlockSize 4096
* this.nBlockLen (this.nBlockSize >> 2)
* this.nBlockShift 12
* this.nBlockLimit 0xfff
* this.nBlockTotal ((this.nBusLimit + this.nBlockSize) / this.nBlockSize) | 0
* this.nBlockMask (this.nBlockTotal - 1) [ie, 0xff]
*
* Note that we choose a nBlockShift value (and thus a physical memory block size) based on "buswidth":
* Compute all BusPDP11 memory block parameters, based on the width of the bus. The entire
* address space is divided into blocks, using a block size that is (hopefully) appropriate to
* the bus width. The following table summarizes our simplistic calculations.
*
* Bus Width Block Shift Block Size
* --------- ----------- ----------
@ -125,20 +104,24 @@ function BusPDP11(parmsBus, cpu, dbg)
this.assert(this.nBlockMask <= BusPDP11.BlockInfo.num.mask);
/*
* Lists of I/O notification functions: aIONotify are arrays, indexed by address, where each entry
* contains an array:
* aIONotify is an array (ie, a hash) of I/O notification handlers, indexed by address, where each
* entry contains an array:
*
* [0]: registered function to call for read
* [1]: registered function to call for write
* [0]: readByte(addr)
* [1]: writeByte()
* [2]: readShort()
* [3]: writeShort()
*
* The registered function is called with the address, and if the access was triggered by the CPU,
* the program counter (PC) at the point of access.
* Each of these 4-element arrays are similar to the memory access arrays assigned to entire Memory
* blocks, but these handlers generally target a specific address (or handful of addresses), while
* Memory access handlers must service the entire block; see the setAccess() function in the Memory
* component for details.
*
* UPDATE: The Debugger now piggy-backs on these arrays to indicate addresses for which it wants
* UPDATE: The Debugger wants to piggy-back on these arrays to indicate addresses for which it wants
* notification. In those cases, the registered component/function elements may or may not be set,
* but the following additional element will be set:
*
* [2]: true to break on I/O, false to ignore I/O
* [4]: true to break on I/O, false to ignore I/O
*
* The false case is important if fIOBreakAll is set, because it allows the Debugger to selectively
* ignore specific addresses.
@ -172,38 +155,6 @@ BusPDP11.ERROR = {
REMOVE_INVALID: 5
};
/**
* @typedef {number}
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
BusPDP11.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfoPDP11 object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfoPDP11;
BusPDP11.controller = {
/**
@ -211,26 +162,13 @@ BusPDP11.controller = {
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} [addr]
* @param {number} addr
* @return {number}
*/
readIOPageByte: function(off, addr)
{
return 0;
},
/**
* readIOPageWord(off, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} [addr]
* @return {number}
*/
readIOPageWord: function(off, addr)
{
var afn = this.controller.aIONotify[off];
return afn? afn[0](addr) : 0;
return afn && afn[0]? afn[0](addr) : 0;
},
/**
@ -239,24 +177,58 @@ BusPDP11.controller = {
* @this {MemoryPDP11}
* @param {number} off
* @param {number} b (which should already be pre-masked to 8 bits)
* @param {number} [addr]
* @param {number} addr
*/
writeIOPageByte: function(off, b, addr)
{
var afn = this.controller.aIONotify[off];
if (afn && afn[1]) {
afn[1](addr, b);
}
},
/**
* writeIOPageWord(off, w, addr)
* readIOPageShort(off, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readIOPageShort: function(off, addr)
{
Component.assert(!(addr & 1)); // unaligned addresses should be getting trapped at a higher level
var afn = this.controller.aIONotify[off];
if (afn) {
if (afn[2]) {
return afn[2](addr);
} else if (afn[0]) {
return afn[0](addr) | (afn[0](addr + 1) << 8);
}
}
return 0;
},
/**
* writeIOPageShort(off, w, addr)
*
* @this {MemoryPDP11}
* @param {number} off
* @param {number} w (which should already be pre-masked to 16 bits)
* @param {number} [addr]
* @param {number} addr
*/
writeIOPageWord: function(off, w, addr)
writeIOPageShort: function(off, w, addr)
{
Component.assert(!(addr & 1)); // unaligned addresses should be getting trapped at a higher level
var afn = this.controller.aIONotify[off];
return afn? afn[1](w, addr) : 0;
if (afn) {
if (afn[3]) {
afn[3](addr, w);
} else if (afn[1]) {
afn[1](addr, w & 0xff);
afn[1](addr + 1, w >> 8);
}
}
}
};
@ -277,9 +249,9 @@ BusPDP11.prototype.initMemory = function()
}
this.afnIOPage = new Array(4);
this.afnIOPage[0] = BusPDP11.controller.readIOPageByte;
this.afnIOPage[1] = BusPDP11.controller.readIOPageWord;
this.afnIOPage[1] = BusPDP11.controller.readIOPageShort;
this.afnIOPage[2] = BusPDP11.controller.writeIOPageByte;
this.afnIOPage[3] = BusPDP11.controller.writeIOPageWord;
this.afnIOPage[3] = BusPDP11.controller.writeIOPageShort;
this.addrIOPage = this.addrTotal - BusPDP11.IOPAGE_LENGTH;
this.addMemory(this.addrIOPage, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
};
@ -451,16 +423,52 @@ BusPDP11.prototype.cleanMemory = function(addr, size)
return fClean;
};
/*
* Data types used by scanMemory()
*/
/**
* @typedef {number} BlockInfo
*/
var BlockInfo;
/**
* This defines the BlockInfo bit fields used by scanMemory() when it creates the aBlocks array.
*
* @typedef {{
* num: BitField,
* count: BitField,
* btmod: BitField,
* type: BitField
* }}
*/
BusPDP11.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfoPDP11 object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
* aBlocks: array of allocated Memory block numbers
*
* @typedef {{
* cbTotal: number,
* cBlocks: number,
* aBlocks: Array.<BlockInfo>
* }} BusInfoPDP11
*/
var BusInfoPDP11;
/**
* scanMemory(info, addr, size)
*
* Returns a BusInfoPDP11 object for the specified address range.
*
* @this {BusPDP11}
* @param {Object} [info] previous BusInfoPDP11, if any
* @param {BusInfoPDP11} [info] previous BusInfoPDP11, 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 info (or new info if no previous info provided)
* @return {BusInfoPDP11} updated info (or new info if no previous info provided)
*/
BusPDP11.prototype.scanMemory = function(info, addr, size)
{
@ -640,7 +648,7 @@ BusPDP11.prototype.getByteDirect = function(addr)
*
* @this {BusPDP11}
* @param {number} addr is a physical address
* @return {number} word (16-bit) value at that address
* @return {number} short (16-bit) value at that address
*/
BusPDP11.prototype.getShort = function(addr)
{
@ -659,7 +667,7 @@ BusPDP11.prototype.getShort = function(addr)
*
* @this {BusPDP11}
* @param {number} addr is a physical address
* @return {number} word (16-bit) value at that address
* @return {number} short (16-bit) value at that address
*/
BusPDP11.prototype.getShortDirect = function(addr)
{
@ -703,7 +711,7 @@ BusPDP11.prototype.setByteDirect = function(addr, b)
*
* @this {BusPDP11}
* @param {number} addr is a physical address
* @param {number} w is the word (16-bit) value to write (we truncate it to 16 bits to be safe)
* @param {number} w is the short (16-bit) value to write (we truncate it to 16 bits to be safe)
*/
BusPDP11.prototype.setShort = function(addr, w)
{
@ -725,7 +733,7 @@ BusPDP11.prototype.setShort = function(addr, w)
*
* @this {BusPDP11}
* @param {number} addr is a physical address
* @param {number} w is the word (16-bit) value to write (we truncate it to 16 bits to be safe)
* @param {number} w is the short (16-bit) value to write (we truncate it to 16 bits to be safe)
*/
BusPDP11.prototype.setShortDirect = function(addr, w)
{
@ -860,18 +868,21 @@ BusPDP11.prototype.restoreMemory = function(a)
};
/**
* addIOHandlers(start, end, fnRead, fnWrite)
* addIOHandlers(start, end, fnReadByte, fnWriteByte, fnReadShort, fnWriteShort)
*
* Add I/O notification handlers to the list of such handlers. The start and end addresses are typically
* relative to the starting IOPAGE address, but they can also be absolute.
* Add I/O notification handlers to the master list (aIONotify). The start and end addresses are typically
* relative to the starting IOPAGE address, but they can also be absolute; we simply mask all addresses with
* (IOPAGE_LENGTH - 1).
*
* @this {BusPDP11}
* @param {number} start address
* @param {number} end address
* @param {function(number)|null|undefined} fnRead is called with the read address whenever a read occurs
* @param {function(number,number)|null|undefined} fnWrite is called with the data and write address whenever a write occurs
* @param {function(number)|null|undefined} fnReadByte
* @param {function(number,number)|null|undefined} fnWriteByte
* @param {function(number)|null|undefined} fnReadShort
* @param {function(number,number)|null|undefined} fnWriteShort
*/
BusPDP11.prototype.addIOHandlers = function(start, end, fnRead, fnWrite)
BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte, fnReadShort, fnWriteShort)
{
for (var addr = start; addr <= end; addr += 2) {
var off = addr & (BusPDP11.IOPAGE_LENGTH - 1);
@ -883,7 +894,7 @@ BusPDP11.prototype.addIOHandlers = function(start, end, fnRead, fnWrite)
Component.warning("I/O address already registered: " + str.toHexLong(this.addrIOPage + off));
continue;
}
this.aIONotify[off] = [fnRead, fnWrite, false];
this.aIONotify[off] = [fnReadByte, fnWriteByte, fnReadShort, fnWriteShort, false];
if (MAXDEBUG) this.log("addIOHandlers(" + str.toHexLong(this.addrIOPage + off) + ")");
}
};
@ -901,9 +912,11 @@ BusPDP11.prototype.addIOTable = function(component, table)
{
for (var port in table) {
var afn = table[port];
var fnRead = afn[0]? afn[0].bind(component) : null;
var fnWrite = afn[1]? afn[1].bind(component) : null;
this.addIOHandlers(+port, +port, fnRead, fnWrite);
var fnReadByte = afn[0]? afn[0].bind(component) : null;
var fnWriteByte = afn[1]? afn[1].bind(component) : null;
var fnReadShort = afn[2]? afn[2].bind(component) : null;
var fnWriteShort = afn[3]? afn[3].bind(component) : null;
this.addIOHandlers(+port, +port, fnReadByte, fnWriteByte, fnReadShort, fnWriteShort);
}
};

View file

@ -89,7 +89,7 @@ DevicePDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
* readPSW(addr)
*
* @this {DevicePDP11}
* @param {number} [addr]
* @param {number} addr
* @return {number}
*/
DevicePDP11.prototype.readPSW = function(addr)
@ -102,7 +102,7 @@ DevicePDP11.prototype.readPSW = function(addr)
*
* @this {DevicePDP11}
* @param {number} data
* @param {number} [addr]
* @param {number} addr
*/
DevicePDP11.prototype.writePSW = function(data, addr)
{
@ -110,7 +110,7 @@ DevicePDP11.prototype.writePSW = function(data, addr)
};
DevicePDP11.UNIBUS_TABLE = {};
DevicePDP11.UNIBUS_TABLE[DevicePDP11.ADDR_PSW] = [DevicePDP11.prototype.readPSW, DevicePDP11.prototype.writePSW];
DevicePDP11.UNIBUS_TABLE[DevicePDP11.ADDR_PSW] = [null, null, DevicePDP11.prototype.readPSW, DevicePDP11.prototype.writePSW];
/**
* DevicePDP11.init()

View file

@ -383,7 +383,19 @@ MemoryPDP11.prototype = {
/**
* setAccess(afn, fDirect)
*
* If no function table is specified, a default is selected based on the MemoryPDP11 type.
* The afn parameter should be a 4-entry function table containing two byte handlers and
* two short handlers. See the static afnMemory table for an example.
*
* If no function table is specified, a default is selected based on the MemoryPDP11 type;
* similarly, any undefined entries in the table are filled with default handlers that fall
* back to the byte handlers, and if one or both byte handlers are undefined, they default
* to handlers that simply ignore the access.
*
* fDirect indicates that both the default AND the direct handlers should be updated. Direct
* handlers normally match the default handlers, except when "checked" handlers are installed;
* this allows "checked" handlers to know where to dispatch the call after performing checks.
* Examples of checks are read/write breakpoints, but it's really up to the Debugger to decide
* what the check consists of.
*
* @this {MemoryPDP11}
* @param {Array.<function()>} [afn] function table
@ -407,11 +419,11 @@ MemoryPDP11.prototype = {
setReadAccess: function(afn, fDirect) {
if (!fDirect || !this.cReadBreakpoints) {
this.readByte = afn[0] || this.readNone;
this.readShort = afn[1] || this.readShortDefault;
this.readShort = afn[2] || this.readShortDefault;
}
if (fDirect || fDirect === undefined) {
this.readByteDirect = afn[0] || this.readNone;
this.readShortDirect = afn[1] || this.readShortDefault;
this.readShortDirect = afn[2] || this.readShortDefault;
}
},
/**
@ -423,11 +435,11 @@ MemoryPDP11.prototype = {
*/
setWriteAccess: function(afn, fDirect) {
if (!fDirect || !this.cWriteBreakpoints) {
this.writeByte = !this.fReadOnly && afn[2] || this.writeNone;
this.writeByte = !this.fReadOnly && afn[1] || this.writeNone;
this.writeShort = !this.fReadOnly && afn[3] || this.writeShortDefault;
}
if (fDirect || fDirect === undefined) {
this.writeByteDirect = afn[2] || this.writeNone;
this.writeByteDirect = afn[1] || this.writeNone;
this.writeShortDirect = afn[3] || this.writeShortDefault;
}
},
@ -830,43 +842,43 @@ MemoryPDP11.prototype = {
/*
* This is the effective definition of afnNone, but we need not fully define it, because setAccess()
* uses these defaults when any of the 4 handlers (ie, 2 read handlers and 2 write handlers) are undefined.
* uses these defaults when any of the 4 handlers (ie, 2 byte handlers and 2 short handlers) are undefined.
*
MemoryPDP11.afnNone = [
MemoryPDP11.afnNone = [
MemoryPDP11.prototype.readNone,
MemoryPDP11.prototype.readShortDefault,
MemoryPDP11.prototype.writeNone,
MemoryPDP11.prototype.readShortDefault,
MemoryPDP11.prototype.writeShortDefault
];
*/
MemoryPDP11.afnNone = [];
MemoryPDP11.afnNone = [];
MemoryPDP11.afnMemory = [
MemoryPDP11.afnMemory = [
MemoryPDP11.prototype.readByteMemory,
MemoryPDP11.prototype.readShortMemory,
MemoryPDP11.prototype.writeByteMemory,
MemoryPDP11.prototype.readShortMemory,
MemoryPDP11.prototype.writeShortMemory
];
MemoryPDP11.afnChecked = [
MemoryPDP11.afnChecked = [
MemoryPDP11.prototype.readByteChecked,
MemoryPDP11.prototype.readShortChecked,
MemoryPDP11.prototype.writeByteChecked,
MemoryPDP11.prototype.readShortChecked,
MemoryPDP11.prototype.writeShortChecked
];
if (TYPEDARRAYS) {
MemoryPDP11.afnArrayBE = [
MemoryPDP11.afnArrayBE = [
MemoryPDP11.prototype.readByteBE,
MemoryPDP11.prototype.readShortBE,
MemoryPDP11.prototype.writeByteBE,
MemoryPDP11.prototype.readShortBE,
MemoryPDP11.prototype.writeShortBE
];
MemoryPDP11.afnArrayLE = [
MemoryPDP11.afnArrayLE = [
MemoryPDP11.prototype.readByteLE,
MemoryPDP11.prototype.readShortLE,
MemoryPDP11.prototype.writeByteLE,
MemoryPDP11.prototype.readShortLE,
MemoryPDP11.prototype.writeShortLE
];
}