Merge branch 'next-release'

This commit is contained in:
Jeff Parsons 2016-08-19 08:43:20 -07:00
commit f99a0c59a0
293 changed files with 14086 additions and 4715 deletions

View file

@ -150,6 +150,7 @@ var sTemplateFile = "./modules/shared/templates/common.html";
* HTML template file; sMachineXMLFile is a fallback file to look for when sReadMeFile doesn't exist.
*/
var sReadMeFile = "README.md";
var sMachineMDFile = "machine.md";
var sMachineXMLFile = "machine.xml";
var sManifestXMLFile = "manifest.xml";
@ -1713,12 +1714,20 @@ HTMLOut.prototype.getMarkdownFile = function(sFile, sToken, sIndent, aParms, sPr
{
var obj = this;
sFile = path.join(this.sDir, sFile);
var sFilePath = path.join(this.sDir, sFile);
HTMLOut.logConsole('HTMLOut.getMarkdownFile("' + sFile + '")');
HTMLOut.logConsole('HTMLOut.getMarkdownFile("' + sFilePath + '")');
fs.readFile(sFile, {encoding: "utf8"}, function doneMarkdownFile(err, s) {
fs.readFile(sFilePath, {encoding: "utf8"}, function doneMarkdownFile(err, s) {
if (err) {
/*
* HACK to look for a "machine.md" if our attempt to load a "README.md" failed.
*/
if (sFile.indexOf(sReadMeFile) >= 0) {
sFile = sFile.replace(sReadMeFile, sMachineMDFile);
obj.getMarkdownFile(sFile, sToken, sIndent, aParms, sPrevious, sMachineFile);
return;
}
/*
* Instead of displaying a cryptic error message inside our beautiful HTML template, eg:
*

View file

@ -33,5 +33,4 @@ PC8080 is comprised of the following non-shared components, as listed in [packag
* [video.js](/modules/pc8080/lib/video.js)
* [serialport.js](/modules/pc8080/lib/serialport.js)
* [debugger.js](/modules/pc8080/lib/debugger.js)
* [state.js](/modules/pc8080/lib/state.js)
* [computer.js](/modules/pc8080/lib/computer.js)

View file

@ -35,23 +35,23 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var Component = require("../../shared/lib/component");
var Memory = require("./memory");
var Messages = require("./messages");
var State = require("./state");
var State = require("../../shared/lib/state");
var Memory8080 = require("./memory");
var Messages8080= require("./messages");
}
/**
* Bus(cpu, dbg)
* Bus8080(cpu, dbg)
*
* The Bus component manages physical memory and I/O address spaces.
* The Bus8080 component manages physical memory and I/O address spaces.
*
* The Bus component has no UI elements, so it does not require an init() handler,
* The Bus8080 component has no UI elements, so it does not require an init() handler,
* but it still inherits from the Component class and must be allocated like any
* other device component. It's currently allocated by the Computer's init() handler,
* which then calls the initBus() method of all the other components.
*
* For memory beyond the simple needs of the ROM and RAM components (ie, memory-mapped
* devices), the address space must still be allocated through the Bus component via
* devices), the address space must still be allocated through the Bus8080 component via
* addMemory(). If the component needs something more than simple read/write storage,
* it must provide a custom controller.
*
@ -63,12 +63,12 @@ if (NODE) {
* @constructor
* @extends Component
* @param {Object} parmsBus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
function Bus(parmsBus, cpu, dbg)
function Bus8080(parmsBus, cpu, dbg)
{
Component.call(this, "Bus", parmsBus, Bus);
Component.call(this, "Bus", parmsBus, Bus8080);
this.cpu = cpu;
this.dbg = dbg;
@ -76,7 +76,7 @@ function Bus(parmsBus, cpu, dbg)
this.nBusWidth = parmsBus['busWidth'] || 16;
/*
* Compute all Bus memory block parameters, based on the width of the bus.
* Compute all Bus8080 memory block parameters, based on the width of the bus.
*
* Regarding blockTotal, we want to avoid using block overflow expressions like:
*
@ -121,7 +121,7 @@ function Bus(parmsBus, cpu, dbg)
this.nBlockLimit = this.nBlockSize - 1;
this.nBlockTotal = (this.addrTotal / this.nBlockSize) | 0;
this.nBlockMask = this.nBlockTotal - 1;
this.assert(this.nBlockMask <= Bus.BlockInfo.num.mask);
this.assert(this.nBlockMask <= Bus8080.BlockInfo.num.mask);
/*
* Lists of I/O notification functions: aPortInputNotify and aPortOutputNotify are arrays, indexed by
@ -164,9 +164,9 @@ function Bus(parmsBus, cpu, dbg)
this.setReady();
}
Component.subclass(Bus);
Component.subclass(Bus8080);
Bus.ERROR = {
Bus8080.ERROR = {
ADD_MEM_INUSE: 1,
ADD_MEM_BADRANGE: 2,
SET_MEM_BADRANGE: 4,
@ -188,10 +188,10 @@ var BlockInfo;
* type: BitField
* }}
*/
Bus.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
Bus8080.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
/**
* BusInfo object definition (returned by scanMemory())
* Bus8080Info object definition (returned by scanMemory())
*
* cbTotal: total bytes allocated
* cBlocks: total Memory blocks allocated
@ -203,18 +203,18 @@ Bus.BlockInfo = usr.defineBitFields({num:20, count:8, btmod:1, type:3});
* aBlocks: Array.<BlockInfo>
* }}
*/
var BusInfo;
var Bus8080Info;
/**
* initMemory()
*
* Allocate enough (empty) Memory blocks to span the entire physical address space.
*
* @this {Bus}
* @this {Bus8080}
*/
Bus.prototype.initMemory = function()
Bus8080.prototype.initMemory = function()
{
var block = new Memory();
var block = new Memory8080();
block.copyBreakpoints(this.dbg);
this.aMemBlocks = new Array(this.nBlockTotal);
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
@ -225,9 +225,9 @@ Bus.prototype.initMemory = function()
/**
* reset()
*
* @this {Bus}
* @this {Bus8080}
*/
Bus.prototype.reset = function()
Bus8080.prototype.reset = function()
{
};
@ -243,12 +243,12 @@ Bus.prototype.reset = function()
* TODO: Perhaps Computer should be smarter: if there's no powerUp() handler, then fallback to the reset() handler.
* In that case, however, we'd either need to remove the powerUp() stub in Component, or detect the existence of the stub.
*
* @this {Bus}
* @this {Bus8080}
* @param {Object|null} data (always null because we supply no powerDown() handler)
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
Bus.prototype.powerUp = function(data, fRepower)
Bus8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) this.reset();
return true;
@ -267,7 +267,7 @@ Bus.prototype.powerUp = function(data, fRepower)
* because machines with large block sizes can make it impossible to load certain ROMs at
* their required addresses. Every allocation still allocates a whole number of blocks.
*
* Even so, Bus memory management does NOT provide a general-purpose heap. Most memory
* Even so, Bus8080 memory management does NOT provide a general-purpose heap. Most memory
* allocations occur during machine initialization and never change. In particular, there
* is NO support for removing partial-block allocations.
*
@ -277,13 +277,13 @@ Bus.prototype.powerUp = function(data, fRepower)
* space. However, any holes that might have existed between the original allocation and an
* extension are subsumed by the extension.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is the starting physical address of the request
* @param {number} size of the request, in bytes
* @param {number} type is one of the Memory.TYPE constants
* @param {number} type is one of the Memory8080.TYPE constants
* @return {boolean} true if successful, false if not
*/
Bus.prototype.addMemory = function(addr, size, type)
Bus8080.prototype.addMemory = function(addr, size, type)
{
var addrNext = addr;
var sizeLeft = size;
@ -319,10 +319,10 @@ Bus.prototype.addMemory = function(addr, size, type)
continue;
}
}
return this.reportError(Bus.ERROR.ADD_MEM_INUSE, addrNext, sizeLeft);
return this.reportError(Bus8080.ERROR.ADD_MEM_INUSE, addrNext, sizeLeft);
}
var blockNew = new Memory(addrNext, sizeBlock, this.nBlockSize, type);
var blockNew = new Memory8080(addrNext, sizeBlock, this.nBlockSize, type);
blockNew.copyBreakpoints(this.dbg, block);
this.aMemBlocks[iBlock++] = blockNew;
@ -331,22 +331,22 @@ Bus.prototype.addMemory = function(addr, size, type)
}
if (sizeLeft <= 0) {
this.status(Math.floor(size / 1024) + "Kb " + Memory.TYPE.NAMES[type] + " at " + str.toHexWord(addr));
this.status(Math.floor(size / 1024) + "Kb " + Memory8080.TYPE.NAMES[type] + " at " + str.toHexWord(addr));
return true;
}
return this.reportError(Bus.ERROR.ADD_MEM_BADRANGE, addr, size);
return this.reportError(Bus8080.ERROR.ADD_MEM_BADRANGE, addr, size);
};
/**
* cleanMemory(addr, size)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr
* @param {number} size
* @return {boolean} true if all blocks were clean, false if dirty; all blocks are cleaned in the process
*/
Bus.prototype.cleanMemory = function(addr, size)
Bus8080.prototype.cleanMemory = function(addr, size)
{
var fClean = true;
var iBlock = addr >>> this.nBlockShift;
@ -364,15 +364,15 @@ Bus.prototype.cleanMemory = function(addr, size)
/**
* scanMemory(info, addr, size)
*
* Returns a BusInfo object for the specified address range.
* Returns a Bus8080Info object for the specified address range.
*
* @this {Bus}
* @param {Object} [info] previous BusInfo, if any
* @this {Bus8080}
* @param {Object} [info] previous Bus8080Info, 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)
*/
Bus.prototype.scanMemory = function(info, addr, size)
Bus8080.prototype.scanMemory = function(info, addr, size)
{
if (addr == null) addr = 0;
if (size == null) size = (this.addrTotal - addr) | 0;
@ -387,7 +387,7 @@ Bus.prototype.scanMemory = function(info, addr, size)
var block = this.aMemBlocks[iBlock];
info.cbTotal += block.size;
if (block.size) {
info.aBlocks.push(usr.initBitFields(Bus.BlockInfo, iBlock, 0, 0, block.type));
info.aBlocks.push(usr.initBitFields(Bus8080.BlockInfo, iBlock, 0, 0, block.type));
info.cBlocks++
}
iBlock++;
@ -398,10 +398,10 @@ Bus.prototype.scanMemory = function(info, addr, size)
/**
* getWidth()
*
* @this {Bus}
* @this {Bus8080}
* @return {number}
*/
Bus.prototype.getWidth = function()
Bus8080.prototype.getWidth = function()
{
return this.nBusWidth;
};
@ -413,18 +413,18 @@ Bus.prototype.getWidth = function()
*
* TODO: Update the removeMemory() interface to reflect the relaxed requirements of the addMemory() interface.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr
* @param {number} size
* @return {boolean} true if successful, false if not
*/
Bus.prototype.removeMemory = function(addr, size)
Bus8080.prototype.removeMemory = function(addr, size)
{
if (!(addr & this.nBlockLimit) && size && !(size & this.nBlockLimit)) {
var iBlock = addr >>> this.nBlockShift;
while (size > 0) {
var blockOld = this.aMemBlocks[iBlock];
var blockNew = new Memory(addr);
var blockNew = new Memory8080(addr);
blockNew.copyBreakpoints(this.dbg, blockOld);
this.aMemBlocks[iBlock++] = blockNew;
addr = iBlock * this.nBlockSize;
@ -432,18 +432,18 @@ Bus.prototype.removeMemory = function(addr, size)
}
return true;
}
return this.reportError(Bus.ERROR.REM_MEM_BADRANGE, addr, size);
return this.reportError(Bus8080.ERROR.REM_MEM_BADRANGE, addr, size);
};
/**
* getMemoryBlocks(addr, size)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is the starting physical address
* @param {number} size of the request, in bytes
* @return {Array} of Memory blocks
*/
Bus.prototype.getMemoryBlocks = function(addr, size)
Bus8080.prototype.getMemoryBlocks = function(addr, size)
{
var aBlocks = [];
var iBlock = addr >>> this.nBlockShift;
@ -463,13 +463,13 @@ Bus.prototype.getMemoryBlocks = function(addr, size)
* Otherwise, new blocks are allocated with the specified type; the underlying memory from the
* provided blocks is still used, but the new blocks may have different access to that memory.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is the starting physical address
* @param {number} size of the request, in bytes
* @param {Array} aBlocks as returned by getMemoryBlocks()
* @param {number} [type] is one of the Memory.TYPE constants
* @param {number} [type] is one of the Memory8080.TYPE constants
*/
Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
Bus8080.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
{
var i = 0;
var iBlock = addr >>> this.nBlockShift;
@ -478,7 +478,7 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
this.assert(block);
if (!block) break;
if (type !== undefined) {
var blockNew = new Memory(addr);
var blockNew = new Memory8080(addr);
blockNew.clone(block, type, this.dbg);
block = blockNew;
}
@ -490,11 +490,11 @@ Bus.prototype.setMemoryBlocks = function(addr, size, aBlocks, type)
/**
* getByte(addr)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is a physical address
* @return {number} byte (8-bit) value at that address
*/
Bus.prototype.getByte = function(addr)
Bus8080.prototype.getByte = function(addr)
{
return this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].readByte(addr & this.nBlockLimit, addr);
};
@ -504,11 +504,11 @@ Bus.prototype.getByte = function(addr)
*
* This is useful for the Debugger and other components that want to bypass getByte() breakpoint detection.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is a physical address
* @return {number} byte (8-bit) value at that address
*/
Bus.prototype.getByteDirect = function(addr)
Bus8080.prototype.getByteDirect = function(addr)
{
return this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].readByteDirect(addr & this.nBlockLimit, addr);
};
@ -516,11 +516,11 @@ Bus.prototype.getByteDirect = function(addr)
/**
* getShort(addr)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is a physical address
* @return {number} word (16-bit) value at that address
*/
Bus.prototype.getShort = function(addr)
Bus8080.prototype.getShort = function(addr)
{
var off = addr & this.nBlockLimit;
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
@ -535,11 +535,11 @@ Bus.prototype.getShort = function(addr)
*
* This is useful for the Debugger and other components that want to bypass getShort() breakpoint detection.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is a physical address
* @return {number} word (16-bit) value at that address
*/
Bus.prototype.getShortDirect = function(addr)
Bus8080.prototype.getShortDirect = function(addr)
{
var off = addr & this.nBlockLimit;
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
@ -552,11 +552,11 @@ Bus.prototype.getShortDirect = function(addr)
/**
* setByte(addr, b)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is a physical address
* @param {number} b is the byte (8-bit) value to write (we truncate it to 8 bits to be safe)
*/
Bus.prototype.setByte = function(addr, b)
Bus8080.prototype.setByte = function(addr, b)
{
this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].writeByte(addr & this.nBlockLimit, b & 0xff, addr);
};
@ -567,11 +567,11 @@ Bus.prototype.setByte = function(addr, b)
* This is useful for the Debugger and other components that want to bypass breakpoint detection AND read-only
* memory protection (for example, this is an interface the ROM component could use to initialize ROM contents).
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr is a physical address
* @param {number} b is the byte (8-bit) value to write (we truncate it to 8 bits to be safe)
*/
Bus.prototype.setByteDirect = function(addr, b)
Bus8080.prototype.setByteDirect = function(addr, b)
{
this.aMemBlocks[(addr & this.nBusMask) >>> this.nBlockShift].writeByteDirect(addr & this.nBlockLimit, b & 0xff, addr);
};
@ -579,11 +579,11 @@ Bus.prototype.setByteDirect = function(addr, b)
/**
* setShort(addr, w)
*
* @this {Bus}
* @this {Bus8080}
* @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)
*/
Bus.prototype.setShort = function(addr, w)
Bus8080.prototype.setShort = function(addr, w)
{
var off = addr & this.nBlockLimit;
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
@ -601,11 +601,11 @@ Bus.prototype.setShort = function(addr, w)
* This is useful for the Debugger and other components that want to bypass breakpoint detection AND read-only
* memory protection (for example, this is an interface the ROM component could use to initialize ROM contents).
*
* @this {Bus}
* @this {Bus8080}
* @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)
*/
Bus.prototype.setShortDirect = function(addr, w)
Bus8080.prototype.setShortDirect = function(addr, w)
{
var off = addr & this.nBlockLimit;
var iBlock = (addr & this.nBusMask) >>> this.nBlockShift;
@ -620,11 +620,11 @@ Bus.prototype.setShortDirect = function(addr, w)
/**
* addMemBreak(addr, fWrite)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
*/
Bus.prototype.addMemBreak = function(addr, fWrite)
Bus8080.prototype.addMemBreak = function(addr, fWrite)
{
if (DEBUGGER) {
var iBlock = addr >>> this.nBlockShift;
@ -635,11 +635,11 @@ Bus.prototype.addMemBreak = function(addr, fWrite)
/**
* removeMemBreak(addr, fWrite)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} addr
* @param {boolean} fWrite is true for a memory write breakpoint, false for a memory read breakpoint
*/
Bus.prototype.removeMemBreak = function(addr, fWrite)
Bus8080.prototype.removeMemBreak = function(addr, fWrite)
{
if (DEBUGGER) {
var iBlock = addr >>> this.nBlockShift;
@ -672,11 +672,11 @@ Bus.prototype.removeMemBreak = function(addr, fWrite)
* that it's compressed, since we'll only store them in compressed form if they actually shrank, and we'll use State
* helper methods compress() and decompress() to create and expand the compressed data arrays.
*
* @this {Bus}
* @this {Bus8080}
* @param {boolean} [fAll] (true to save all non-ROM memory blocks, regardless of their dirty flags)
* @return {Array} a
*/
Bus.prototype.saveMemory = function(fAll)
Bus8080.prototype.saveMemory = function(fAll)
{
var i = 0;
var a = [];
@ -688,7 +688,7 @@ Bus.prototype.saveMemory = function(fAll)
* the memory blocks (eg, video memory), and while cleanMemory() will clear a dirty block's fDirty flag,
* it also sets the dirty block's fDirtyEver flag, which is left set for the lifetime of the machine.
*/
if (fAll && block.type != Memory.TYPE.ROM || block.fDirty || block.fDirtyEver) {
if (fAll && block.type != Memory8080.TYPE.ROM || block.fDirty || block.fDirtyEver) {
a[i++] = iBlock;
a[i++] = State.compress(block.save());
}
@ -710,11 +710,11 @@ Bus.prototype.saveMemory = function(fAll)
*
* See saveMemory() for more information on how the memory block contents are saved.
*
* @this {Bus}
* @this {Bus8080}
* @param {Array} a
* @return {boolean} true if successful, false if not
*/
Bus.prototype.restoreMemory = function(a)
Bus8080.prototype.restoreMemory = function(a)
{
var i;
for (i = 0; i < a.length - 1; i += 2) {
@ -740,11 +740,11 @@ Bus.prototype.restoreMemory = function(a)
/**
* addPortInputBreak(port)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} [port]
* @return {boolean} true if break on port input enabled, false if disabled
*/
Bus.prototype.addPortInputBreak = function(port)
Bus8080.prototype.addPortInputBreak = function(port)
{
if (port === undefined) {
this.fPortInputBreakAll = !this.fPortInputBreakAll;
@ -762,12 +762,12 @@ Bus.prototype.addPortInputBreak = function(port)
*
* Add a port input-notification handler to the list of such handlers.
*
* @this {Bus}
* @this {Bus8080}
* @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)
Bus8080.prototype.addPortInputNotify = function(start, end, fn)
{
if (fn !== undefined) {
for (var port = start; port <= end; port++) {
@ -786,12 +786,12 @@ Bus.prototype.addPortInputNotify = function(start, end, fn)
*
* Add port input-notification handlers from the specified table (a batch version of addPortInputNotify)
*
* @this {Bus}
* @this {Bus8080}
* @param {Component} component
* @param {Object} table
* @param {number} [offset] is an optional port offset
*/
Bus.prototype.addPortInputTable = function(component, table, offset)
Bus8080.prototype.addPortInputTable = function(component, table, offset)
{
if (offset === undefined) offset = 0;
if (table) {
@ -806,11 +806,11 @@ Bus.prototype.addPortInputTable = function(component, table, offset)
*
* By default, all input ports are 1 byte wide; ports that are wider must call this function.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} port
* @param {number} size (1, 2 or 4)
*/
Bus.prototype.addPortInputWidth = function(port, size)
Bus8080.prototype.addPortInputWidth = function(port, size)
{
this.aPortInputWidth[port] = size;
};
@ -818,7 +818,7 @@ Bus.prototype.addPortInputWidth = function(port, size)
/**
* checkPortInputNotify(port, size, addrIP)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} port
* @param {number} size (1, 2 or 4)
* @param {number} [addrIP] is the IP value at the time of the input
@ -827,7 +827,7 @@ Bus.prototype.addPortInputWidth = function(port, size)
* 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)
Bus8080.prototype.checkPortInputNotify = function(port, size, addrIP)
{
var data = 0, shift = 0;
@ -882,11 +882,11 @@ Bus.prototype.checkPortInputNotify = function(port, size, addrIP)
*
* Remove port input-notification handler(s) (to be ENABLED later if needed)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} start address
* @param {number} end address
*
Bus.prototype.removePortInputNotify = function(start, end)
Bus8080.prototype.removePortInputNotify = function(start, end)
{
for (var port = start; port < end; port++) {
if (this.aPortInputNotify[port]) {
@ -899,11 +899,11 @@ Bus.prototype.removePortInputNotify = function(start, end)
/**
* addPortOutputBreak(port)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} [port]
* @return {boolean} true if break on port output enabled, false if disabled
*/
Bus.prototype.addPortOutputBreak = function(port)
Bus8080.prototype.addPortOutputBreak = function(port)
{
if (port === undefined) {
this.fPortOutputBreakAll = !this.fPortOutputBreakAll;
@ -921,12 +921,12 @@ Bus.prototype.addPortOutputBreak = function(port)
*
* Add a port output-notification handler to the list of such handlers.
*
* @this {Bus}
* @this {Bus8080}
* @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)
Bus8080.prototype.addPortOutputNotify = function(start, end, fn)
{
if (fn !== undefined) {
for (var port = start; port <= end; port++) {
@ -945,12 +945,12 @@ Bus.prototype.addPortOutputNotify = function(start, end, fn)
*
* Add port output-notification handlers from the specified table (a batch version of addPortOutputNotify)
*
* @this {Bus}
* @this {Bus8080}
* @param {Component} component
* @param {Object} table
* @param {number} [offset] is an optional port offset
*/
Bus.prototype.addPortOutputTable = function(component, table, offset)
Bus8080.prototype.addPortOutputTable = function(component, table, offset)
{
if (offset === undefined) offset = 0;
if (table) {
@ -965,11 +965,11 @@ Bus.prototype.addPortOutputTable = function(component, table, offset)
*
* By default, all output ports are 1 byte wide; ports that are wider must call this function.
*
* @this {Bus}
* @this {Bus8080}
* @param {number} port
* @param {number} size (1, 2 or 4)
*/
Bus.prototype.addPortOutputWidth = function(port, size)
Bus8080.prototype.addPortOutputWidth = function(port, size)
{
this.aPortOutputWidth[port] = size;
};
@ -977,13 +977,13 @@ Bus.prototype.addPortOutputWidth = function(port, size)
/**
* checkPortOutputNotify(port, size, data, addrIP)
*
* @this {Bus}
* @this {Bus8080}
* @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)
Bus8080.prototype.checkPortOutputNotify = function(port, size, data, addrIP)
{
var shift = 0;
@ -1030,11 +1030,11 @@ Bus.prototype.checkPortOutputNotify = function(port, size, data, addrIP)
*
* Remove port output-notification handler(s) (to be ENABLED later if needed)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} start address
* @param {number} end address
*
Bus.prototype.removePortOutputNotify = function(start, end)
Bus8080.prototype.removePortOutputNotify = function(start, end)
{
for (var port = start; port < end; port++) {
if (this.aPortOutputNotify[port]) {
@ -1047,14 +1047,14 @@ Bus.prototype.removePortOutputNotify = function(start, end)
/**
* reportError(op, addr, size, fQuiet)
*
* @this {Bus}
* @this {Bus8080}
* @param {number} op
* @param {number} addr
* @param {number} size
* @param {boolean} [fQuiet] (true if any error should be quietly logged)
* @return {boolean} false
*/
Bus.prototype.reportError = function(op, addr, size, fQuiet)
Bus8080.prototype.reportError = function(op, addr, size, fQuiet)
{
var sError = "Memory block error (" + op + ": " + str.toHex(addr) + "," + str.toHex(size) + ")";
if (fQuiet) {
@ -1069,4 +1069,4 @@ Bus.prototype.reportError = function(op, addr, size, fQuiet)
return false;
};
if (NODE) module.exports = Bus;
if (NODE) module.exports = Bus8080;

View file

@ -36,34 +36,34 @@ if (NODE) {
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var State = require("./state");
var CPUDef = require("./cpudef");
var State = require("../../shared/lib/state");
var CPUDef8080 = require("./cpudef");
var Messages8080= require("./messages");
}
/**
* ChipSet(parmsChipSet)
* ChipSet8080(parmsChipSet)
*
* The ChipSet component has the following component-specific (parmsChipSet) properties:
* The ChipSet8080 component has the following component-specific (parmsChipSet) properties:
*
* model: eg, "SI1978" (should be a member of ChipSet.MODELS)
* model: eg, "SI1978" (should be a member of ChipSet8080.MODELS)
* swDIP: eg, "00000000", where swDIP[0] is DIP0, swDIP[1] is DIP1, etc.
*
* @constructor
* @extends Component
* @param {Object} parmsChipSet
*/
function ChipSet(parmsChipSet)
function ChipSet8080(parmsChipSet)
{
Component.call(this, "ChipSet", parmsChipSet, ChipSet, Messages.CHIPSET);
Component.call(this, "ChipSet", parmsChipSet, ChipSet8080, Messages8080.CHIPSET);
var model = parmsChipSet['model'];
if (model && !ChipSet.MODELS[model]) {
if (model && !ChipSet8080.MODELS[model]) {
Component.notice("Unrecognized ChipSet model: " + model);
}
this.config = ChipSet.MODELS[model] || {};
this.config = ChipSet8080.MODELS[model] || {};
this.bSwitches = this.parseDIPSwitches(parmsChipSet['swDIP']);
@ -98,7 +98,7 @@ function ChipSet(parmsChipSet)
this.setReady();
}
Component.subclass(ChipSet);
Component.subclass(ChipSet8080);
/*
* NOTE: The STATUS1 port could have been handled entirely by the Keyboard component, but it was just as easy
@ -106,7 +106,7 @@ Component.subclass(ChipSet);
* button press or release. It's a six-of-one, half-a-dozen-of-another choice, since technically, Space Invaders
* doesn't have a keyboard.
*/
ChipSet.SI1978 = {
ChipSet8080.SI1978 = {
MODEL: 1978.1,
STATUS0: { // NOTE: STATUS0 not used by the SI1978 ROMs; refer to STATUS1 instead
PORT: 0,
@ -218,7 +218,7 @@ ChipSet.SI1978 = {
* but some are more appropriately handled by other components; eg, port 0x82 is handled by the Keyboard component,
* so it's defined there instead of here.
*/
ChipSet.VT100 = {
ChipSet8080.VT100 = {
MODEL: 100.0,
FLAGS: {
PORT: 0x42, // read-only
@ -363,20 +363,20 @@ ChipSet.VT100 = {
/*
* Supported models and their configurations
*/
ChipSet.MODELS = {
"SI1978": ChipSet.SI1978,
"VT100": ChipSet.VT100
ChipSet8080.MODELS = {
"SI1978": ChipSet8080.SI1978,
"VT100": ChipSet8080.VT100
};
/**
* parseDIPSwitches(sBits, bDefault)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {string} sBits describing switch settings
* @param {number} [bDefault]
* @return {number|undefined}
*/
ChipSet.prototype.parseDIPSwitches = function(sBits, bDefault)
ChipSet8080.prototype.parseDIPSwitches = function(sBits, bDefault)
{
var b = bDefault;
if (sBits) {
@ -396,14 +396,14 @@ ChipSet.prototype.parseDIPSwitches = function(sBits, bDefault)
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "sw1")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
ChipSet.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
ChipSet8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
return false;
};
@ -411,21 +411,21 @@ ChipSet.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {ChipSet}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {ChipSet8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
ChipSet8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
this.cmp = cmp;
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
this.serial = /** @type {SerialPort} */ (cmp.getMachineComponent("SerialPort"));
this.video = /** @type {Video} */ (cmp.getMachineComponent("Video"));
this.kbd = /** @type {Keyboard8080} */ (cmp.getMachineComponent("Keyboard"));
this.serial = /** @type {SerialPort8080} */ (cmp.getMachineComponent("SerialPort"));
this.video = /** @type {Video8080} */ (cmp.getMachineComponent("Video"));
bus.addPortInputTable(this, this.config.portsInput);
bus.addPortOutputTable(this, this.config.portsOutput);
};
@ -433,12 +433,12 @@ ChipSet.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* powerUp(data, fRepower)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
ChipSet.prototype.powerUp = function(data, fRepower)
ChipSet8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
if (!data) {
@ -453,39 +453,39 @@ ChipSet.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave, fShutdown)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
ChipSet.prototype.powerDown = function(fSave, fShutdown)
ChipSet8080.prototype.powerDown = function(fSave, fShutdown)
{
return fSave? this.save() : true;
};
ChipSet.SI1978.INIT = [
ChipSet8080.SI1978.INIT = [
[
ChipSet.SI1978.STATUS0.ALWAYS_SET,
ChipSet.SI1978.STATUS1.ALWAYS_SET,
ChipSet.SI1978.STATUS2.ALWAYS_SET,
ChipSet8080.SI1978.STATUS0.ALWAYS_SET,
ChipSet8080.SI1978.STATUS1.ALWAYS_SET,
ChipSet8080.SI1978.STATUS2.ALWAYS_SET,
0, 0, 0, 0
]
];
ChipSet.VT100.INIT = [
ChipSet8080.VT100.INIT = [
[
ChipSet.VT100.BRIGHTNESS.INIT,
ChipSet.VT100.FLAGS.NO_AVO | ChipSet.VT100.FLAGS.NO_GFX
ChipSet8080.VT100.BRIGHTNESS.INIT,
ChipSet8080.VT100.FLAGS.NO_AVO | ChipSet8080.VT100.FLAGS.NO_GFX
],
[
ChipSet.VT100.DC011.INITCOLS,
ChipSet.VT100.DC011.INITRATE
ChipSet8080.VT100.DC011.INITCOLS,
ChipSet8080.VT100.DC011.INITRATE
],
[
ChipSet.VT100.DC012.INITSCROLL,
ChipSet.VT100.DC012.INITBLINK,
ChipSet.VT100.DC012.INITREVERSE,
ChipSet.VT100.DC012.INITATTR
ChipSet8080.VT100.DC012.INITSCROLL,
ChipSet8080.VT100.DC012.INITBLINK,
ChipSet8080.VT100.DC012.INITREVERSE,
ChipSet8080.VT100.DC012.INITATTR
],
[
0, 0, 0, 0,
@ -507,9 +507,9 @@ ChipSet.VT100.INIT = [
/**
* reset()
*
* @this {ChipSet}
* @this {ChipSet8080}
*/
ChipSet.prototype.reset = function()
ChipSet8080.prototype.reset = function()
{
if (this.config.INIT && !this.restore(this.config.INIT)) {
this.notice("reset error");
@ -521,17 +521,17 @@ ChipSet.prototype.reset = function()
*
* This implements save support for the ChipSet component.
*
* @this {ChipSet}
* @this {ChipSet8080}
* @return {Object}
*/
ChipSet.prototype.save = function()
ChipSet8080.prototype.save = function()
{
var state = new State(this);
switch(this.config.MODEL) {
case ChipSet.SI1978.MODEL:
case ChipSet8080.SI1978.MODEL:
state.set(0, [this.bStatus0, this.bStatus1, this.bStatus2, this.wShiftData, this.bShiftCount, this.bSound1, this.bSound2]);
break;
case ChipSet.VT100.MODEL:
case ChipSet8080.VT100.MODEL:
state.set(0, [this.bBrightness, this.bFlags]);
state.set(1, [this.bDC011Cols, this.bDC011Rate]);
state.set(2, [this.bDC012Scroll, this.bDC012Blink, this.bDC012Reverse, this.bDC012Attr]);
@ -546,16 +546,16 @@ ChipSet.prototype.save = function()
*
* This implements restore support for the ChipSet component.
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
ChipSet.prototype.restore = function(data)
ChipSet8080.prototype.restore = function(data)
{
var a;
if (data && (a = data[0]) && a.length) {
switch(this.config.MODEL) {
case ChipSet.SI1978.MODEL:
case ChipSet8080.SI1978.MODEL:
this.bStatus0 = a[0];
this.bStatus1 = a[1];
this.bStatus2 = a[2];
@ -564,7 +564,7 @@ ChipSet.prototype.restore = function(data)
this.bSound1 = a[5];
this.bSound2 = a[6];
return true;
case ChipSet.VT100.MODEL:
case ChipSet8080.VT100.MODEL:
this.bBrightness = a[0];
this.bFlags = a[1];
a = data[1];
@ -592,9 +592,9 @@ ChipSet.prototype.restore = function(data)
*
* Notification from the CPU that it's starting.
*
* @this {ChipSet}
* @this {ChipSet8080}
*/
ChipSet.prototype.start = function()
ChipSet8080.prototype.start = function()
{
/*
* Currently, all we (may) do with this notification is allow the speaker to make noise.
@ -606,9 +606,9 @@ ChipSet.prototype.start = function()
*
* Notification from the CPU that it's stopping.
*
* @this {ChipSet}
* @this {ChipSet8080}
*/
ChipSet.prototype.stop = function()
ChipSet8080.prototype.stop = function()
{
/*
* Currently, all we (may) do with this notification is prevent the speaker from making noise.
@ -618,11 +618,11 @@ ChipSet.prototype.stop = function()
/**
* updateStatus0(bit, fSet)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} bit
* @param {boolean} fSet
*/
ChipSet.prototype.updateStatus0 = function(bit, fSet)
ChipSet8080.prototype.updateStatus0 = function(bit, fSet)
{
this.bStatus0 &= ~bit;
if (fSet) this.bStatus0 |= bit;
@ -631,11 +631,11 @@ ChipSet.prototype.updateStatus0 = function(bit, fSet)
/**
* updateStatus1(bit, fSet)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} bit
* @param {boolean} fSet
*/
ChipSet.prototype.updateStatus1 = function(bit, fSet)
ChipSet8080.prototype.updateStatus1 = function(bit, fSet)
{
this.bStatus1 &= ~bit;
if (fSet) this.bStatus1 |= bit;
@ -644,11 +644,11 @@ ChipSet.prototype.updateStatus1 = function(bit, fSet)
/**
* updateStatus2(bit, fSet)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} bit
* @param {boolean} fSet
*/
ChipSet.prototype.updateStatus2 = function(bit, fSet)
ChipSet8080.prototype.updateStatus2 = function(bit, fSet)
{
this.bStatus2 &= ~bit;
if (fSet) this.bStatus2 |= bit;
@ -657,12 +657,12 @@ ChipSet.prototype.updateStatus2 = function(bit, fSet)
/**
* inSIStatus0(port, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x00)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inSIStatus0 = function(port, addrFrom)
ChipSet8080.prototype.inSIStatus0 = function(port, addrFrom)
{
var b = this.bStatus0;
this.printMessageIO(port, null, addrFrom, "STATUS0", b, true);
@ -672,12 +672,12 @@ ChipSet.prototype.inSIStatus0 = function(port, addrFrom)
/**
* inSIStatus1(port, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x01)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inSIStatus1 = function(port, addrFrom)
ChipSet8080.prototype.inSIStatus1 = function(port, addrFrom)
{
var b = this.bStatus1;
this.printMessageIO(port, null, addrFrom, "STATUS1", b, true);
@ -687,12 +687,12 @@ ChipSet.prototype.inSIStatus1 = function(port, addrFrom)
/**
* inSIStatus2(port, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x02)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inSIStatus2 = function(port, addrFrom)
ChipSet8080.prototype.inSIStatus2 = function(port, addrFrom)
{
var b = this.bStatus2;
this.printMessageIO(port, null, addrFrom, "STATUS2", b, true);
@ -702,12 +702,12 @@ ChipSet.prototype.inSIStatus2 = function(port, addrFrom)
/**
* inSIShiftResult(port, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x03)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inSIShiftResult = function(port, addrFrom)
ChipSet8080.prototype.inSIShiftResult = function(port, addrFrom)
{
var b = (this.wShiftData >> (8 - this.bShiftCount)) & 0xff;
this.printMessageIO(port, null, addrFrom, "SHIFT.RESULT", b, true);
@ -717,12 +717,12 @@ ChipSet.prototype.inSIShiftResult = function(port, addrFrom)
/**
* outSIShiftCount(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x02)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outSIShiftCount = function(port, b, addrFrom)
ChipSet8080.prototype.outSIShiftCount = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "SHIFT.COUNT", null, true);
this.bShiftCount = b;
@ -731,12 +731,12 @@ ChipSet.prototype.outSIShiftCount = function(port, b, addrFrom)
/**
* outSISound1(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x03)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outSISound1 = function(port, b, addrFrom)
ChipSet8080.prototype.outSISound1 = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "SOUND1", null, true);
this.bSound1 = b;
@ -745,12 +745,12 @@ ChipSet.prototype.outSISound1 = function(port, b, addrFrom)
/**
* outSIShiftData(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x04)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outSIShiftData = function(port, b, addrFrom)
ChipSet8080.prototype.outSIShiftData = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "SHIFT.DATA", null, true);
this.wShiftData = (b << 8) | (this.wShiftData >> 8);
@ -759,12 +759,12 @@ ChipSet.prototype.outSIShiftData = function(port, b, addrFrom)
/**
* outSISound2(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x05)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outSISound2 = function(port, b, addrFrom)
ChipSet8080.prototype.outSISound2 = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "SOUND2", null, true);
this.bSound2 = b;
@ -773,12 +773,12 @@ ChipSet.prototype.outSISound2 = function(port, b, addrFrom)
/**
* outSIWatchdog(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x06)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outSIWatchdog = function(port, b, addrFrom)
ChipSet8080.prototype.outSIWatchdog = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "WATCHDOG", null, true);
};
@ -796,7 +796,7 @@ ChipSet.prototype.outSIWatchdog = function(port, b, addrFrom)
* @param {number} iBit
* @return {number}
*/
ChipSet.prototype.getVT100LBA = function(iBit)
ChipSet8080.prototype.getVT100LBA = function(iBit)
{
return (this.cpu.getCycles() & (1 << (iBit - 1))) << 1;
};
@ -806,7 +806,7 @@ ChipSet.prototype.getVT100LBA = function(iBit)
*
* @return {number}
*/
ChipSet.prototype.getNVRAddr = function()
ChipSet8080.prototype.getNVRAddr = function()
{
var i;
var tens = 0, ones = 0;
@ -827,54 +827,54 @@ ChipSet.prototype.getNVRAddr = function()
/**
* doNVRCommand()
*/
ChipSet.prototype.doNVRCommand = function()
ChipSet8080.prototype.doNVRCommand = function()
{
var addr, data;
var bit = this.bNVRLatch & 0x1;
var bCmd = (this.bNVRLatch >> 1) & 0x7;
switch(bCmd) {
case ChipSet.VT100.NVR.CMD.STANDBY:
case ChipSet8080.VT100.NVR.CMD.STANDBY:
break;
case ChipSet.VT100.NVR.CMD.ACCEPT_ADDR:
case ChipSet8080.VT100.NVR.CMD.ACCEPT_ADDR:
this.dNVRAddr = (this.dNVRAddr << 1) | bit;
break;
case ChipSet.VT100.NVR.CMD.ERASE:
case ChipSet8080.VT100.NVR.CMD.ERASE:
addr = this.getNVRAddr();
this.aNVRWords[addr] = ChipSet.VT100.NVR.WORDMASK;
this.aNVRWords[addr] = ChipSet8080.VT100.NVR.WORDMASK;
this.printMessage("doNVRCommand(): erase data at addr " + str.toHexWord(addr));
break;
case ChipSet.VT100.NVR.CMD.ACCEPT_DATA:
case ChipSet8080.VT100.NVR.CMD.ACCEPT_DATA:
this.wNVRData = (this.wNVRData << 1) | bit;
break;
case ChipSet.VT100.NVR.CMD.WRITE:
case ChipSet8080.VT100.NVR.CMD.WRITE:
addr = this.getNVRAddr();
data = this.wNVRData & ChipSet.VT100.NVR.WORDMASK;
data = this.wNVRData & ChipSet8080.VT100.NVR.WORDMASK;
this.aNVRWords[addr] = data;
this.printMessage("doNVRCommand(): write data " + str.toHexWord(data) + " to addr " + str.toHexWord(addr));
break;
case ChipSet.VT100.NVR.CMD.READ:
case ChipSet8080.VT100.NVR.CMD.READ:
addr = this.getNVRAddr();
data = this.aNVRWords[addr];
/*
* If we don't explicitly initialize aNVRWords[], pretend any uninitialized words contains WORDMASK.
*/
if (data == null) data = ChipSet.VT100.NVR.WORDMASK;
if (data == null) data = ChipSet8080.VT100.NVR.WORDMASK;
this.wNVRData = data;
this.printMessage("doNVRCommand(): read data " + str.toHexWord(data) + " from addr " + str.toHexWord(addr));
break;
case ChipSet.VT100.NVR.CMD.SHIFT_OUT:
case ChipSet8080.VT100.NVR.CMD.SHIFT_OUT:
this.wNVRData <<= 1;
/*
* Since WORDMASK is 0x3fff, this will mask the shifted data with 0x4000, which is the bit we want to isolate.
*/
this.bNVROut = this.wNVRData & (ChipSet.VT100.NVR.WORDMASK + 1);
this.bNVROut = this.wNVRData & (ChipSet8080.VT100.NVR.WORDMASK + 1);
break;
default:
@ -886,35 +886,35 @@ ChipSet.prototype.doNVRCommand = function()
/**
* inVT100Flags(port, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x42)
* @param {number} [addrFrom] (not defined if the Debugger is trying to read the specified port)
* @return {number} simulated port value
*/
ChipSet.prototype.inVT100Flags = function(port, addrFrom)
ChipSet8080.prototype.inVT100Flags = function(port, addrFrom)
{
/*
* The NVR_CLK bit is driven by LBA7 (ie, bit 7 from Line Buffer Address generation); see the DC011 discussion above.
*/
var b = this.bFlags;
b &= ~ChipSet.VT100.FLAGS.NVR_CLK;
b &= ~ChipSet8080.VT100.FLAGS.NVR_CLK;
if (this.getVT100LBA(7)) {
b |= ChipSet.VT100.FLAGS.NVR_CLK;
b |= ChipSet8080.VT100.FLAGS.NVR_CLK;
if (b != this.bFlags) {
this.doNVRCommand();
}
}
b &= ~ChipSet.VT100.FLAGS.NVR_DATA;
b &= ~ChipSet8080.VT100.FLAGS.NVR_DATA;
if (this.bNVROut) {
b |= ChipSet.VT100.FLAGS.NVR_DATA;
b |= ChipSet8080.VT100.FLAGS.NVR_DATA;
}
b &= ~ChipSet.VT100.FLAGS.KBD_XMIT;
b &= ~ChipSet8080.VT100.FLAGS.KBD_XMIT;
if (this.kbd && this.kbd.isTransmitterReady()) {
b |= ChipSet.VT100.FLAGS.KBD_XMIT;
b |= ChipSet8080.VT100.FLAGS.KBD_XMIT;
}
b &= ~ChipSet.VT100.FLAGS.UART_XMIT;
b &= ~ChipSet8080.VT100.FLAGS.UART_XMIT;
if (this.serial && this.serial.isTransmitterReady()) {
b |= ChipSet.VT100.FLAGS.UART_XMIT;
b |= ChipSet8080.VT100.FLAGS.UART_XMIT;
}
this.bFlags = b;
this.printMessageIO(port, null, addrFrom, "FLAGS", b);
@ -924,12 +924,12 @@ ChipSet.prototype.inVT100Flags = function(port, addrFrom)
/**
* outVT100Brightness(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x42)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outVT100Brightness = function(port, b, addrFrom)
ChipSet8080.prototype.outVT100Brightness = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "BRIGHTNESS");
this.bBrightness = b;
@ -938,12 +938,12 @@ ChipSet.prototype.outVT100Brightness = function(port, b, addrFrom)
/**
* outVT100NVRLatch(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0x62)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outVT100NVRLatch = function(port, b, addrFrom)
ChipSet8080.prototype.outVT100NVRLatch = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "NVR.LATCH");
this.bNVRLatch = b;
@ -955,12 +955,12 @@ ChipSet.prototype.outVT100NVRLatch = function(port, b, addrFrom)
* TODO: Consider whether we should disable any interrupts (eg, vertical retrace) until
* this port is initialized at runtime.
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0xA2)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outVT100DC012 = function(port, b, addrFrom)
ChipSet8080.prototype.outVT100DC012 = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "DC012");
@ -997,29 +997,29 @@ ChipSet.prototype.outVT100DC012 = function(port, b, addrFrom)
/**
* outVT100DC011(port, b, addrFrom)
*
* @this {ChipSet}
* @this {ChipSet8080}
* @param {number} port (0xC2)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
ChipSet.prototype.outVT100DC011 = function(port, b, addrFrom)
ChipSet8080.prototype.outVT100DC011 = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "DC011");
if (b & ChipSet.VT100.DC011.RATE60) {
b &= ChipSet.VT100.DC011.RATE50;
if (b & ChipSet8080.VT100.DC011.RATE60) {
b &= ChipSet8080.VT100.DC011.RATE50;
if (this.bDC011Rate != b) {
this.bDC011Rate = b;
if (this.video) {
this.video.updateRate(this.bDC011Rate == ChipSet.VT100.DC011.RATE50? 50 : 60);
this.video.updateRate(this.bDC011Rate == ChipSet8080.VT100.DC011.RATE50? 50 : 60);
}
}
} else {
b &= ChipSet.VT100.DC011.COLS132;
b &= ChipSet8080.VT100.DC011.COLS132;
if (this.bDC011Cols != b) {
this.bDC011Cols = b;
if (this.video) {
var nCols = (this.bDC011Cols == ChipSet.VT100.DC011.COLS132? 132 : 80);
var nRows = (nCols > 80 && (this.bFlags & ChipSet.VT100.FLAGS.NO_AVO)? 14 : 24);
var nCols = (this.bDC011Cols == ChipSet8080.VT100.DC011.COLS132? 132 : 80);
var nRows = (nCols > 80 && (this.bFlags & ChipSet8080.VT100.FLAGS.NO_AVO)? 14 : 24);
this.video.updateDimensions(nCols, nRows);
}
}
@ -1029,47 +1029,47 @@ ChipSet.prototype.outVT100DC011 = function(port, b, addrFrom)
/*
* Port notification tables
*/
ChipSet.SI1978.portsInput = {
0x00: ChipSet.prototype.inSIStatus0,
0x01: ChipSet.prototype.inSIStatus1,
0x02: ChipSet.prototype.inSIStatus2,
0x03: ChipSet.prototype.inSIShiftResult
ChipSet8080.SI1978.portsInput = {
0x00: ChipSet8080.prototype.inSIStatus0,
0x01: ChipSet8080.prototype.inSIStatus1,
0x02: ChipSet8080.prototype.inSIStatus2,
0x03: ChipSet8080.prototype.inSIShiftResult
};
ChipSet.SI1978.portsOutput = {
0x02: ChipSet.prototype.outSIShiftCount,
0x03: ChipSet.prototype.outSISound1,
0x04: ChipSet.prototype.outSIShiftData,
0x05: ChipSet.prototype.outSISound2,
0x06: ChipSet.prototype.outSIWatchdog
ChipSet8080.SI1978.portsOutput = {
0x02: ChipSet8080.prototype.outSIShiftCount,
0x03: ChipSet8080.prototype.outSISound1,
0x04: ChipSet8080.prototype.outSIShiftData,
0x05: ChipSet8080.prototype.outSISound2,
0x06: ChipSet8080.prototype.outSIWatchdog
};
ChipSet.VT100.portsInput = {
0x42: ChipSet.prototype.inVT100Flags
ChipSet8080.VT100.portsInput = {
0x42: ChipSet8080.prototype.inVT100Flags
};
ChipSet.VT100.portsOutput = {
0x42: ChipSet.prototype.outVT100Brightness,
0x62: ChipSet.prototype.outVT100NVRLatch,
0xA2: ChipSet.prototype.outVT100DC012,
0xC2: ChipSet.prototype.outVT100DC011
ChipSet8080.VT100.portsOutput = {
0x42: ChipSet8080.prototype.outVT100Brightness,
0x62: ChipSet8080.prototype.outVT100NVRLatch,
0xA2: ChipSet8080.prototype.outVT100DC012,
0xC2: ChipSet8080.prototype.outVT100DC011
};
/**
* ChipSet.init()
* ChipSet8080.init()
*
* This function operates on every HTML element of class "chipset", extracting the
* JSON-encoded parameters for the ChipSet constructor from the element's "data-value"
* attribute, invoking the constructor to create a ChipSet component, and then binding
* any associated HTML controls to the new component.
*/
ChipSet.init = function()
ChipSet8080.init = function()
{
var aeChipSet = Component.getElementsByClass(document, PC8080.APPCLASS, "chipset");
for (var iChip = 0; iChip < aeChipSet.length; iChip++) {
var eChipSet = aeChipSet[iChip];
var parmsChipSet = Component.getComponentParms(eChipSet);
var chipset = new ChipSet(parmsChipSet);
var chipset = new ChipSet8080(parmsChipSet);
Component.bindComponentControls(chipset, eChipSet, PC8080.APPCLASS);
}
};
@ -1077,6 +1077,6 @@ ChipSet.init = function()
/*
* Initialize every ChipSet module on the page.
*/
web.onInit(ChipSet.init);
web.onInit(ChipSet8080.init);
if (NODE) module.exports = ChipSet;
if (NODE) module.exports = ChipSet8080;

View file

@ -38,17 +38,17 @@ if (NODE) {
var UserAPI = require("../../shared/lib/userapi");
var ReportAPI = require("../../shared/lib/reportapi");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
/*
* TODO: I'm confused why WebStorm complains if the following require() is missing in THIS file but not other files.
*/
var PC8080 = require("./defines");
var Messages = require("./messages");
var Bus = require("./bus");
var State = require("./state");
var Bus8080 = require("./bus");
var Messages8080= require("./messages");
}
/**
* Computer(parmsComputer, parmsMachine, fSuspended)
* Computer8080(parmsComputer, parmsMachine, fSuspended)
*
* @constructor
* @extends Component
@ -56,7 +56,7 @@ if (NODE) {
* @param {Object} [parmsMachine]
* @param {boolean} [fSuspended]
*
* The Computer component has no required (parmsComputer) properties, but it does
* The Computer8080 component has no required (parmsComputer) properties, but it does
* support the following:
*
* autoPower: true to automatically power the computer (default), false to wait;
@ -67,7 +67,7 @@ if (NODE) {
* while 24 is required for 80286 protected-mode addressing. This value is passed
* directly through to the Bus component; see that component for more details.
*
* resume: one of the Computer.RESUME constants, which are as follows:
* resume: one of the Computer8080.RESUME constants, which are as follows:
* '0' if resume disabled (default)
* '1' if enabled without prompting
* '2' if enabled with prompting
@ -81,13 +81,13 @@ if (NODE) {
* autoMount: if set, this should override any 'autoMount' property in the FDC's
* parmsFDC object.
*
* autoPower: if set, this should override any 'autoPower' property in the Computer's
* autoPower: if set, this should override any 'autoPower' property in the Computer8080's
* parmsComputer object.
*
* messages: if set, this should override any 'messages' property in the Debugger's
* parmsDbg object.
*
* state: if set, this should override any 'state' property in the Computer's
* state: if set, this should override any 'state' property in the Computer8080's
* parmsComputer object.
*
* url: the location of the machine XML file
@ -109,9 +109,9 @@ if (NODE) {
* function (if it has one--it's optional). We call the CPU's powerUp() function last,
* so that the CPU is assured that all other components are ready and "powered".
*/
function Computer(parmsComputer, parmsMachine, fSuspended) {
function Computer8080(parmsComputer, parmsMachine, fSuspended) {
Component.call(this, "Computer", parmsComputer, Computer, Messages.COMPUTER);
Component.call(this, "Computer", parmsComputer, Computer8080, Messages8080.COMPUTER);
this.flags.fPowered = false;
@ -130,7 +130,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
*/
this.nBusWidth = parmsComputer['busWidth'] || parmsComputer['buswidth'];
this.resume = Computer.RESUME_NONE;
this.resume = Computer8080.RESUME_NONE;
this.sStateData = null;
this.fStateData = false; // remembers if sStateData was loaded
this.fServerState = false;
@ -151,12 +151,12 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
* where we know getComponentByType() will only return an CPUState object or null), wrap the expression
* in parentheses. I never knew this until I stumbled across it in "Closure: The Definitive Guide".
*/
this.cpu = /** @type {CPUState} */ (Component.getComponentByType("CPU", this.id));
this.cpu = /** @type {CPUState8080} */ (Component.getComponentByType("CPU", this.id));
if (!this.cpu) {
Component.error("Unable to find CPU component");
return;
}
this.dbg = /** @type {Debugger} */ (Component.getComponentByType("Debugger", this.id));
this.dbg = /** @type {Debugger8080} */ (Component.getComponentByType("Debugger", this.id));
/*
* Enumerate all Video components for future updateVideo() calls.
@ -169,14 +169,14 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
/*
* Initialize the Bus component
*/
this.bus = new Bus({'id': this.idMachine + '.bus', 'busWidth': this.nBusWidth}, this.cpu, this.dbg);
this.bus = new Bus8080({'id': this.idMachine + '.bus', 'busWidth': this.nBusWidth}, this.cpu, this.dbg);
/*
* Iterate through all the components and connect them to the Control Panel, if any
*/
var iComponent, component;
var aComponents = Component.getComponents(this.id);
this.panel = /** @type {Panel} */ (Component.getComponentByType("Panel", this.id));
this.panel = /** @type {Panel8080} */ (Component.getComponentByType("Panel", this.id));
if (this.panel && this.panel.controlPrint) {
for (iComponent = 0; iComponent < aComponents.length; iComponent++) {
@ -240,7 +240,7 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
sStatePath = this.sStatePath = sState;
if (!fAllowResume) {
this.fServerState = true;
this.resume = Computer.RESUME_NONE;
this.resume = Computer8080.RESUME_NONE;
}
if (this.resume) {
this.stateComputer = new State(this, PC8080.APPVERSION);
@ -278,33 +278,33 @@ function Computer(parmsComputer, parmsMachine, fSuspended) {
if (!fSuspended && this.fAutoPower) this.wait(this.powerOn);
}
Component.subclass(Computer);
Component.subclass(Computer8080);
Computer.STATE_FAILSAFE = "failsafe";
Computer.STATE_VALIDATE = "validate";
Computer.STATE_TIMESTAMP = "timestamp";
Computer.STATE_VERSION = "version";
Computer.STATE_HOSTURL = "url";
Computer.STATE_BROWSER = "browser";
Computer.STATE_USERID = "user";
Computer8080.STATE_FAILSAFE = "failsafe";
Computer8080.STATE_VALIDATE = "validate";
Computer8080.STATE_TIMESTAMP = "timestamp";
Computer8080.STATE_VERSION = "version";
Computer8080.STATE_HOSTURL = "url";
Computer8080.STATE_BROWSER = "browser";
Computer8080.STATE_USERID = "user";
/*
* The following constants define all the resume options. Negative values (eg, RESUME_REPOWER) are for
* internal use only, and RESUME_DELETE is not documented (it provides a way of deleting ALL saved states
* whenever a resume is declined). As a result, the only "end-user" values are 0, 1 and 2.
*/
Computer.RESUME_REPOWER = -1; // resume without changing any state (for internal use only)
Computer.RESUME_NONE = 0; // default (no resume)
Computer.RESUME_AUTO = 1; // automatically save/restore state
Computer.RESUME_PROMPT = 2; // automatically save but conditionally restore (WARNING: if restore is declined, any state is discarded)
Computer.RESUME_DELETE = 3; // same as RESUME_PROMPT but discards ALL machines states whenever ANY machine restore is declined (undocumented)
Computer8080.RESUME_REPOWER = -1; // resume without changing any state (for internal use only)
Computer8080.RESUME_NONE = 0; // default (no resume)
Computer8080.RESUME_AUTO = 1; // automatically save/restore state
Computer8080.RESUME_PROMPT = 2; // automatically save but conditionally restore (WARNING: if restore is declined, any state is discarded)
Computer8080.RESUME_DELETE = 3; // same as RESUME_PROMPT but discards ALL machines states whenever ANY machine restore is declined (undocumented)
/**
* getMachineID()
*
* @return {string}
*/
Computer.prototype.getMachineID = function()
Computer8080.prototype.getMachineID = function()
{
return this.sMachineID;
};
@ -316,7 +316,7 @@ Computer.prototype.getMachineID = function()
*
* @param {Object} [parmsMachine]
*/
Computer.prototype.setMachineParms = function(parmsMachine)
Computer8080.prototype.setMachineParms = function(parmsMachine)
{
if (!parmsMachine) {
var sParms;
@ -345,7 +345,7 @@ Computer.prototype.setMachineParms = function(parmsMachine)
* @param {Object} [parmsComponent]
* @return {string|undefined}
*/
Computer.prototype.getMachineParm = function(sParm, parmsComponent)
Computer8080.prototype.getMachineParm = function(sParm, parmsComponent)
{
/*
* When checking parmsURL, the check is allowed be a bit looser, because URL parameters are
@ -373,7 +373,7 @@ Computer.prototype.getMachineParm = function(sParm, parmsComponent)
*
* @return {string|null}
*/
Computer.prototype.saveMachineParms = function()
Computer8080.prototype.saveMachineParms = function()
{
return this.parmsMachine? JSON.stringify(this.parmsMachine) : null;
};
@ -383,7 +383,7 @@ Computer.prototype.saveMachineParms = function()
*
* @return {string}
*/
Computer.prototype.getUserID = function()
Computer8080.prototype.getUserID = function()
{
return this.sUserID || "";
};
@ -391,12 +391,12 @@ Computer.prototype.getUserID = function()
/**
* doneLoad(sURL, sStateData, nErrorCode)
*
* @this {Computer}
* @this {Computer8080}
* @param {string} sURL
* @param {string} sStateData
* @param {number} nErrorCode
*/
Computer.prototype.doneLoad = function(sURL, sStateData, nErrorCode)
Computer8080.prototype.doneLoad = function(sURL, sStateData, nErrorCode)
{
if (!nErrorCode) {
this.sStateData = sStateData;
@ -426,11 +426,11 @@ Computer.prototype.doneLoad = function(sURL, sStateData, nErrorCode)
*
* param {function(this:Computer, (number|Array|undefined)): undefined} fn
*
* @this {Computer}
* @this {Computer8080}
* @param {function(...)} fn
* @param {number|Array} [parms] optional parameters
*/
Computer.prototype.wait = function(fn, parms)
Computer8080.prototype.wait = function(fn, parms)
{
var computer = this;
var aComponents = Component.getComponents(this.id);
@ -443,7 +443,7 @@ Computer.prototype.wait = function(fn, parms)
return;
}
}
if (DEBUG && this.messageEnabled()) this.printMessage("Computer.wait(ready)");
if (DEBUG && this.messageEnabled()) this.printMessage("Computer8080.wait(ready)");
fn.call(this, parms);
};
@ -452,17 +452,17 @@ Computer.prototype.wait = function(fn, parms)
*
* NOTE: We clear() stateValidate only when there's no stateComputer.
*
* @this {Computer}
* @this {Computer8080}
* @param {State|null} [stateComputer]
* @return {boolean} true if state passes validation, false if not
*/
Computer.prototype.validateState = function(stateComputer)
Computer8080.prototype.validateState = function(stateComputer)
{
var fValid = true;
var stateValidate = new State(this, PC8080.APPVERSION, Computer.STATE_VALIDATE);
var stateValidate = new State(this, PC8080.APPVERSION, Computer8080.STATE_VALIDATE);
if (stateValidate.load() && stateValidate.parse()) {
var sTimestampValidate = stateValidate.get(Computer.STATE_TIMESTAMP);
var sTimestampComputer = stateComputer ? stateComputer.get(Computer.STATE_TIMESTAMP) : "unknown";
var sTimestampValidate = stateValidate.get(Computer8080.STATE_TIMESTAMP);
var sTimestampComputer = stateComputer? stateComputer.get(Computer8080.STATE_TIMESTAMP) : "unknown";
if (sTimestampValidate != sTimestampComputer) {
this.notice("Machine state may be out-of-date\n(" + sTimestampValidate + " vs. " + sTimestampComputer + ")\nCheck your browser's local storage limits");
fValid = false;
@ -481,17 +481,17 @@ Computer.prototype.validateState = function(stateComputer)
*
* Power every component "up", applying any previously available state information.
*
* @this {Computer}
* @this {Computer8080}
* @param {number} [resume] is a valid RESUME value; default is this.resume
*/
Computer.prototype.powerOn = function(resume)
Computer8080.prototype.powerOn = function(resume)
{
if (resume === undefined) {
resume = this.resume || (this.sStateData? Computer.RESUME_AUTO : Computer.RESUME_NONE);
resume = this.resume || (this.sStateData? Computer8080.RESUME_AUTO : Computer8080.RESUME_NONE);
}
if (DEBUG && this.messageEnabled()) {
this.printMessage("Computer.powerOn(" + (resume == Computer.RESUME_REPOWER ? "repower" : (resume ? "resume" : "")) + ")");
this.printMessage("Computer8080.powerOn(" + (resume == Computer8080.RESUME_REPOWER ? "repower" : (resume ? "resume" : "")) + ")");
}
if (this.nPowerChange) {
@ -504,10 +504,10 @@ Computer.prototype.powerOn = function(resume)
this.fRestoreError = false;
var stateComputer = this.stateComputer || new State(this, PC8080.APPVERSION);
if (resume == Computer.RESUME_REPOWER) {
if (resume == Computer8080.RESUME_REPOWER) {
fRepower = true;
}
else if (resume > Computer.RESUME_NONE) {
else if (resume > Computer8080.RESUME_NONE) {
if (stateComputer.load(this.sStateData)) {
/*
* Since we're resuming something (either a predefined state or a state from localStorage), let's
@ -515,7 +515,7 @@ Computer.prototype.powerOn = function(resume)
* Which means, of course, that if a previous "failsafe" checkpoint already exists, something bad
* may have happened the last time around.
*/
this.stateFailSafe = new State(this, PC8080.APPVERSION, Computer.STATE_FAILSAFE);
this.stateFailSafe = new State(this, PC8080.APPVERSION, Computer8080.STATE_FAILSAFE);
if (this.stateFailSafe.load()) {
this.powerReport(stateComputer);
/*
@ -523,7 +523,7 @@ Computer.prototype.powerOn = function(resume)
* all the way to RESUME_PROMPT, so that the user will be prompted, and if the user declines to
* restore, the state will be removed.
*/
resume = Computer.RESUME_PROMPT;
resume = Computer8080.RESUME_PROMPT;
/*
* To ensure that the set() below succeeds, we need to call unload(), otherwise it may fail
* with a "read only" error (eg, "TypeError: Cannot assign to read only property 'timestamp'").
@ -531,11 +531,11 @@ Computer.prototype.powerOn = function(resume)
this.stateFailSafe.unload();
}
this.stateFailSafe.set(Computer.STATE_TIMESTAMP, usr.getTimestamp());
this.stateFailSafe.set(Computer8080.STATE_TIMESTAMP, usr.getTimestamp());
this.stateFailSafe.store();
var fValidate = this.resume && !this.fServerState;
if (resume == Computer.RESUME_AUTO || web.confirmUser("Click OK to restore the previous " + PC8080.APPNAME + " machine state, or CANCEL to reset the machine.")) {
if (resume == Computer8080.RESUME_AUTO || web.confirmUser("Click OK to restore the previous " + PC8080.APPNAME + " machine state, or CANCEL to reset the machine.")) {
fRestore = stateComputer.parse();
if (fRestore) {
var sCode = stateComputer.get(UserAPI.RES.CODE);
@ -578,7 +578,7 @@ Computer.prototype.powerOn = function(resume)
/*
* RESUME_PROMPT indicates we should delete the state if they clicked Cancel to confirm() above.
*/
if (resume == Computer.RESUME_PROMPT) stateComputer.clear();
if (resume == Computer8080.RESUME_PROMPT) stateComputer.clear();
}
} else {
/*
@ -610,7 +610,7 @@ Computer.prototype.powerOn = function(resume)
*/
var aParms = [stateComputer, resume, fRestore];
if (resume != Computer.RESUME_REPOWER) {
if (resume != Computer8080.RESUME_REPOWER) {
this.wait(this.donePowerOn, aParms);
return;
}
@ -620,14 +620,14 @@ Computer.prototype.powerOn = function(resume)
/**
* powerRestore(component, stateComputer, fRepower, fRestore)
*
* @this {Computer}
* @this {Computer8080}
* @param {Component} component
* @param {State} stateComputer
* @param {boolean} fRepower
* @param {boolean} fRestore
* @return {boolean} true if restore should continue, false if not
*/
Computer.prototype.powerRestore = function(component, stateComputer, fRepower, fRestore)
Computer8080.prototype.powerRestore = function(component, stateComputer, fRepower, fRestore)
{
if (!component.flags.fPowered) {
@ -685,7 +685,7 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
*/
if (this.sStatePath && !this.fStateData) {
stateComputer.clear();
this.resume = Computer.RESUME_NONE;
this.resume = Computer8080.RESUME_NONE;
web.reloadPage();
} else {
/*
@ -725,17 +725,17 @@ Computer.prototype.powerRestore = function(component, stateComputer, fRepower, f
*
* This is nothing more than a continuation of powerOn(), giving us the option of calling wait() one more time.
*
* @this {Computer}
* @this {Computer8080}
* @param {Array} aParms containing [stateComputer, resume, fRestore]
*/
Computer.prototype.donePowerOn = function(aParms)
Computer8080.prototype.donePowerOn = function(aParms)
{
var stateComputer = aParms[0];
var fRepower = (aParms[1] < 0);
var fRestore = aParms[2];
if (DEBUG && this.flags.fPowered && this.messageEnabled()) {
this.printMessage("Computer.donePowerOn(): redundant");
this.printMessage("Computer8080.donePowerOn(): redundant");
}
this.fInitialized = true;
@ -775,10 +775,10 @@ Computer.prototype.donePowerOn = function(aParms)
/**
* checkPower()
*
* @this {Computer}
* @this {Computer8080}
* @return {boolean} true if the computer is fully powered, false otherwise
*/
Computer.prototype.checkPower = function()
Computer8080.prototype.checkPower = function()
{
if (this.flags.fPowered) return true;
@ -803,10 +803,10 @@ Computer.prototype.checkPower = function()
/**
* powerReport(stateComputer)
*
* @this {Computer}
* @this {Computer8080}
* @param {State} stateComputer
*/
Computer.prototype.powerReport = function(stateComputer)
Computer8080.prototype.powerReport = function(stateComputer)
{
if (web.confirmUser("There may be a problem with your " + PC8080.APPNAME + " machine.\n\nTo help us diagnose it, click OK to send this " + PC8080.APPNAME + " machine state to http://" + SITEHOST + ".")) {
web.sendReport(PC8080.APPNAME, PC8080.APPVERSION, this.url, this.getUserID(), ReportAPI.TYPE.BUG, stateComputer.toString());
@ -839,18 +839,18 @@ Computer.prototype.powerReport = function(stateComputer)
* As it stands, the worst that happens is any manually mounted disk images might have to be manually remounted,
* which doesn't seem like a huge problem.
*
* @this {Computer}
* @this {Computer8080}
* @param {boolean} [fSave] is true to request a saved state
* @param {boolean} [fShutdown] is true if the machine is being shut down
* @return {string|null} string representing the saved state (or null if error)
*/
Computer.prototype.powerOff = function(fSave, fShutdown)
Computer8080.prototype.powerOff = function(fSave, fShutdown)
{
var data;
var sState = "none";
if (DEBUG && this.messageEnabled()) {
this.printMessage("Computer.powerOff(" + (fSave ? "save" : "nosave") + (fShutdown ? ",shutdown" : "") + ")");
this.printMessage("Computer8080.powerOff(" + (fSave ? "save" : "nosave") + (fShutdown ? ",shutdown" : "") + ")");
}
if (this.nPowerChange) {
@ -859,14 +859,14 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
this.nPowerChange--;
var stateComputer = new State(this, PC8080.APPVERSION);
var stateValidate = new State(this, PC8080.APPVERSION, Computer.STATE_VALIDATE);
var stateValidate = new State(this, PC8080.APPVERSION, Computer8080.STATE_VALIDATE);
var sTimestamp = usr.getTimestamp();
stateValidate.set(Computer.STATE_TIMESTAMP, sTimestamp);
stateComputer.set(Computer.STATE_TIMESTAMP, sTimestamp);
stateComputer.set(Computer.STATE_VERSION, APPVERSION);
stateComputer.set(Computer.STATE_HOSTURL, web.getHostURL());
stateComputer.set(Computer.STATE_BROWSER, web.getUserAgent());
stateValidate.set(Computer8080.STATE_TIMESTAMP, sTimestamp);
stateComputer.set(Computer8080.STATE_TIMESTAMP, sTimestamp);
stateComputer.set(Computer8080.STATE_VERSION, APPVERSION);
stateComputer.set(Computer8080.STATE_HOSTURL, web.getHostURL());
stateComputer.set(Computer8080.STATE_BROWSER, web.getUserAgent());
/*
* Always power the CPU "down" first, just to help insure it doesn't ask other components to do anything
@ -932,7 +932,7 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
*/
if (this.resume) {
fClear = true;
fClearAll = (this.resume == Computer.RESUME_DELETE);
fClearAll = (this.resume == Computer8080.RESUME_DELETE);
}
}
if (fClear) {
@ -963,9 +963,9 @@ Computer.prototype.powerOff = function(fSave, fShutdown)
* allocated the Bus object ourselves, after all the other components were allocated, it ends
* up near the end of Component's list of components. Hence the special case for this.bus below.
*
* @this {Computer}
* @this {Computer8080}
*/
Computer.prototype.reset = function()
Computer8080.prototype.reset = function()
{
if (this.bus && this.bus.reset) {
/*
@ -993,11 +993,11 @@ Computer.prototype.reset = function()
* Note that we're called by runCPU(), which is why we exclude the CPU component,
* as well as ourselves.
*
* @this {Computer}
* @this {Computer8080}
* @param {number} ms
* @param {number} nCycles
*/
Computer.prototype.start = function(ms, nCycles)
Computer8080.prototype.start = function(ms, nCycles)
{
var aComponents = Component.getComponents(this.id);
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
@ -1017,11 +1017,11 @@ Computer.prototype.start = function(ms, nCycles)
* Note that we're called by runCPU(), which is why we exclude the CPU component,
* as well as ourselves.
*
* @this {Computer}
* @this {Computer8080}
* @param {number} ms
* @param {number} nCycles
*/
Computer.prototype.stop = function(ms, nCycles)
Computer8080.prototype.stop = function(ms, nCycles)
{
var aComponents = Component.getComponents(this.id);
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
@ -1036,14 +1036,14 @@ Computer.prototype.stop = function(ms, nCycles)
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {Computer}
* @this {Computer8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
Computer.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
Computer8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
var computer = this;
@ -1130,9 +1130,9 @@ Computer.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
/**
* resetUserID()
*/
Computer.prototype.resetUserID = function()
Computer8080.prototype.resetUserID = function()
{
web.setLocalStorageItem(Computer.STATE_USERID, "");
web.setLocalStorageItem(Computer8080.STATE_USERID, "");
this.sUserID = null;
};
@ -1142,11 +1142,11 @@ Computer.prototype.resetUserID = function()
* @param {boolean} [fPrompt]
* @returns {string|null|undefined}
*/
Computer.prototype.queryUserID = function(fPrompt)
Computer8080.prototype.queryUserID = function(fPrompt)
{
var sUserID = this.sUserID;
if (!sUserID) {
sUserID = web.getLocalStorageItem(Computer.STATE_USERID);
sUserID = web.getLocalStorageItem(Computer8080.STATE_USERID);
if (sUserID !== undefined) {
if (!sUserID && fPrompt) {
/*
@ -1170,11 +1170,11 @@ Computer.prototype.queryUserID = function(fPrompt)
/**
* verifyUserID(sUserID)
*
* @this {Computer}
* @this {Computer8080}
* @param {string} sUserID
* @return {string} validated user ID, or null if error
*/
Computer.prototype.verifyUserID = function(sUserID)
Computer8080.prototype.verifyUserID = function(sUserID)
{
this.sUserID = null;
var fMessages = DEBUG && this.messageEnabled();
@ -1187,8 +1187,8 @@ Computer.prototype.verifyUserID = function(sUserID)
try {
response = eval("(" + sResponse + ")");
if (response.code && response.code == UserAPI.CODE.OK) {
web.setLocalStorageItem(Computer.STATE_USERID, response.data);
if (fMessages) this.printMessage(Computer.STATE_USERID + " updated: " + response.data);
web.setLocalStorageItem(Computer8080.STATE_USERID, response.data);
if (fMessages) this.printMessage(Computer8080.STATE_USERID + " updated: " + response.data);
this.sUserID = response.data;
} else {
if (fMessages) this.printMessage(response.code + ": " + response.data);
@ -1205,20 +1205,20 @@ Computer.prototype.verifyUserID = function(sUserID)
/**
* getServerStatePath()
*
* @this {Computer}
* @this {Computer8080}
* @return {string|null} sStatePath (null if no localStorage or no USERID stored in localStorage)
*/
Computer.prototype.getServerStatePath = function()
Computer8080.prototype.getServerStatePath = function()
{
var sStatePath = null;
if (this.sUserID) {
if (DEBUG && this.messageEnabled()) {
this.printMessage(Computer.STATE_USERID + " for load: " + this.sUserID);
this.printMessage(Computer8080.STATE_USERID + " for load: " + this.sUserID);
}
sStatePath = web.getHost() + UserAPI.ENDPOINT + '?' + UserAPI.QUERY.REQ + '=' + UserAPI.REQ.LOAD + '&' + UserAPI.QUERY.USER + '=' + this.sUserID + '&' + UserAPI.QUERY.STATE + '=' + State.key(this, PC8080.APPVERSION);
} else {
if (DEBUG && this.messageEnabled()) {
this.printMessage(Computer.STATE_USERID + " unavailable");
this.printMessage(Computer8080.STATE_USERID + " unavailable");
}
}
return sStatePath;
@ -1230,7 +1230,7 @@ Computer.prototype.getServerStatePath = function()
* @param {string} sUserID
* @param {string|null} sState
*/
Computer.prototype.saveServerState = function(sUserID, sState)
Computer8080.prototype.saveServerState = function(sUserID, sState)
{
/*
* We must pass fSync == true, because (as I understand it) browsers will blow off any async
@ -1265,16 +1265,16 @@ Computer.prototype.saveServerState = function(sUserID, sState)
/**
* storeServerState(sUserID, sState, fSync)
*
* @this {Computer}
* @this {Computer8080}
* @param {string} sUserID
* @param {string} sState
* @param {boolean} [fSync] is true if we're powering down and should perform a synchronous request (default is async)
* @return {*} server response if fSync is true and a response was received; otherwise null
*/
Computer.prototype.storeServerState = function(sUserID, sState, fSync)
Computer8080.prototype.storeServerState = function(sUserID, sState, fSync)
{
if (DEBUG && this.messageEnabled()) {
this.printMessage(Computer.STATE_USERID + " for store: " + sUserID);
this.printMessage(Computer8080.STATE_USERID + " for store: " + sUserID);
}
/*
* TODO: Determine whether or not any browsers cancel our request if we're called during a browser "shutdown" event,
@ -1310,9 +1310,9 @@ Computer.prototype.storeServerState = function(sUserID, sState, fSync)
*
* This handles UI requests to toggle the computer's power (eg, see the "power" button binding).
*
* @this {Computer}
* @this {Computer8080}
*/
Computer.prototype.onPower = function()
Computer8080.prototype.onPower = function()
{
if (!this.nPowerChange) {
if (!this.flags.fPowered) {
@ -1328,9 +1328,9 @@ Computer.prototype.onPower = function()
*
* This handles UI requests to reset the computer's state (eg, see the "reset" button binding).
*
* @this {Computer}
* @this {Computer8080}
*/
Computer.prototype.onReset = function()
Computer8080.prototype.onReset = function()
{
/*
* I'm going to start with the presumption that it makes little sense for an "unpowered" computer to be "reset";
@ -1349,10 +1349,10 @@ Computer.prototype.onReset = function()
*/
if (this.resume && !this.sResumePath) {
/*
* I used to bypass the prompt if this.resume == Computer.RESUME_AUTO, setting fSave to true automatically,
* I used to bypass the prompt if this.resume == Computer8080.RESUME_AUTO, setting fSave to true automatically,
* but that gives the user no means of resetting a resumable machine that contains errors in its resume state.
*/
var fSave = (/* this.resume == Computer.RESUME_AUTO || */ web.confirmUser("Click OK to save changes to this " + PC8080.APPNAME + " machine.\n\nWARNING: If you CANCEL, all disk changes will be discarded."));
var fSave = (/* this.resume == Computer8080.RESUME_AUTO || */ web.confirmUser("Click OK to save changes to this " + PC8080.APPNAME + " machine.\n\nWARNING: If you CANCEL, all disk changes will be discarded."));
this.powerOff(fSave, true);
/*
* Forcing the page to reload is an expedient option, but ugly. It's preferable to call powerOn()
@ -1371,7 +1371,7 @@ Computer.prototype.onReset = function()
return;
}
if (!fSave) this.fReload = true;
this.powerOn(Computer.RESUME_NONE);
this.powerOn(Computer8080.RESUME_NONE);
this.fReload = false;
} else {
this.reset();
@ -1382,13 +1382,14 @@ Computer.prototype.onReset = function()
/**
* getMachineComponent(sType, componentPrev)
*
* @this {Computer}
* @this {Computer8080}
* @param {string} sType
* @param {Component|null} [componentPrev] of previously returned component, if any
* @return {Component|null}
*/
Computer.prototype.getMachineComponent = function(sType, componentPrev)
Computer8080.prototype.getMachineComponent = function(sType, componentPrev)
{
var componentLast = componentPrev;
var aComponents = Component.getComponents(this.id);
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
var component = aComponents[iComponent];
@ -1398,6 +1399,7 @@ Computer.prototype.getMachineComponent = function(sType, componentPrev)
}
if (component.type == sType) return component;
}
if (!componentLast) Component.log("Machine component type '" + sType + "' not found", "warning");
return null;
};
@ -1407,10 +1409,10 @@ Computer.prototype.getMachineComponent = function(sType, componentPrev)
* NOTE: When soft keyboard buttons call us to return focus to the machine (and away from the button),
* the scroll feature has annoying effect on iOS, so we no longer do it by default (fScroll must be true).
*
* @this {Computer}
* @this {Computer8080}
* @param {boolean} [fScroll]
*/
Computer.prototype.updateFocus = function(fScroll)
Computer8080.prototype.updateFocus = function(fScroll)
{
if (this.aVideo.length) {
/*
@ -1450,10 +1452,10 @@ Computer.prototype.updateFocus = function(fScroll)
* knows the names, number, sizes, etc, of all the active registers. The Panel component is the logical candidate,
* but Panel is an optional component; generally, only machines that include Debugger also include Panel.
*
* @this {Computer}
* @this {Computer8080}
* @param {boolean} [fForce] (true will display registers even if the CPU is running and "live" registers are not enabled)
*/
Computer.prototype.updateStatus = function(fForce)
Computer8080.prototype.updateStatus = function(fForce)
{
/*
* fForce is generally set to true whenever the CPU is transitioning to/from a running state, in which case
@ -1473,10 +1475,10 @@ Computer.prototype.updateStatus = function(fForce)
*
* Any high-frequency updates should be performed here (avoid updating DOM elements).
*
* @this {Computer}
* @this {Computer8080}
* @param {number} n (where 0 <= n < VIDEO_UPDATES_PER_SECOND for a normal update, or -1 for a forced update)
*/
Computer.prototype.updateVideo = function(n)
Computer8080.prototype.updateVideo = function(n)
{
for (var i = 0; i < this.aVideo.length; i++) {
this.aVideo[i].updateScreen(n);
@ -1484,14 +1486,14 @@ Computer.prototype.updateVideo = function(n)
};
/**
* Computer.init()
* Computer8080.init()
*
* For every machine represented by an HTML element of class "pcjs-machine", this function
* locates the HTML element of class "computer", extracting the JSON-encoded parameters for the
* Computer constructor from the element's "data-value" attribute, invoking the constructor to
* create a Computer component, and then binding any associated HTML controls to the new component.
*/
Computer.init = function()
Computer8080.init = function()
{
/*
* In non-COMPILED builds, embedMachine() may have set XMLVERSION.
@ -1516,7 +1518,7 @@ Computer.init = function()
* We set fSuspended in the Computer constructor because we want to "power up" the
* computer ourselves, after any/all bindings are in place.
*/
var computer = new Computer(parmsComputer, parmsMachine, true);
var computer = new Computer8080(parmsComputer, parmsMachine, true);
if (DEBUG && computer.messageEnabled()) {
computer.printMessage("onInit(" + computer.flags.fPowered + ")");
@ -1538,7 +1540,7 @@ Computer.init = function()
};
/**
* Computer.show()
* Computer8080.show()
*
* When exit() is using an "onbeforeunload" handler, this "onpageshow" handler allows us to repower everything,
* without either resetting or restoring. We call powerOn() with a special resume value (RESUME_REPOWER) if the
@ -1546,31 +1548,36 @@ Computer.init = function()
* should be very quick, essentially just marking all components as powered again (so that, for example, the Video
* component will start drawing again) and firing the CPU up again.
*/
Computer.show = function()
Computer8080.show = function()
{
var aeComputers = Component.getElementsByClass(document, PC8080.APPCLASS, "computer");
for (var iComputer = 0; iComputer < aeComputers.length; iComputer++) {
var eComputer = aeComputers[iComputer];
var parmsComputer = Component.getComponentParms(eComputer);
var computer = /** @type {Computer} */ (Component.getComponentByType("Computer", parmsComputer['id']));
var computer = /** @type {Computer8080} */ (Component.getComponentByType("Computer", parmsComputer['id']));
if (computer) {
if (DEBUG && computer.messageEnabled()) {
computer.printMessage("onShow(" + computer.fInitialized + "," + computer.flags.fPowered + ")");
}
/*
* Note that the FIRST 'onpageshow' event, and therefore the first show() callback, occurs
* AFTER the the initial 'onload' event, and at that point in time, fInitialized will not be set yet.
* So, practically speaking, the first show() callback isn't all that useful.
*/
if (computer.fInitialized && !computer.flags.fPowered) {
/**
* Repower the computer, notifying every component to continue running as-is.
*/
computer.powerOn(Computer.RESUME_REPOWER);
computer.powerOn(Computer8080.RESUME_REPOWER);
}
}
}
};
/**
* Computer.exit()
* Computer8080.exit()
*
* The Computer is currently the only component that uses an "exit" handler, which web.onExit() defines as
* either an "unload" or "onbeforeunload" handler. This gives us the opportunity to save the machine state,
@ -1586,7 +1593,7 @@ Computer.show = function()
* presence of an "onunload" handler generally causes a browser to throw the page away once the handler returns.
*
* However, in order to safely use "onbeforeunload", we must add yet another handler ("onpageshow") to repower
* everything, without either resetting or restoring. Hence, the Computer.show() function, which calls powerOn()
* everything, without either resetting or restoring. Hence, the Computer8080.show() function, which calls powerOn()
* with a special resume value (RESUME_REPOWER) if the computer is already marked as "ready", meaning the browser
* didn't change anything. This "repower" process should be very quick, essentially just marking all components as
* powered again (so that, for example, the Video component will start drawing again) and firing the CPU up again.
@ -1595,13 +1602,13 @@ Computer.show = function()
* "unload" instead. But even when the page must be rebuilt from scratch, the combination of browser cache and
* localStorage means the simulation should be restored and become operational almost immediately.
*/
Computer.exit = function()
Computer8080.exit = function()
{
var aeComputers = Component.getElementsByClass(document, PC8080.APPCLASS, "computer");
for (var iComputer = 0; iComputer < aeComputers.length; iComputer++) {
var eComputer = aeComputers[iComputer];
var parmsComputer = Component.getComponentParms(eComputer);
var computer = /** @type {Computer} */ (Component.getComponentByType("Computer", parmsComputer['id']));
var computer = /** @type {Computer8080} */ (Component.getComponentByType("Computer", parmsComputer['id']));
if (computer) {
if (DEBUG && computer.messageEnabled()) {
@ -1623,8 +1630,8 @@ Computer.exit = function()
/*
* Initialize every Computer on the page.
*/
web.onInit(Computer.init);
web.onShow(Computer.show);
web.onExit(Computer.exit);
web.onInit(Computer8080.init);
web.onShow(Computer8080.show);
web.onExit(Computer8080.exit);
if (NODE) module.exports = Computer;
if (NODE) module.exports = Computer8080;

View file

@ -35,15 +35,15 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var Messages8080= require("./messages");
}
/**
* CPU(parmsCPU, nCyclesDefault)
* CPU8080(parmsCPU, nCyclesDefault)
*
* The CPU class supports the following (parmsCPU) properties:
* The CPU8080 class supports the following (parmsCPU) properties:
*
* cycles: the machine's base cycles per second; the CPUState constructor will
* cycles: the machine's base cycles per second; the CPUState8080 constructor will
* provide us with a default (based on the CPU model) to use as a fallback.
*
* multiplier: base cycle multiplier; default is 1.
@ -64,16 +64,16 @@ if (NODE) {
* This component is primarily responsible for interfacing the CPU with the outside
* world (eg, Panel and Debugger components), and managing overall CPU operation.
*
* It is extended by the CPUState component, where the simulation control logic resides.
* It is extended by the CPUState8080 component, where the simulation control logic resides.
*
* @constructor
* @extends Component
* @param {Object} parmsCPU
* @param {number} nCyclesDefault
*/
function CPU(parmsCPU, nCyclesDefault)
function CPU8080(parmsCPU, nCyclesDefault)
{
Component.call(this, "CPU", parmsCPU, CPU, Messages.CPU);
Component.call(this, "CPU", parmsCPU, CPU8080, Messages8080.CPU);
var nCycles = parmsCPU['cycles'] || nCyclesDefault;
@ -132,7 +132,7 @@ function CPU(parmsCPU, nCyclesDefault)
this.setReady();
}
Component.subclass(CPU);
Component.subclass(CPU8080);
/*
* Constants that control the frequency at which various updates should occur.
@ -141,9 +141,9 @@ Component.subclass(CPU);
* calcCycles(), which uses the nCyclesPerSecond passed to the constructor as a starting
* point and computes the following variables:
*
* this.aCounts.nCyclesPerYield (this.aCounts.nCyclesPerSecond / CPU.YIELDS_PER_SECOND)
* this.aCounts.nCyclesPerVideoUpdate (this.aCounts.nCyclesPerSecond / CPU.VIDEO_UPDATES_PER_SECOND)
* this.aCounts.nCyclesPerStatusUpdate (this.aCounts.nCyclesPerSecond / CPU.STATUS_UPDATES_PER_SECOND)
* this.aCounts.nCyclesPerYield (this.aCounts.nCyclesPerSecond / CPU8080.YIELDS_PER_SECOND)
* this.aCounts.nCyclesPerVideoUpdate (this.aCounts.nCyclesPerSecond / CPU8080.VIDEO_UPDATES_PER_SECOND)
* this.aCounts.nCyclesPerStatusUpdate (this.aCounts.nCyclesPerSecond / CPU8080.STATUS_UPDATES_PER_SECOND)
*
* The above variables are also multiplied by any cycle multiplier in effect, via setSpeed(),
* and then they're used to initialize another set of variables for each runCPU() iteration:
@ -152,42 +152,42 @@ Component.subclass(CPU);
* this.aCounts.nCyclesNextVideoUpdate <= this.aCounts.nCyclesPerVideoUpdate
* this.aCounts.nCyclesNextStatusUpdate <= this.aCounts.nCyclesPerStatusUpdate
*/
CPU.YIELDS_PER_SECOND = 30;
CPU.VIDEO_UPDATES_PER_SECOND = 60;
CPU.STATUS_UPDATES_PER_SECOND = 2;
CPU8080.YIELDS_PER_SECOND = 30;
CPU8080.VIDEO_UPDATES_PER_SECOND = 60;
CPU8080.STATUS_UPDATES_PER_SECOND = 2;
CPU.BUTTONS = ["power", "reset"];
CPU8080.BUTTONS = ["power", "reset"];
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {CPU}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPU} cpu
* @param {Debugger} dbg
* @this {CPU8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPU8080} cpu
* @param {Debugger8080} dbg
*/
CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
CPU8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.bus = bus;
this.dbg = dbg;
for (var i = 0; i < CPU.BUTTONS.length; i++) {
var control = this.bindings[CPU.BUTTONS[i]];
if (control) this.cmp.setBinding(null, CPU.BUTTONS[i], control);
for (var i = 0; i < CPU8080.BUTTONS.length; i++) {
var control = this.bindings[CPU8080.BUTTONS[i]];
if (control) this.cmp.setBinding(null, CPU8080.BUTTONS[i], control);
}
/*
* We need to know the refresh rate (and corresponding interrupt rate, if any) of the Video component.
*/
var video = /** @type {Video} */ (cmp.getMachineComponent("Video"));
this.refreshRate = video && video.getRefreshRate() || CPU.VIDEO_UPDATES_PER_SECOND;
var video = /** @type {Video8080} */ (cmp.getMachineComponent("Video"));
this.refreshRate = video && video.getRefreshRate() || CPU8080.VIDEO_UPDATES_PER_SECOND;
/*
* Attach the ChipSet component to the CPU so that it can be notified whenever the CPU stops and starts.
*/
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
this.chipset = /** @type {ChipSet8080} */ (cmp.getMachineComponent("ChipSet"));
/*
* We've already saved the parmsCPU 'autoStart' setting, but there may be a machine (or URL) override.
@ -203,9 +203,9 @@ CPU.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* reset()
*
* @this {CPU}
* @this {CPU8080}
*/
CPU.prototype.reset = function()
CPU8080.prototype.reset = function()
{
this.aCounts.nVideoUpdates = 0;
};
@ -215,10 +215,10 @@ CPU.prototype.reset = function()
*
* This is a placeholder for save support (overridden by the CPUState component).
*
* @this {CPU}
* @this {CPU8080}
* @return {Object|null}
*/
CPU.prototype.save = function()
CPU8080.prototype.save = function()
{
return null;
};
@ -228,11 +228,11 @@ CPU.prototype.save = function()
*
* This is a placeholder for restore support (overridden by the CPUState component).
*
* @this {CPU}
* @this {CPU8080}
* @param {Object} data
* @return {boolean} true if restore successful, false if not
*/
CPU.prototype.restore = function(data)
CPU8080.prototype.restore = function(data)
{
return false;
};
@ -240,12 +240,12 @@ CPU.prototype.restore = function(data)
/**
* powerUp(data, fRepower)
*
* @this {CPU}
* @this {CPU8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
CPU.prototype.powerUp = function(data, fRepower)
CPU8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
if (!data || !this.restore) {
@ -286,12 +286,12 @@ CPU.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave, fShutdown)
*
* @this {CPU}
* @this {CPU8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
CPU.prototype.powerDown = function(fSave, fShutdown)
CPU8080.prototype.powerDown = function(fSave, fShutdown)
{
/*
* The Computer component (which is responsible for all powerDown and powerUp notifications)
@ -305,10 +305,10 @@ CPU.prototype.powerDown = function(fSave, fShutdown)
/**
* autoStart()
*
* @this {CPU}
* @this {CPU8080}
* @return {boolean} true if started, false if not
*/
CPU.prototype.autoStart = function()
CPU8080.prototype.autoStart = function()
{
/*
* Start running automatically on power-up, assuming there's no Debugger and no "Run" button
@ -327,10 +327,10 @@ CPU.prototype.autoStart = function()
/**
* isPowered()
*
* @this {CPU}
* @this {CPU8080}
* @return {boolean}
*/
CPU.prototype.isPowered = function()
CPU8080.prototype.isPowered = function()
{
if (!this.flags.fPowered) {
this.println(this.toString() + " not powered");
@ -342,10 +342,10 @@ CPU.prototype.isPowered = function()
/**
* isRunning()
*
* @this {CPU}
* @this {CPU8080}
* @return {boolean}
*/
CPU.prototype.isRunning = function()
CPU8080.prototype.isRunning = function()
{
return this.flags.fRunning;
};
@ -355,10 +355,10 @@ CPU.prototype.isRunning = function()
*
* This will be implemented by the CPUState component.
*
* @this {CPU}
* @this {CPU8080}
* @return {number} a 32-bit summation of key elements of the current CPU state (used by the CPU checksum code)
*/
CPU.prototype.getChecksum = function()
CPU8080.prototype.getChecksum = function()
{
return 0;
};
@ -370,10 +370,10 @@ CPU.prototype.getChecksum = function()
* cycle counter that will trigger the next displayChecksum(); called by resetCycles(), which is called whenever
* the CPU is reset or restored.
*
* @this {CPU}
* @this {CPU8080}
* @return {boolean} true if checksum generation enabled, false if not
*/
CPU.prototype.resetChecksum = function()
CPU8080.prototype.resetChecksum = function()
{
if (this.aCounts.nCyclesChecksumStart === undefined) this.aCounts.nCyclesChecksumStart = 0;
if (this.aCounts.nCyclesChecksumInterval === undefined) this.aCounts.nCyclesChecksumInterval = -1;
@ -399,10 +399,10 @@ CPU.prototype.resetChecksum = function()
* the exact number cycles that were actually executed. This should give us instruction-granular checksums
* at precise intervals that are 100% repeatable.
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nCycles
*/
CPU.prototype.updateChecksum = function(nCycles)
CPU8080.prototype.updateChecksum = function(nCycles)
{
if (this.flags.fChecksum) {
/*
@ -434,9 +434,9 @@ CPU.prototype.updateChecksum = function(nCycles)
* checksums generated at the specified cycle intervals, as specified by the "csStart" and "csInterval" parmsCPU
* properties).
*
* @this {CPU}
* @this {CPU8080}
*/
CPU.prototype.displayChecksum = function()
CPU8080.prototype.displayChecksum = function()
{
this.println(this.getCycles() + " cycles: " + "checksum=" + str.toHex(this.aCounts.nChecksum));
};
@ -447,12 +447,12 @@ CPU.prototype.displayChecksum = function()
* This is principally for displaying register values, but in reality, it can be used to display any
* numeric (hex) value bound to the given label.
*
* @this {CPU}
* @this {CPU8080}
* @param {string} sLabel
* @param {number} nValue
* @param {number} cch
*/
CPU.prototype.displayValue = function(sLabel, nValue, cch)
CPU8080.prototype.displayValue = function(sLabel, nValue, cch)
{
if (this.bindings[sLabel]) {
if (nValue === undefined) {
@ -478,14 +478,14 @@ CPU.prototype.displayValue = function(sLabel, nValue, cch)
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {CPU}
* @this {CPU8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "run")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
CPU.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
CPU8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
var cpu = this;
var fBound = false;
@ -544,11 +544,11 @@ CPU.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
* NOTE: In this context, "timer" refers to a timer chip (eg, an Intel 8253) being emulated by
* by the ChipSet component, not the timers managed by the CPU (eg, addTimer(), setTimer(), etc).
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nCycles is the target number of cycles to drop the current burst to
* @return {boolean}
*/
CPU.prototype.setBurstCycles = function(nCycles)
CPU8080.prototype.setBurstCycles = function(nCycles)
{
if (this.flags.fRunning) {
var nDelta = this.nStepCycles - nCycles;
@ -571,11 +571,11 @@ CPU.prototype.setBurstCycles = function(nCycles)
/**
* addCycles(nCycles, fEndStep)
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nCycles
* @param {boolean} [fEndStep]
*/
CPU.prototype.addCycles = function(nCycles, fEndStep)
CPU8080.prototype.addCycles = function(nCycles, fEndStep)
{
this.nTotalCycles += nCycles;
if (fEndStep) {
@ -589,9 +589,9 @@ CPU.prototype.addCycles = function(nCycles, fEndStep)
* Calculate the number of cycles to process for each "burst" of CPU activity. The size of a burst
* is driven by the following values:
*
* CPU.YIELDS_PER_SECOND (eg, 30)
* CPU.VIDEO_UPDATES_PER_SECOND (eg, 60)
* CPU.STATUS_UPDATES_PER_SECOND (eg, 5)
* CPU8080.YIELDS_PER_SECOND (eg, 30)
* CPU8080.VIDEO_UPDATES_PER_SECOND (eg, 60)
* CPU8080.STATUS_UPDATES_PER_SECOND (eg, 5)
*
* The largest of the above values forces the size of the burst to its smallest value. Let's say that
* largest value is 30. Assuming nCyclesPerSecond is 1,000,000, that results in bursts of 33,333 cycles.
@ -604,18 +604,18 @@ CPU.prototype.addCycles = function(nCycles, fEndStep)
* Similarly, whenever the "next video update" cycle counter goes to (or below) zero, we call updateVideo(),
* and whenever the "next status update" cycle counter goes to (or below) zero, we call updateStatus().
*
* @this {CPU}
* @this {CPU8080}
* @param {boolean} [fRecalc] is true if the caller wants to recalculate thresholds based on the most recent
* speed calculation (see calcSpeed).
*/
CPU.prototype.calcCycles = function(fRecalc)
CPU8080.prototype.calcCycles = function(fRecalc)
{
/*
* Calculate the most cycles we're allowed to execute in a single "burst"
*/
var nMostUpdatesPerSecond = CPU.YIELDS_PER_SECOND;
var nMostUpdatesPerSecond = CPU8080.YIELDS_PER_SECOND;
if (nMostUpdatesPerSecond < this.refreshRate) nMostUpdatesPerSecond = this.refreshRate;
if (nMostUpdatesPerSecond < CPU.STATUS_UPDATES_PER_SECOND) nMostUpdatesPerSecond = CPU.STATUS_UPDATES_PER_SECOND;
if (nMostUpdatesPerSecond < CPU8080.STATUS_UPDATES_PER_SECOND) nMostUpdatesPerSecond = CPU8080.STATUS_UPDATES_PER_SECOND;
/*
* Calculate cycle "per" values for the yield, video update, and status update cycle counters
@ -627,11 +627,11 @@ CPU.prototype.calcCycles = function(fRecalc)
}
}
this.aCounts.msPerYield = Math.round(1000 / CPU.YIELDS_PER_SECOND);
this.aCounts.msPerYield = Math.round(1000 / CPU8080.YIELDS_PER_SECOND);
this.aCounts.nCyclesPerBurst = Math.floor(this.aCounts.nCyclesPerSecond / nMostUpdatesPerSecond * vMultiplier);
this.aCounts.nCyclesPerYield = Math.floor(this.aCounts.nCyclesPerSecond / CPU.YIELDS_PER_SECOND * vMultiplier);
this.aCounts.nCyclesPerYield = Math.floor(this.aCounts.nCyclesPerSecond / CPU8080.YIELDS_PER_SECOND * vMultiplier);
this.aCounts.nCyclesPerVideoUpdate = Math.floor(this.aCounts.nCyclesPerSecond / this.refreshRate * vMultiplier);
this.aCounts.nCyclesPerStatusUpdate = Math.floor(this.aCounts.nCyclesPerSecond / CPU.STATUS_UPDATES_PER_SECOND * vMultiplier);
this.aCounts.nCyclesPerStatusUpdate = Math.floor(this.aCounts.nCyclesPerSecond / CPU8080.STATUS_UPDATES_PER_SECOND * vMultiplier);
/*
* And initialize "next" yield, video update, and status update cycle "threshold" counters to those "per" values
@ -657,11 +657,11 @@ CPU.prototype.calcCycles = function(fRecalc)
* nTotalCycles eventually get reset by calcSpeed(), to avoid overflow, so components that rely on
* getCycles() returning steadily increasing values should also be prepared for a reset at any time.
*
* @this {CPU}
* @this {CPU8080}
* @param {boolean} [fScaled] is true if the caller wants a cycle count relative to a multiplier of 1
* @return {number}
*/
CPU.prototype.getCycles = function(fScaled)
CPU8080.prototype.getCycles = function(fScaled)
{
var nCycles = this.nTotalCycles + this.nRunCycles + this.nBurstCycles - this.nStepCycles;
if (fScaled && this.aCounts.nCyclesMultiplier > 1 && this.aCounts.mhz > this.aCounts.mhzDefault) {
@ -693,10 +693,10 @@ CPU.prototype.getCycles = function(fScaled)
*
* This returns the CPU's "base" speed (ie, the original cycles per second defined for the machine)
*
* @this {CPU}
* @this {CPU8080}
* @return {number}
*/
CPU.prototype.getCyclesPerSecond = function()
CPU8080.prototype.getCyclesPerSecond = function()
{
return this.aCounts.nCyclesPerSecond;
};
@ -708,9 +708,9 @@ CPU.prototype.getCyclesPerSecond = function()
* It's important that this be called BEFORE the actual restore() call, because restore() may want to call setSpeed(),
* which in turn assumes that all the cycle counts have been initialized to sensible values.
*
* @this {CPU}
* @this {CPU8080}
*/
CPU.prototype.resetCycles = function()
CPU8080.prototype.resetCycles = function()
{
this.aCounts.mhz = 0;
this.nTotalCycles = this.nRunCycles = this.nBurstCycles = this.nStepCycles = 0;
@ -721,10 +721,10 @@ CPU.prototype.resetCycles = function()
/**
* getSpeed()
*
* @this {CPU}
* @this {CPU8080}
* @return {number} the current speed multiplier
*/
CPU.prototype.getSpeed = function()
CPU8080.prototype.getSpeed = function()
{
return this.aCounts.nCyclesMultiplier;
};
@ -732,10 +732,10 @@ CPU.prototype.getSpeed = function()
/**
* getSpeedCurrent()
*
* @this {CPU}
* @this {CPU8080}
* @return {string} the current speed, in mhz, as a string formatted to two decimal places
*/
CPU.prototype.getSpeedCurrent = function()
CPU8080.prototype.getSpeedCurrent = function()
{
/*
* TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
@ -746,10 +746,10 @@ CPU.prototype.getSpeedCurrent = function()
/**
* getSpeedTarget()
*
* @this {CPU}
* @this {CPU8080}
* @return {string} the target speed, in mhz, as a string formatted to two decimal places
*/
CPU.prototype.getSpeedTarget = function()
CPU8080.prototype.getSpeedTarget = function()
{
/*
* TODO: Has toFixed() been "fixed" in all browsers (eg, IE) to return a rounded value now?
@ -766,12 +766,12 @@ CPU.prototype.getSpeedTarget = function()
* so that the next effective speed calculation obtains sensible results. In fact, when runCPU() initially calls
* setSpeed() with no parameters, that's all this function does (it doesn't change the current speed setting).
*
* @this {CPU}
* @this {CPU8080}
* @param {number} [nMultiplier] is the new proposed multiplier (reverts to 1 if the target was too high)
* @param {boolean} [fUpdateFocus] is true to update Computer focus
* @return {boolean} true if successful, false if not
*/
CPU.prototype.setSpeed = function(nMultiplier, fUpdateFocus)
CPU8080.prototype.setSpeed = function(nMultiplier, fUpdateFocus)
{
var fSuccess = false;
if (nMultiplier !== undefined) {
@ -805,11 +805,11 @@ CPU.prototype.setSpeed = function(nMultiplier, fUpdateFocus)
/**
* calcSpeed(nCycles, msElapsed)
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nCycles
* @param {number} msElapsed
*/
CPU.prototype.calcSpeed = function(nCycles, msElapsed)
CPU8080.prototype.calcSpeed = function(nCycles, msElapsed)
{
if (msElapsed) {
this.aCounts.mhz = Math.round(nCycles / (msElapsed * 10)) / 100;
@ -823,9 +823,9 @@ CPU.prototype.calcSpeed = function(nCycles, msElapsed)
/**
* calcStartTime()
*
* @this {CPU}
* @this {CPU8080}
*/
CPU.prototype.calcStartTime = function()
CPU8080.prototype.calcStartTime = function()
{
if (this.aCounts.nCyclesRecalc >= this.aCounts.nCyclesPerSecond) {
this.calcCycles(true);
@ -879,10 +879,10 @@ CPU.prototype.calcStartTime = function()
/**
* calcRemainingTime()
*
* @this {CPU}
* @this {CPU8080}
* @return {number}
*/
CPU.prototype.calcRemainingTime = function()
CPU8080.prototype.calcRemainingTime = function()
{
this.aCounts.msEndThisRun = usr.getTime();
@ -939,7 +939,7 @@ CPU.prototype.calcRemainingTime = function()
*/
this.aCounts.nCyclesRecalc += this.aCounts.nCyclesThisRun;
if (DEBUG && this.messageEnabled(Messages.LOG) && msRemainsThisRun) {
if (DEBUG && this.messageEnabled(Messages8080.LOG) && msRemainsThisRun) {
this.log("calcRemainingTime: " + msRemainsThisRun + "ms to sleep after " + this.aCounts.msEndThisRun + "ms");
}
@ -960,11 +960,11 @@ CPU.prototype.calcRemainingTime = function()
*
* Why not use JavaScript's setTimeout() instead? Good question. For a good answer, see setTimer() below.
*
* @this {CPU}
* @this {CPU8080}
* @param {function()} callBack
* @return {number} timer index
*/
CPU.prototype.addTimer = function(callBack)
CPU8080.prototype.addTimer = function(callBack)
{
var iTimer = this.aTimers.length;
this.aTimers.push([-1, callBack]);
@ -986,12 +986,12 @@ CPU.prototype.addTimer = function(callBack)
* use setTimer(); however, due to legacy code (ie, code that predates these functions) and/or laziness,
* that's currently not the case. TODO: Fix.
*
* @this {CPU}
* @this {CPU8080}
* @param {number} iTimer
* @param {number} ms (converted into a cycle countdown internally)
* @return {number} (number of cycles used to arm timer, or -1 if error)
*/
CPU.prototype.setTimer = function(iTimer, ms)
CPU8080.prototype.setTimer = function(iTimer, ms)
{
var nCycles = -1;
if (iTimer >= 0 && iTimer < this.aTimers.length) {
@ -1006,11 +1006,11 @@ CPU.prototype.setTimer = function(iTimer, ms)
*
* Used by runCPU() to either accept or shorten the current burst if any timers need to fire soon.
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nCycles (number of cycles about to execute)
* @return {number} (either nCycles or less if a timer needs to fire)
*/
CPU.prototype.getTimerBurst = function(nCycles)
CPU8080.prototype.getTimerBurst = function(nCycles)
{
for (var i = 0; i < this.aTimers.length; i++) {
var timer = this.aTimers[i];
@ -1029,10 +1029,10 @@ CPU.prototype.getTimerBurst = function(nCycles)
* this is the function that actually "fires" any timer(s) whose countdown has reached (or dropped below)
* zero, invoking their callback function.
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nCycles (number of cycles actually executed)
*/
CPU.prototype.updateTimers = function(nCycles)
CPU8080.prototype.updateTimers = function(nCycles)
{
for (var i = 0; i < this.aTimers.length; i++) {
var timer = this.aTimers[i];
@ -1048,10 +1048,10 @@ CPU.prototype.updateTimers = function(nCycles)
/**
* runCPU(fUpdateFocus)
*
* @this {CPU}
* @this {CPU8080}
* @param {boolean} [fUpdateFocus] is true to update Computer focus
*/
CPU.prototype.runCPU = function(fUpdateFocus)
CPU8080.prototype.runCPU = function(fUpdateFocus)
{
if (!this.setBusy(true)) {
this.updateCPU();
@ -1140,7 +1140,7 @@ CPU.prototype.runCPU = function(fUpdateFocus)
*
* @param {boolean} [fUpdateFocus]
*/
CPU.prototype.startCPU = function(fUpdateFocus)
CPU8080.prototype.startCPU = function(fUpdateFocus)
{
if (!this.flags.fRunning) {
/*
@ -1168,11 +1168,11 @@ CPU.prototype.startCPU = function(fUpdateFocus)
*
* This will be implemented by the CPUState component.
*
* @this {CPU}
* @this {CPU8080}
* @param {number} nMinCycles (0 implies a single-step, and therefore breakpoints should be ignored)
* @return {number} of cycles executed; 0 indicates that the last instruction was not executed
*/
CPU.prototype.stepCPU = function(nMinCycles)
CPU8080.prototype.stepCPU = function(nMinCycles)
{
return 0;
};
@ -1185,10 +1185,10 @@ CPU.prototype.stepCPU = function(nMinCycles)
* This similar to yieldCPU(), but it doesn't need to zero nCyclesNextYield to break out of runCPU();
* it simply needs to clear fRunning (well, "simply" may be oversimplifying a bit....)
*
* @this {CPU}
* @this {CPU8080}
* @param {boolean} [fComplete]
*/
CPU.prototype.stopCPU = function(fComplete)
CPU8080.prototype.stopCPU = function(fComplete)
{
this.isBusy(true);
this.nBurstCycles -= this.nStepCycles;
@ -1212,10 +1212,10 @@ CPU.prototype.stopCPU = function(fComplete)
* other callers of stepCPU(), such as the Debugger, the combination of stepCPU() + updateCPU()
* provides the old behavior.
*
* @this {CPU}
* @this {CPU8080}
* @param {boolean} [fForce] (true to force a video update; used by the Debugger)
*/
CPU.prototype.updateCPU = function(fForce)
CPU8080.prototype.updateCPU = function(fForce)
{
if (this.cmp) {
this.cmp.updateVideo(-1);
@ -1229,9 +1229,9 @@ CPU.prototype.updateCPU = function(fForce)
* Similar to stopCPU() with regard to how it resets various cycle countdown values, but the CPU
* remains in a "running" state.
*
* @this {CPU}
* @this {CPU8080}
*/
CPU.prototype.yieldCPU = function()
CPU8080.prototype.yieldCPU = function()
{
this.aCounts.nCyclesNextYield = 0; // this will break us out of runCPU(), once we break out of stepCPU()
this.nBurstCycles -= this.nStepCycles;
@ -1245,4 +1245,4 @@ CPU.prototype.yieldCPU = function()
this.updateCPU();
};
if (NODE) module.exports = CPU;
if (NODE) module.exports = CPU8080;

View file

@ -31,7 +31,7 @@
"use strict";
var CPUDef = {
var CPUDef8080 = {
/*
* CPU model numbers (supported)
*/
@ -114,17 +114,17 @@ var CPUDef = {
* These are the internal PS bits (outside of PS.MASK) that getPS() and setPS() can get and set,
* but which cannot be seen with any of the documented instructions.
*/
CPUDef.PS.INTERNAL = (CPUDef.PS.IF);
CPUDef8080.PS.INTERNAL = (CPUDef8080.PS.IF);
/*
* PS "arithmetic" flags are NOT stored in regPS; they are maintained across separate result registers,
* hence the RESULT designation.
*/
CPUDef.PS.RESULT = (CPUDef.PS.CF | CPUDef.PS.PF | CPUDef.PS.AF | CPUDef.PS.ZF | CPUDef.PS.SF);
CPUDef8080.PS.RESULT = (CPUDef8080.PS.CF | CPUDef8080.PS.PF | CPUDef8080.PS.AF | CPUDef8080.PS.ZF | CPUDef8080.PS.SF);
/*
* These are the "always set" PS bits for the 8080.
*/
CPUDef.PS.SET = (CPUDef.PS.BIT1);
CPUDef8080.PS.SET = (CPUDef8080.PS.BIT1);
if (NODE) module.exports = CPUDef;
if (NODE) module.exports = CPUDef8080;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -68,7 +68,7 @@ var BYTEARRAYS = false;
/**
* TYPEDARRAYS enables use of typed arrays for Memory blocks. This used to be a compile-time-only option, but I've
* added Memory access functions for typed arrays (see Memory.afnTypedArray), so support can be enabled dynamically now.
* added Memory access functions for typed arrays (see Memory8080.afnTypedArray), so support can be enabled dynamically now.
*
* See the Memory component for details.
*/
@ -101,7 +101,6 @@ if (NODE) {
global.BYTEARRAYS = BYTEARRAYS;
global.TYPEDARRAYS = TYPEDARRAYS;
global.PC8080 = PC8080;
/*
* TODO: When we're "required" by Node, should we return anything via module.exports?
*/
module.exports = PC8080;
}

View file

@ -35,39 +35,39 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var ChipSet8080 = require("./chipset");
var Messages8080= require("./messages");
}
/**
* Keyboard(parmsKbd)
* Keyboard8080(parmsKbd)
*
* The Keyboard component has the following component-specific (parmsKbd) properties:
* The Keyboard8080 component has the following component-specific (parmsKbd) properties:
*
* model: eg, "VT100" (should be a member of Keyboard.MODELS)
* model: eg, "VT100" (should be a member of Keyboard8080.MODELS)
*
* @constructor
* @extends Component
* @param {Object} parmsKbd
*/
function Keyboard(parmsKbd)
function Keyboard8080(parmsKbd)
{
Component.call(this, "Keyboard", parmsKbd, Keyboard, Messages.KEYBOARD);
Component.call(this, "Keyboard", parmsKbd, Keyboard8080, Messages8080.KEYBOARD);
var model = parmsKbd['model'];
if (model && !Keyboard.MODELS[model]) {
Component.notice("Unrecognized Keyboard model: " + model);
if (model && !Keyboard8080.MODELS[model]) {
Component.notice("Unrecognized Keyboard8080 model: " + model);
}
this.config = Keyboard.MODELS[model] || {};
this.config = Keyboard8080.MODELS[model] || {};
this.reset();
this.setReady();
}
Component.subclass(Keyboard);
Component.subclass(Keyboard8080);
/**
* Alphanumeric and other common (printable) ASCII codes.
@ -78,7 +78,7 @@ Component.subclass(Keyboard);
*
* @enum {number}
*/
Keyboard.ASCII = {
Keyboard8080.ASCII = {
CTRL_A: 1, CTRL_C: 3, CTRL_Z: 26,
' ': 32, '!': 33, '"': 34, '#': 35, '$': 36, '%': 37, '&': 38, "'": 39,
'(': 40, ')': 41, '*': 42, '+': 43, ',': 44, '-': 45, '.': 46, '/': 47,
@ -106,7 +106,7 @@ Keyboard.ASCII = {
*
* @enum {number}
*/
Keyboard.KEYCODE = {
Keyboard8080.KEYCODE = {
/* 0x08 */ BS: 8,
/* 0x09 */ TAB: 9,
/* 0x0A */ LF: 10, // TODO: Determine if any key actually generates this (I suspect there is none)
@ -227,26 +227,26 @@ Keyboard.KEYCODE = {
/*
* Check the event object's 'location' property for a non-zero value for the following ONRIGHT keys.
*/
Keyboard.KEYCODE.NUM_CR = Keyboard.KEYCODE.CR + Keyboard.KEYCODE.ONRIGHT;
Keyboard8080.KEYCODE.NUM_CR = Keyboard8080.KEYCODE.CR + Keyboard8080.KEYCODE.ONRIGHT;
/*
* Maps "stupid" keyCodes to their "non-stupid" counterparts
*/
Keyboard.STUPID_KEYCODES = {};
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.SEMI] = Keyboard.ASCII[';']; // 186 -> 59
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.EQUALS] = Keyboard.ASCII['=']; // 187 -> 61
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.COMMA] = Keyboard.ASCII[',']; // 188 -> 44
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.DASH] = Keyboard.ASCII['-']; // 189 -> 45
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.PERIOD] = Keyboard.ASCII['.']; // 190 -> 46
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.SLASH] = Keyboard.ASCII['/']; // 191 -> 47
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.BQUOTE] = Keyboard.ASCII['`']; // 192 -> 96
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.LBRACK] = Keyboard.ASCII['[']; // 219 -> 91
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.BSLASH] = Keyboard.ASCII['\\']; // 220 -> 92
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.RBRACK] = Keyboard.ASCII[']']; // 221 -> 93
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.QUOTE] = Keyboard.ASCII["'"]; // 222 -> 39
Keyboard.STUPID_KEYCODES[Keyboard.KEYCODE.FF_DASH] = Keyboard.ASCII['-'];
Keyboard8080.STUPID_KEYCODES = {};
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.SEMI] = Keyboard8080.ASCII[';']; // 186 -> 59
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.EQUALS] = Keyboard8080.ASCII['=']; // 187 -> 61
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.COMMA] = Keyboard8080.ASCII[',']; // 188 -> 44
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.DASH] = Keyboard8080.ASCII['-']; // 189 -> 45
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.PERIOD] = Keyboard8080.ASCII['.']; // 190 -> 46
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.SLASH] = Keyboard8080.ASCII['/']; // 191 -> 47
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.BQUOTE] = Keyboard8080.ASCII['`']; // 192 -> 96
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.LBRACK] = Keyboard8080.ASCII['[']; // 219 -> 91
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.BSLASH] = Keyboard8080.ASCII['\\']; // 220 -> 92
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.RBRACK] = Keyboard8080.ASCII[']']; // 221 -> 93
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.QUOTE] = Keyboard8080.ASCII["'"]; // 222 -> 39
Keyboard8080.STUPID_KEYCODES[Keyboard8080.KEYCODE.FF_DASH] = Keyboard8080.ASCII['-'];
Keyboard.MINPRESSTIME = 100; // 100ms
Keyboard8080.MINPRESSTIME = 100; // 100ms
/**
* Alternate keyCode mappings to support popular "WASD"-style directional-key mappings.
@ -254,36 +254,36 @@ Keyboard.MINPRESSTIME = 100; // 100ms
* TODO: ES6 computed property name support may now be in all mainstream browsers, allowing us to use
* a simple object literal for this and all other object initializations.
*/
Keyboard.WASDCODES = {};
Keyboard.WASDCODES[Keyboard.ASCII.A] = Keyboard.KEYCODE.LEFT;
Keyboard.WASDCODES[Keyboard.ASCII.D] = Keyboard.KEYCODE.RIGHT;
Keyboard.WASDCODES[Keyboard.ASCII.L] = Keyboard.KEYCODE.SPACE;
Keyboard8080.WASDCODES = {};
Keyboard8080.WASDCODES[Keyboard8080.ASCII.A] = Keyboard8080.KEYCODE.LEFT;
Keyboard8080.WASDCODES[Keyboard8080.ASCII.D] = Keyboard8080.KEYCODE.RIGHT;
Keyboard8080.WASDCODES[Keyboard8080.ASCII.L] = Keyboard8080.KEYCODE.SPACE;
/*
* Supported configurations
*/
Keyboard.SI1978 = {
Keyboard8080.SI1978 = {
MODEL: 1978.1,
KEYMAP: {},
ALTCODES: Keyboard.WASDCODES,
ALTCODES: Keyboard8080.WASDCODES,
LEDCODES: {},
SOFTCODES: {
'1p': Keyboard.KEYCODE.ONE,
'2p': Keyboard.KEYCODE.TWO,
'coin': Keyboard.KEYCODE.THREE,
'left': Keyboard.KEYCODE.LEFT,
'right': Keyboard.KEYCODE.RIGHT,
'fire': Keyboard.KEYCODE.SPACE
'1p': Keyboard8080.KEYCODE.ONE,
'2p': Keyboard8080.KEYCODE.TWO,
'coin': Keyboard8080.KEYCODE.THREE,
'left': Keyboard8080.KEYCODE.LEFT,
'right': Keyboard8080.KEYCODE.RIGHT,
'fire': Keyboard8080.KEYCODE.SPACE
}
};
Keyboard.VT100 = {
Keyboard8080.VT100 = {
MODEL: 100.0,
KEYMAP: {},
ALTCODES: {},
LEDCODES: {},
SOFTCODES: {
'setup': Keyboard.KEYCODE.F9
'setup': Keyboard8080.KEYCODE.F9
},
/*
* Reading port 0x82 returns a key address from the VT100 keyboard's UART data output.
@ -328,119 +328,119 @@ Keyboard.VT100 = {
/*
* Table to map host key codes to VT100 key addresses (ie, unique 7-bit values representing key positions on the VT100)
*/
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.DEL] = 0x03;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.P] = 0x05;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.O] = 0x06;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.Y] = 0x07;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.T] = 0x08;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.W] = 0x09;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.Q] = 0x0A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.RIGHT] = 0x10;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.RBRACK] = 0x14;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.LBRACK] = 0x15;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.I] = 0x16;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.U] = 0x17;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.R] = 0x18;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.E] = 0x19;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.ONE] = 0x1A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.LEFT] = 0x20;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.DOWN] = 0x22;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F6] = 0x23; // aka BREAK
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.PAUSE] = 0x23; // aka BREAK
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.BQUOTE] = 0x24;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.DASH] = 0x25;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NINE] = 0x26;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.SEVEN] = 0x27;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.FOUR] = 0x28;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.THREE] = 0x29;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.ESC] = 0x2A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.UP] = 0x30;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F3] = 0x31; // aka PF3
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F1] = 0x32; // aka PF1
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.BS] = 0x33;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.EQUALS] = 0x34;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.ZERO] = 0x35;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.EIGHT] = 0x36;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.SIX] = 0x37;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.FIVE] = 0x38;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.TWO] = 0x39;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.TAB] = 0x3A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_7] = 0x40;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F4] = 0x41; // aka PF4
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F2] = 0x42; // aka PF2
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_0] = 0x43;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F7] = 0x44; // aka LINE FEED
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.BSLASH] = 0x45;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.L] = 0x46;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.K] = 0x47;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.G] = 0x48;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.F] = 0x49;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.A] = 0x4A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_8] = 0x50;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_CR] = 0x51;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_2] = 0x52;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_1] = 0x53;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.QUOTE] = 0x55;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.SEMI] = 0x56;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.J] = 0x57;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.H] = 0x58;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.D] = 0x59;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.S] = 0x5A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_DEL] = 0x60; // keypad period
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F5] = 0x61; // aka KEYPAD COMMA
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_5] = 0x62;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_4] = 0x63;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.CR] = 0x64; // TODO: Figure out why the Technical Manual lists CR at both 0x04 and 0x64
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.PERIOD] = 0x65;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.COMMA] = 0x66;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.N] = 0x67;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.B] = 0x68;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.X] = 0x69;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F8] = 0x6A; // aka NO SCROLL
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_9] = 0x70;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_3] = 0x71;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_6] = 0x72;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.NUM_SUB] = 0x73; // aka KEYPAD MINUS
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.SLASH] = 0x75;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.M] = 0x76;
Keyboard.VT100.KEYMAP[Keyboard.ASCII[' ']] = 0x77;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.V] = 0x78;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.C] = 0x79;
Keyboard.VT100.KEYMAP[Keyboard.ASCII.Z] = 0x7A;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.F9] = 0x7B; // aka SET-UP
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.CTRL] = 0x7C;
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.SHIFT] = 0x7D; // either shift key (doesn't matter)
Keyboard.VT100.KEYMAP[Keyboard.KEYCODE.CAPSLOCK]= 0x7E;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.DEL] = 0x03;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.P] = 0x05;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.O] = 0x06;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.Y] = 0x07;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.T] = 0x08;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.W] = 0x09;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.Q] = 0x0A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.RIGHT] = 0x10;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.RBRACK] = 0x14;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.LBRACK] = 0x15;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.I] = 0x16;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.U] = 0x17;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.R] = 0x18;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.E] = 0x19;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.ONE] = 0x1A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.LEFT] = 0x20;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.DOWN] = 0x22;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F6] = 0x23; // aka BREAK
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.PAUSE] = 0x23; // aka BREAK
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.BQUOTE] = 0x24;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.DASH] = 0x25;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NINE] = 0x26;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.SEVEN] = 0x27;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.FOUR] = 0x28;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.THREE] = 0x29;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.ESC] = 0x2A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.UP] = 0x30;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F3] = 0x31; // aka PF3
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F1] = 0x32; // aka PF1
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.BS] = 0x33;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.EQUALS] = 0x34;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.ZERO] = 0x35;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.EIGHT] = 0x36;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.SIX] = 0x37;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.FIVE] = 0x38;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.TWO] = 0x39;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.TAB] = 0x3A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_7] = 0x40;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F4] = 0x41; // aka PF4
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F2] = 0x42; // aka PF2
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_0] = 0x43;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F7] = 0x44; // aka LINE FEED
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.BSLASH] = 0x45;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.L] = 0x46;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.K] = 0x47;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.G] = 0x48;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.F] = 0x49;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.A] = 0x4A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_8] = 0x50;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_CR] = 0x51;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_2] = 0x52;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_1] = 0x53;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.QUOTE] = 0x55;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.SEMI] = 0x56;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.J] = 0x57;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.H] = 0x58;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.D] = 0x59;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.S] = 0x5A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_DEL] = 0x60; // keypad period
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F5] = 0x61; // aka KEYPAD COMMA
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_5] = 0x62;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_4] = 0x63;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.CR] = 0x64; // TODO: Figure out why the Technical Manual lists CR at both 0x04 and 0x64
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.PERIOD] = 0x65;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.COMMA] = 0x66;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.N] = 0x67;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.B] = 0x68;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.X] = 0x69;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F8] = 0x6A; // aka NO SCROLL
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_9] = 0x70;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_3] = 0x71;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_6] = 0x72;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.NUM_SUB] = 0x73; // aka KEYPAD MINUS
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.SLASH] = 0x75;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.M] = 0x76;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII[' ']] = 0x77;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.V] = 0x78;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.C] = 0x79;
Keyboard8080.VT100.KEYMAP[Keyboard8080.ASCII.Z] = 0x7A;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.F9] = 0x7B; // aka SET-UP
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.CTRL] = 0x7C;
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.SHIFT] = 0x7D; // either shift key (doesn't matter)
Keyboard8080.VT100.KEYMAP[Keyboard8080.KEYCODE.CAPSLOCK]= 0x7E;
Keyboard.VT100.LEDCODES = {
'l4': Keyboard.VT100.STATUS.LED4,
'l3': Keyboard.VT100.STATUS.LED3,
'l2': Keyboard.VT100.STATUS.LED2,
'l1': Keyboard.VT100.STATUS.LED1,
'locked': Keyboard.VT100.STATUS.LOCKED,
'local': Keyboard.VT100.STATUS.LOCAL,
'online': ~Keyboard.VT100.STATUS.LOCAL
Keyboard8080.VT100.LEDCODES = {
'l4': Keyboard8080.VT100.STATUS.LED4,
'l3': Keyboard8080.VT100.STATUS.LED3,
'l2': Keyboard8080.VT100.STATUS.LED2,
'l1': Keyboard8080.VT100.STATUS.LED1,
'locked': Keyboard8080.VT100.STATUS.LOCKED,
'local': Keyboard8080.VT100.STATUS.LOCAL,
'online': ~Keyboard8080.VT100.STATUS.LOCAL
};
/*
* Supported models and their configurations
*/
Keyboard.MODELS = {
"SI1978": Keyboard.SI1978,
"VT100": Keyboard.VT100
Keyboard8080.MODELS = {
"SI1978": Keyboard8080.SI1978,
"VT100": Keyboard8080.VT100
};
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "esc")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
Keyboard8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
/*
* There's a special binding that the Video component uses ("kbd") to effectively bind its
@ -528,18 +528,18 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {Keyboard}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {Keyboard8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg)
Keyboard8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.cpu = cpu;
this.dbg = dbg; // NOTE: The "dbg" property must be set for the message functions to work
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
this.chipset = /** @type {ChipSet8080} */ (cmp.getMachineComponent("ChipSet"));
bus.addPortInputTable(this, this.config.portsInput);
bus.addPortOutputTable(this, this.config.portsOutput);
};
@ -547,12 +547,12 @@ Keyboard.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* powerUp(data, fRepower)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
Keyboard.prototype.powerUp = function(data, fRepower)
Keyboard8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
if (!data) {
@ -567,20 +567,20 @@ Keyboard.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave, fShutdown)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
Keyboard.prototype.powerDown = function(fSave, fShutdown)
Keyboard8080.prototype.powerDown = function(fSave, fShutdown)
{
return fSave? this.save() : true;
};
Keyboard.VT100.INIT = [
Keyboard8080.VT100.INIT = [
[
Keyboard.VT100.STATUS.INIT, // bVT100Status
Keyboard.VT100.ADDRESS.INIT, // bVT100Address
Keyboard8080.VT100.STATUS.INIT, // bVT100Status
Keyboard8080.VT100.ADDRESS.INIT, // bVT100Address
-1 // iKeyNext
]
];
@ -588,9 +588,9 @@ Keyboard.VT100.INIT = [
/**
* reset()
*
* @this {Keyboard}
* @this {Keyboard8080}
*/
Keyboard.prototype.reset = function()
Keyboard8080.prototype.reset = function()
{
/*
* As keyDown events are encountered, a corresponding "softCode" is looked up. If one is found,
@ -614,16 +614,16 @@ Keyboard.prototype.reset = function()
*
* This implements save support for the Keyboard component.
*
* @this {Keyboard}
* @this {Keyboard8080}
* @return {Object}
*/
Keyboard.prototype.save = function()
Keyboard8080.prototype.save = function()
{
var state = new State(this);
switch(this.config.MODEL) {
case Keyboard.SI1978.MODEL:
case Keyboard8080.SI1978.MODEL:
break;
case Keyboard.VT100.MODEL:
case Keyboard8080.VT100.MODEL:
state.set(0, [this.bVT100Status, this.bVT100Address, -1]);
break;
}
@ -635,21 +635,21 @@ Keyboard.prototype.save = function()
*
* This implements restore support for the Keyboard component.
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
Keyboard.prototype.restore = function(data)
Keyboard8080.prototype.restore = function(data)
{
var a;
if (data && (a = data[0]) && a.length) {
switch(this.config.MODEL) {
case Keyboard.SI1978.MODEL:
case Keyboard8080.SI1978.MODEL:
return true;
case Keyboard.VT100.MODEL:
case Keyboard8080.VT100.MODEL:
this.bVT100Status = a[0];
this.updateLEDs(this.bVT100Status & Keyboard.VT100.STATUS.LEDS);
this.updateLEDs(this.bVT100Status & Keyboard8080.VT100.STATUS.LEDS);
this.bVT100Address = a[1];
this.iKeyNext = a[2];
return true;
@ -661,11 +661,11 @@ Keyboard.prototype.restore = function(data)
/**
* setLED(control, f)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {Object} control is an HTML control DOM object
* @param {boolean} f is true if the LED represented by control should be "on", false if "off"
*/
Keyboard.prototype.setLED = function(control, f)
Keyboard8080.prototype.setLED = function(control, f)
{
/*
* TODO: Add support for user-definable LED colors
@ -676,10 +676,10 @@ Keyboard.prototype.setLED = function(control, f)
/**
* updateLEDs(bLEDs)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {number} bLEDs
*/
Keyboard.prototype.updateLEDs = function(bLEDs)
Keyboard8080.prototype.updateLEDs = function(bLEDs)
{
this.bLEDs = bLEDs;
for (var sBinding in this.config.LEDCODES) {
@ -701,10 +701,10 @@ Keyboard.prototype.updateLEDs = function(bLEDs)
*
* Returns a number if the keyCode exists in the KEYMAP, or a string if the keyCode has a soft-code string.
*
* @this {Keyboard}
* @this {Keyboard8080}
* @return {string|number|null}
*/
Keyboard.prototype.getSoftCode = function(keyCode)
Keyboard8080.prototype.getSoftCode = function(keyCode)
{
keyCode = this.config.ALTCODES[keyCode] || keyCode;
if (this.config.KEYMAP[keyCode]) {
@ -721,12 +721,12 @@ Keyboard.prototype.getSoftCode = function(keyCode)
/**
* onKeyDown(event, fDown)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {Object} event
* @param {boolean} fDown is true for a keyDown event, false for up
* @return {boolean} true to pass the event along, false to consume it
*/
Keyboard.prototype.onKeyDown = function(event, fDown)
Keyboard8080.prototype.onKeyDown = function(event, fDown)
{
var fPass = true;
var keyCode = event.keyCode;
@ -737,7 +737,7 @@ Keyboard.prototype.onKeyDown = function(event, fDown)
event.preventDefault();
}
if (!COMPILED && this.messageEnabled(Messages.KEYS)) {
if (!COMPILED && this.messageEnabled(Messages8080.KEYS)) {
this.printMessage("onKey" + (fDown? "Down" : "Up") + "(" + keyCode + "): softCode=" + softCode + ", pass=" + (fPass? "true" : "false"), true);
}
@ -747,11 +747,11 @@ Keyboard.prototype.onKeyDown = function(event, fDown)
/**
* indexOfSoftKey(softCode)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {number|string} softCode
* @return {number} index of softCode in aKeysActive, or -1 if not found
*/
Keyboard.prototype.indexOfSoftKey = function(softCode)
Keyboard8080.prototype.indexOfSoftKey = function(softCode)
{
var i;
for (i = 0; i < this.aKeysActive.length; i++) {
@ -763,12 +763,12 @@ Keyboard.prototype.indexOfSoftKey = function(softCode)
/**
* onSoftKeyDown(softCode, fDown)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {number|string} softCode
* @param {boolean} fDown is true for a down event, false for up
* @return {boolean} true to pass the event along, false to consume it
*/
Keyboard.prototype.onSoftKeyDown = function(softCode, fDown)
Keyboard8080.prototype.onSoftKeyDown = function(softCode, fDown)
{
var i = this.indexOfSoftKey(softCode);
if (fDown) {
@ -789,7 +789,7 @@ Keyboard.prototype.onSoftKeyDown = function(softCode, fDown)
var msDown = this.aKeysActive[i].msDown;
if (msDown) {
var msElapsed = Date.now() - msDown;
if (msElapsed < Keyboard.MINPRESSTIME) {
if (msElapsed < Keyboard8080.MINPRESSTIME) {
// this.println(softCode + " released after only " + msElapsed + "ms");
this.aKeysActive[i].fAutoRelease = true;
this.checkSoftKeysToRelease();
@ -806,22 +806,22 @@ Keyboard.prototype.onSoftKeyDown = function(softCode, fDown)
var bit = 0;
switch(softCode) {
case '1p':
bit = ChipSet.SI1978.STATUS1.P1;
bit = ChipSet8080.SI1978.STATUS1.P1;
break;
case '2p':
bit = ChipSet.SI1978.STATUS1.P2;
bit = ChipSet8080.SI1978.STATUS1.P2;
break;
case 'coin':
bit = ChipSet.SI1978.STATUS1.CREDIT;
bit = ChipSet8080.SI1978.STATUS1.CREDIT;
break;
case 'left':
bit = ChipSet.SI1978.STATUS1.P1_LEFT;
bit = ChipSet8080.SI1978.STATUS1.P1_LEFT;
break;
case 'right':
bit = ChipSet.SI1978.STATUS1.P1_RIGHT;
bit = ChipSet8080.SI1978.STATUS1.P1_RIGHT;
break;
case 'fire':
bit = ChipSet.SI1978.STATUS1.P1_FIRE;
bit = ChipSet8080.SI1978.STATUS1.P1_FIRE;
break;
}
if (bit) {
@ -834,9 +834,9 @@ Keyboard.prototype.onSoftKeyDown = function(softCode, fDown)
/**
* checkSoftKeysToRelease()
*
* @this {Keyboard}
* @this {Keyboard8080}
*/
Keyboard.prototype.checkSoftKeysToRelease = function()
Keyboard8080.prototype.checkSoftKeysToRelease = function()
{
var i = 0;
var msDelayMin = -1;
@ -845,7 +845,7 @@ Keyboard.prototype.checkSoftKeysToRelease = function()
var softCode = this.aKeysActive[i].softCode;
var msDown = this.aKeysActive[i].msDown;
var msElapsed = Date.now() - msDown;
var msDelay = Keyboard.MINPRESSTIME - msElapsed;
var msDelay = Keyboard8080.MINPRESSTIME - msElapsed;
if (msDelay > 0) {
if (msDelayMin < 0 || msDelayMin > msDelay) {
msDelayMin = msDelay;
@ -875,10 +875,10 @@ Keyboard.prototype.checkSoftKeysToRelease = function()
* Called whenever a ChipSet circuit needs the Keyboard UART's transmitter status.
* Currently, we have no busy conditions (our virtual keyboard transmitter is infinitely fast).
*
* @this {Keyboard}
* @this {Keyboard8080}
* @return {boolean} (true if ready, false if not)
*/
Keyboard.prototype.isTransmitterReady = function()
Keyboard8080.prototype.isTransmitterReady = function()
{
return true;
};
@ -888,15 +888,15 @@ Keyboard.prototype.isTransmitterReady = function()
*
* We take our cue from iKeyNext. If it's -1 (default), we simply return the last value latched
* in bVT100Address. Otherwise, if iKeyNext is a valid index into aKeysActive, we look up the key
* in the VT100.KEYMAP, latch it, and increment iKeyNext. Failing that, we latch Keyboard.VT100.KEYLAST
* in the VT100.KEYMAP, latch it, and increment iKeyNext. Failing that, we latch Keyboard8080.VT100.KEYLAST
* and reset iKeyNext to -1.
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {number} port (0x82)
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
* @return {number} simulated port value
*/
Keyboard.prototype.inVT100UARTAddress = function(port, addrFrom)
Keyboard8080.prototype.inVT100UARTAddress = function(port, addrFrom)
{
var b = this.bVT100Address;
if (this.iKeyNext >= 0) {
@ -913,7 +913,7 @@ Keyboard.prototype.inVT100UARTAddress = function(port, addrFrom)
*/
this.aKeysActive.splice(this.iKeyNext, 1);
}
b = Keyboard.VT100.KEYMAP[key.softCode];
b = Keyboard8080.VT100.KEYMAP[key.softCode];
if (b & 0x80) {
/*
* TODO: This code is supposed to be accompanied by a SHIFT key; make sure that it is.
@ -922,7 +922,7 @@ Keyboard.prototype.inVT100UARTAddress = function(port, addrFrom)
}
} else {
this.iKeyNext = -1;
b = Keyboard.VT100.KEYLAST;
b = Keyboard8080.VT100.KEYLAST;
}
this.bVT100Address = b;
this.cpu.requestINTR(1);
@ -934,17 +934,17 @@ Keyboard.prototype.inVT100UARTAddress = function(port, addrFrom)
/**
* outVT100UARTStatus(port, b, addrFrom)
*
* @this {Keyboard}
* @this {Keyboard8080}
* @param {number} port (0x82)
* @param {number} b
* @param {number} [addrFrom] (not defined if the Debugger is trying to write the specified port)
*/
Keyboard.prototype.outVT100UARTStatus = function(port, b, addrFrom)
Keyboard8080.prototype.outVT100UARTStatus = function(port, b, addrFrom)
{
this.printMessageIO(port, b, addrFrom, "KBDUART.STATUS");
this.bVT100Status = b;
this.updateLEDs(b & Keyboard.VT100.STATUS.LEDS);
if (b & Keyboard.VT100.STATUS.START) {
this.updateLEDs(b & Keyboard8080.VT100.STATUS.LEDS);
if (b & Keyboard8080.VT100.STATUS.START) {
this.iKeyNext = 0;
this.cpu.requestINTR(1);
}
@ -953,29 +953,29 @@ Keyboard.prototype.outVT100UARTStatus = function(port, b, addrFrom)
/*
* Port notification tables
*/
Keyboard.VT100.portsInput = {
0x82: Keyboard.prototype.inVT100UARTAddress
Keyboard8080.VT100.portsInput = {
0x82: Keyboard8080.prototype.inVT100UARTAddress
};
Keyboard.VT100.portsOutput = {
0x82: Keyboard.prototype.outVT100UARTStatus
Keyboard8080.VT100.portsOutput = {
0x82: Keyboard8080.prototype.outVT100UARTStatus
};
/**
* Keyboard.init()
* Keyboard8080.init()
*
* This function operates on every HTML element of class "keyboard", extracting the
* JSON-encoded parameters for the Keyboard constructor from the element's "data-value"
* attribute, invoking the constructor to create a Keyboard component, and then binding
* any associated HTML controls to the new component.
*/
Keyboard.init = function()
Keyboard8080.init = function()
{
var aeKbd = Component.getElementsByClass(document, PC8080.APPCLASS, "keyboard");
for (var iKbd = 0; iKbd < aeKbd.length; iKbd++) {
var eKbd = aeKbd[iKbd];
var parmsKbd = Component.getComponentParms(eKbd);
var kbd = new Keyboard(parmsKbd);
var kbd = new Keyboard8080(parmsKbd);
Component.bindComponentControls(kbd, eKbd, PC8080.APPCLASS);
}
};
@ -983,6 +983,6 @@ Keyboard.init = function()
/*
* Initialize every Keyboard module on the page.
*/
web.onInit(Keyboard.init);
web.onInit(Keyboard8080.init);
if (NODE) module.exports = Keyboard;
if (NODE) module.exports = Keyboard8080;

View file

@ -34,8 +34,8 @@
if (NODE) {
var str = require("../../shared/lib/strlib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var CPUDef = require("./cpudef");
var CPUDef8080 = require("./cpudef");
var Messages8080= require("./messages");
}
/**
@ -55,20 +55,20 @@ var littleEndian = (TYPEDARRAYS? (function() {
})() : false);
/**
* Memory(addr, used, size, type)
* Memory8080(addr, used, size, type)
*
* The Bus component allocates Memory objects so that each has a memory buffer with a
* The Bus component allocates Memory8080 objects so that each has a memory buffer with a
* block-granular starting address and an address range equal to bus.nBlockSize; however,
* the size of any given Memory object's underlying buffer can be either zero or bus.nBlockSize;
* the size of any given Memory8080 object's underlying buffer can be either zero or bus.nBlockSize;
* memory read/write functions for empty (buffer-less) blocks are mapped to readNone/writeNone.
*
* 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 blockSize Memory objects as the ranges require. Partial Memory blocks could
* as many new blockSize Memory8080 objects as the ranges require. Partial Memory8080 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
* Because Memory8080 blocks now allow us to have a "sparse" address space, we could choose to
* take the memory hit of allocating 4K arrays per block, where each element stores only one byte,
* instead of the more frugal but slightly slower approach of allocating arrays of 32-bit dwords
* (LONGARRAYS) and shifting/masking bytes/words to/from dwords; in theory, byte accesses would
@ -82,7 +82,7 @@ var littleEndian = (TYPEDARRAYS? (function() {
* size at this point. Also, not all JavaScript implementations support TYPEDARRAYS (IE9 is probably
* the only real outlier: it lacks typed arrays but otherwise has all the necessary HTML5 support).
*
* WARNING: Since Memory blocks are low-level objects that have no UI requirements, they
* WARNING: Since Memory8080 blocks are low-level objects that have no UI requirements, they
* do not inherit from the Component class, so if you want to use any Component class methods,
* such as Component.assert(), use the corresponding Debugger methods instead (assuming a debugger
* is available).
@ -91,19 +91,19 @@ var littleEndian = (TYPEDARRAYS? (function() {
* @param {number|null} [addr] of lowest used address in block
* @param {number} [used] portion of block in bytes (0 for none); must be a multiple of 4
* @param {number} [size] of block's buffer in bytes (0 for none); must be a multiple of 4
* @param {number} [type] is one of the Memory.TYPE constants (default is Memory.TYPE.NONE)
* @param {number} [type] is one of the Memory8080.TYPE constants (default is Memory8080.TYPE.NONE)
*/
function Memory(addr, used, size, type)
function Memory8080(addr, used, size, type)
{
var i;
this.id = (Memory.idBlock += 2);
this.id = (Memory8080.idBlock += 2);
this.adw = null;
this.offset = 0;
this.addr = addr;
this.used = used;
this.size = size || 0;
this.type = type || Memory.TYPE.NONE;
this.fReadOnly = (type == Memory.TYPE.ROM);
this.type = type || Memory8080.TYPE.NONE;
this.fReadOnly = (type == Memory8080.TYPE.ROM);
this.copyBreakpoints(); // initialize the block's Debugger info; the caller will reinitialize
/*
@ -146,7 +146,7 @@ function Memory(addr, used, size, type)
this.ab = new Uint8Array(this.buffer, 0, size);
this.aw = new Uint16Array(this.buffer, 0, size >> 1);
this.adw = new Int32Array(this.buffer, 0, size >> 2);
this.setAccess(littleEndian? Memory.afnArrayLE : Memory.afnArrayBE);
this.setAccess(littleEndian? Memory8080.afnArrayLE : Memory8080.afnArrayBE);
} else {
if (BYTEARRAYS) {
this.ab = new Array(size);
@ -160,7 +160,7 @@ function Memory(addr, used, size, type)
this.adw = new Array(size >> 2);
for (i = 0; i < this.adw.length; i++) this.adw[i] = 0;
}
this.setAccess(Memory.afnMemory);
this.setAccess(Memory8080.afnMemory);
}
}
@ -171,7 +171,7 @@ function Memory(addr, used, size, type)
* 'little endian") storage. ROM is equally conventional, except that the fReadOnly property is set,
* disabling writes. VIDEO is treated exactly like RAM, unless a controller is provided. Both RAM and
* VIDEO memory are always considered writable, and even ROM can be written using the Bus setByteDirect()
* interface (which in turn uses the Memory writeByteDirect() interface), allowing the ROM component to
* interface (which in turn uses the Memory8080 writeByteDirect() interface), allowing the ROM component to
* initialize its own memory. The CTRL type is used to identify memory-mapped devices that do not need
* any default storage and always provide their own controller.
*
@ -186,7 +186,7 @@ function Memory(addr, used, size, type)
* read-only memory), but the larger purpose of these types is to help document the caller's intent and to
* provide the Control Panel with the ability to highlight memory regions accordingly.
*/
Memory.TYPE = {
Memory8080.TYPE = {
NONE: 0,
RAM: 1,
ROM: 2,
@ -199,7 +199,7 @@ Memory.TYPE = {
/*
* Last used block ID (used for debugging only)
*/
Memory.idBlock = 0;
Memory8080.idBlock = 0;
/**
* adjustEndian(dw)
@ -207,22 +207,22 @@ Memory.idBlock = 0;
* @param {number} dw
* @return {number}
*/
Memory.adjustEndian = function(dw) {
Memory8080.adjustEndian = function(dw) {
if (TYPEDARRAYS && !littleEndian) {
dw = (dw << 24) | ((dw << 8) & 0x00ff0000) | ((dw >> 8) & 0x0000ff00) | (dw >>> 24);
}
return dw;
};
Memory.prototype = {
constructor: Memory,
Memory8080.prototype = {
constructor: Memory8080,
parent: null,
/**
* init(addr)
*
* Quick reinitializer when reusing a Memory block.
* Quick reinitializer when reusing a Memory8080 block.
*
* @this {Memory}
* @this {Memory8080}
* @param {number} addr
*/
init: function(addr) {
@ -231,13 +231,13 @@ Memory.prototype = {
/**
* clone(mem, type)
*
* Converts the current Memory block (this) into a clone of the given Memory block (mem),
* Converts the current Memory8080 block (this) into a clone of the given Memory8080 block (mem),
* and optionally overrides the current block's type with the specified type.
*
* @this {Memory}
* @param {Memory} mem
* @this {Memory8080}
* @param {Memory8080} mem
* @param {number} [type]
* @param {Debugger} [dbg]
* @param {Debugger8080} [dbg]
*/
clone: function(mem, type, dbg) {
/*
@ -250,7 +250,7 @@ Memory.prototype = {
this.size = mem.size;
if (type) {
this.type = type;
this.fReadOnly = (type == Memory.TYPE.ROM);
this.fReadOnly = (type == Memory8080.TYPE.ROM);
}
if (TYPEDARRAYS) {
this.buffer = mem.buffer;
@ -258,27 +258,27 @@ Memory.prototype = {
this.ab = mem.ab;
this.aw = mem.aw;
this.adw = mem.adw;
this.setAccess(littleEndian? Memory.afnArrayLE : Memory.afnArrayBE);
this.setAccess(littleEndian? Memory8080.afnArrayLE : Memory8080.afnArrayBE);
} else {
if (BYTEARRAYS) {
this.ab = mem.ab;
} else {
this.adw = mem.adw;
}
this.setAccess(Memory.afnMemory);
this.setAccess(Memory8080.afnMemory);
}
this.copyBreakpoints(dbg, mem);
},
/**
* save()
*
* This gets the contents of a Memory block as an array of 32-bit values; used by Bus.saveMemory(),
* This gets the contents of a Memory8080 block as an array of 32-bit values; used by Bus8080.saveMemory(),
* which in turn is called by CPUState.save().
*
* Memory blocks with custom memory controllers do NOT save their contents; that's the responsibility
* Memory8080 blocks with custom memory controllers do NOT save their contents; that's the responsibility
* of the controller component.
*
* @this {Memory}
* @this {Memory8080}
* @return {Array|Int32Array|null}
*/
save: function() {
@ -315,12 +315,12 @@ Memory.prototype = {
/**
* restore(adw)
*
* This restores the contents of a Memory block from an array of 32-bit values;
* used by Bus.restoreMemory(), which is called by CPUState.restore(), after all other
* components have been restored and thus all Memory blocks have been allocated
* This restores the contents of a Memory8080 block from an array of 32-bit values;
* used by Bus8080.restoreMemory(), which is called by CPUState.restore(), after all other
* components have been restored and thus all Memory8080 blocks have been allocated
* by their respective components.
*
* @this {Memory}
* @this {Memory8080}
* @param {Array|null} adw
* @return {boolean} true if successful, false if block size mismatch
*/
@ -360,16 +360,16 @@ Memory.prototype = {
/**
* setAccess(afn, fDirect)
*
* If no function table is specified, a default is selected based on the Memory type.
* If no function table is specified, a default is selected based on the Memory8080 type.
*
* @this {Memory}
* @this {Memory8080}
* @param {Array.<function()>} [afn] function table
* @param {boolean} [fDirect] (true to update direct access functions as well; default is true)
*/
setAccess: function(afn, fDirect) {
if (!afn) {
Component.assert(this.type == Memory.TYPE.NONE);
afn = Memory.afnNone;
Component.assert(this.type == Memory8080.TYPE.NONE);
afn = Memory8080.afnNone;
}
this.setReadAccess(afn, fDirect);
this.setWriteAccess(afn, fDirect);
@ -377,7 +377,7 @@ Memory.prototype = {
/**
* setReadAccess(afn, fDirect)
*
* @this {Memory}
* @this {Memory8080}
* @param {Array.<function()>} afn
* @param {boolean} [fDirect]
*/
@ -394,7 +394,7 @@ Memory.prototype = {
/**
* setWriteAccess(afn, fDirect)
*
* @this {Memory}
* @this {Memory8080}
* @param {Array.<function()>} afn
* @param {boolean} [fDirect]
*/
@ -411,7 +411,7 @@ Memory.prototype = {
/**
* resetReadAccess()
*
* @this {Memory}
* @this {Memory8080}
*/
resetReadAccess: function() {
this.readByte = this.readByteDirect;
@ -420,7 +420,7 @@ Memory.prototype = {
/**
* resetWriteAccess()
*
* @this {Memory}
* @this {Memory8080}
*/
resetWriteAccess: function() {
this.writeByte = this.fReadOnly? this.writeNone : this.writeByteDirect;
@ -429,31 +429,31 @@ Memory.prototype = {
/**
* printAddr(sMessage)
*
* @this {Memory}
* @this {Memory8080}
* @param {string} sMessage
*/
printAddr: function(sMessage) {
if (DEBUG && this.dbg && this.dbg.messageEnabled(Messages.MEM)) {
if (DEBUG && this.dbg && this.dbg.messageEnabled(Messages8080.MEM)) {
this.dbg.printMessage(sMessage + ' ' + (this.addr != null? ('%' + str.toHex(this.addr)) : '#' + this.id), true);
}
},
/**
* addBreakpoint(off, fWrite)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {boolean} fWrite
*/
addBreakpoint: function(off, fWrite) {
if (!fWrite) {
if (this.cReadBreakpoints++ === 0) {
this.setReadAccess(Memory.afnChecked, false);
this.setReadAccess(Memory8080.afnChecked, false);
}
if (DEBUG) this.printAddr("read breakpoint added to memory block");
}
else {
if (this.cWriteBreakpoints++ === 0) {
this.setWriteAccess(Memory.afnChecked, false);
this.setWriteAccess(Memory8080.afnChecked, false);
}
if (DEBUG) this.printAddr("write breakpoint added to memory block");
}
@ -461,7 +461,7 @@ Memory.prototype = {
/**
* removeBreakpoint(off, fWrite)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {boolean} fWrite
*/
@ -484,19 +484,19 @@ Memory.prototype = {
/**
* copyBreakpoints(dbg, mem)
*
* @this {Memory}
* @param {Debugger} [dbg]
* @param {Memory} [mem] (outgoing Memory block to copy breakpoints from, if any)
* @this {Memory8080}
* @param {Debugger8080} [dbg]
* @param {Memory8080} [mem] (outgoing Memory8080 block to copy breakpoints from, if any)
*/
copyBreakpoints: function(dbg, mem) {
this.dbg = dbg;
this.cReadBreakpoints = this.cWriteBreakpoints = 0;
if (mem) {
if ((this.cReadBreakpoints = mem.cReadBreakpoints)) {
this.setReadAccess(Memory.afnChecked, false);
this.setReadAccess(Memory8080.afnChecked, false);
}
if ((this.cWriteBreakpoints = mem.cWriteBreakpoints)) {
this.setWriteAccess(Memory.afnChecked, false);
this.setWriteAccess(Memory8080.afnChecked, false);
}
}
},
@ -513,15 +513,15 @@ Memory.prototype = {
* that a system would require nonexistent memory locations to return ALL bits set.
*
* Also, I'm reluctant to address that potential issue by simply returning -1, because to date, the above
* Memory interfaces have always returned values that are properly masked to 8, 16 or 32 bits, respectively.
* Memory8080 interfaces have always returned values that are properly masked to 8, 16 or 32 bits, respectively.
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
*/
readNone: function readNone(off, addr) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.CPU | Messages.MEM) /* && !off */) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages8080.CPU | Messages8080.MEM) /* && !off */) {
this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr), true);
}
return 0xff;
@ -529,20 +529,20 @@ Memory.prototype = {
/**
* writeNone(off, v, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} v (could be either a byte or word value, since we use the same handler for both kinds of accesses)
* @param {number} addr
*/
writeNone: function writeNone(off, v, addr) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages.CPU | Messages.MEM) /* && !off */) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(Messages8080.CPU | Messages8080.MEM) /* && !off */) {
this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
}
},
/**
* readShortDefault(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -553,7 +553,7 @@ Memory.prototype = {
/**
* writeShortDefault(off, w, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} w
* @param {number} addr
@ -565,7 +565,7 @@ Memory.prototype = {
/**
* readByteMemory(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -579,7 +579,7 @@ Memory.prototype = {
/**
* readShortMemory(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -602,7 +602,7 @@ Memory.prototype = {
/**
* writeByteMemory(off, b, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} b
* @param {number} addr
@ -620,7 +620,7 @@ Memory.prototype = {
/**
* writeShortMemory(off, w, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} w
* @param {number} addr
@ -645,7 +645,7 @@ Memory.prototype = {
/**
* readByteChecked(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -659,7 +659,7 @@ Memory.prototype = {
/**
* readShortChecked(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -673,7 +673,7 @@ Memory.prototype = {
/**
* writeByteChecked(off, b, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @param {number} b
@ -687,7 +687,7 @@ Memory.prototype = {
/**
* writeShortChecked(off, w, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @param {number} w
@ -701,7 +701,7 @@ Memory.prototype = {
/**
* readByteBE(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -712,7 +712,7 @@ Memory.prototype = {
/**
* readByteLE(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -723,7 +723,7 @@ Memory.prototype = {
/**
* readShortBE(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -734,7 +734,7 @@ Memory.prototype = {
/**
* readShortLE(off, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @return {number}
@ -749,7 +749,7 @@ Memory.prototype = {
/**
* writeByteBE(off, b, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} b
* @param {number} addr
@ -761,7 +761,7 @@ Memory.prototype = {
/**
* writeByteLE(off, b, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @param {number} b
@ -773,7 +773,7 @@ Memory.prototype = {
/**
* writeShortBE(off, w, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @param {number} w
@ -785,7 +785,7 @@ Memory.prototype = {
/**
* writeShortLE(off, w, addr)
*
* @this {Memory}
* @this {Memory8080}
* @param {number} off
* @param {number} addr
* @param {number} w
@ -809,16 +809,16 @@ 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.
*
Memory.afnNone = [Memory.prototype.readNone, Memory.prototype.readShortDefault, Memory.prototype.writeNone, Memory.prototype.writeShortDefault];
Memory8080.afnNone = [Memory8080.prototype.readNone, Memory8080.prototype.readShortDefault, Memory8080.prototype.writeNone, Memory8080.prototype.writeShortDefault];
*/
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];
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];
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];
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];
}
if (NODE) module.exports = Memory;
if (NODE) module.exports = Memory8080;

View file

@ -31,7 +31,7 @@
"use strict";
var Messages = {
var Messages8080 = {
CPU: 0x00000001,
BUS: 0x00000040,
MEM: 0x00000080,
@ -51,4 +51,4 @@ var Messages = {
HALT: 0x80000000|0
};
if (NODE) module.exports = Messages;
if (NODE) module.exports = Messages8080;

View file

@ -36,26 +36,26 @@ if (NODE) {
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Bus = require("./bus");
var Memory = require("./memory");
var CPUDef = require("./cpudef");
var Bus8080 = require("./bus");
var CPUDef8080 = require("./cpudef");
var Memory8080 = require("./memory");
}
/**
* Panel(parmsPanel)
* Panel8080(parmsPanel)
*
* The Panel component has no required (parmsPanel) properties.
* The Panel8080 component has no required (parmsPanel) properties.
*
* @constructor
* @extends Component
* @param {Object} parmsPanel
*/
function Panel(parmsPanel)
function Panel8080(parmsPanel)
{
Component.call(this, "Panel", parmsPanel, Panel);
Component.call(this, "Panel", parmsPanel, Panel8080);
}
Component.subclass(Panel);
Component.subclass(Panel8080);
/**
* setBinding(sHTMLType, sBinding, control, sValue)
@ -64,14 +64,14 @@ Component.subclass(Panel);
* Computer, CPU, Keyboard and Debugger components first. The order shouldn't matter, since any component
* that doesn't recognize the specified binding should simply ignore it.
*
* @this {Panel}
* @this {Panel8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "reset")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
Panel.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
Panel8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
if (this.cmp && this.cmp.setBinding(sHTMLType, sBinding, control, sValue)) return true;
if (this.cpu && this.cpu.setBinding(sHTMLType, sBinding, control, sValue)) return true;
@ -83,44 +83,44 @@ Panel.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {Panel}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {Panel8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
Panel.prototype.initBus = function(cmp, bus, cpu, dbg)
Panel8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
this.kbd = /** @type {Keyboard8080} */ (cmp.getMachineComponent("Keyboard"));
};
/**
* powerUp(data, fRepower)
*
* @this {Panel}
* @this {Panel8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
Panel.prototype.powerUp = function(data, fRepower)
Panel8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) Panel.init();
if (!fRepower) Panel8080.init();
return true;
};
/**
* powerDown(fSave, fShutdown)
*
* @this {Panel}
* @this {Panel8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
Panel.prototype.powerDown = function(fSave, fShutdown)
Panel8080.prototype.powerDown = function(fSave, fShutdown)
{
return true;
};
@ -135,19 +135,19 @@ Panel.prototype.powerDown = function(fSave, fShutdown)
*
* The Computer's updateStatus() handler is currently responsible for calling both our handler and the CPU's handler.
*
* @this {Panel}
* @this {Panel8080}
* @param {boolean} [fForce] (true will display registers even if the CPU is running and "live" registers are not enabled)
*/
Panel.prototype.updateStatus = function(fForce)
Panel8080.prototype.updateStatus = function(fForce)
{
};
/**
* Panel.init()
* Panel8080.init()
*
* This function operates on every HTML element of class "panel", extracting the
* JSON-encoded parameters for the Panel constructor from the element's "data-value"
* attribute, invoking the constructor to create a Panel component, and then binding
* JSON-encoded parameters for the Panel8080 constructor from the element's "data-value"
* attribute, invoking the constructor to create a Panel8080 component, and then binding
* any associated HTML controls to the new component.
*
* NOTE: Unlike most other component init() functions, this one is designed to be
@ -159,7 +159,7 @@ Panel.prototype.updateStatus = function(fForce)
* that might care (eg, CPU, Keyboard, and Debugger) that we have some controls they
* might want to use.
*/
Panel.init = function()
Panel8080.init = function()
{
var fReady = false;
var aePanels = Component.getElementsByClass(document, PC8080.APPCLASS, "panel");
@ -169,7 +169,7 @@ Panel.init = function()
var panel = Component.getComponentByID(parmsPanel['id']);
if (!panel) {
fReady = true;
panel = new Panel(parmsPanel);
panel = new Panel8080(parmsPanel);
}
Component.bindComponentControls(panel, ePanel, PC8080.APPCLASS);
if (fReady) panel.setReady();
@ -179,6 +179,6 @@ Panel.init = function()
/*
* Initialize every Panel module on the page.
*/
web.onInit(Panel.init);
web.onInit(Panel8080.init);
if (NODE) module.exports = Panel;
if (NODE) module.exports = Panel8080;

View file

@ -35,15 +35,15 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Memory = require("./memory");
var ROM = require("./rom");
var State = require("./state");
var State = require("../../shared/lib/state");
var Memory8080 = require("./memory");
var ROM8080 = require("./rom");
}
/**
* RAM(parmsRAM)
* RAM8080(parmsRAM)
*
* The RAM component expects the following (parmsRAM) properties:
* The RAM8080 component expects the following (parmsRAM) properties:
*
* addr: starting physical address of RAM (default is 0)
* size: amount of RAM, in bytes (default is 0, which means defer to motherboard switch settings)
@ -55,9 +55,9 @@ if (NODE) {
* @extends Component
* @param {Object} parmsRAM
*/
function RAM(parmsRAM)
function RAM8080(parmsRAM)
{
Component.call(this, "RAM", parmsRAM, RAM);
Component.call(this, "RAM", parmsRAM, RAM8080);
this.addrRAM = parmsRAM['addr'];
this.sizeRAM = parmsRAM['size'];
@ -65,18 +65,18 @@ function RAM(parmsRAM)
this.fAllocated = false;
}
Component.subclass(RAM);
Component.subclass(RAM8080);
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {RAM}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {RAM8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
RAM.prototype.initBus = function(cmp, bus, cpu, dbg)
RAM8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.bus = bus;
this.cpu = cpu;
@ -87,12 +87,12 @@ RAM.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* powerUp(data, fRepower)
*
* @this {RAM}
* @this {RAM8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
RAM.prototype.powerUp = function(data, fRepower)
RAM8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
/*
@ -109,12 +109,12 @@ RAM.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave, fShutdown)
*
* @this {RAM}
* @this {RAM8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
RAM.prototype.powerDown = function(fSave, fShutdown)
RAM8080.prototype.powerDown = function(fSave, fShutdown)
{
/*
* The Computer powers down the CPU first, at which point CPUState state is saved,
@ -128,12 +128,12 @@ RAM.prototype.powerDown = function(fSave, fShutdown)
/**
* reset()
*
* @this {RAM}
* @this {RAM8080}
*/
RAM.prototype.reset = function()
RAM8080.prototype.reset = function()
{
if (!this.fAllocated && this.sizeRAM) {
if (this.bus.addMemory(this.addrRAM, this.sizeRAM, Memory.TYPE.RAM)) {
if (this.bus.addMemory(this.addrRAM, this.sizeRAM, Memory8080.TYPE.RAM)) {
this.fAllocated = true;
}
}
@ -145,12 +145,12 @@ RAM.prototype.reset = function()
/**
* save()
*
* This implements save support for the RAM component.
* This implements save support for the RAM8080 component.
*
* @this {RAM}
* @this {RAM8080}
* @return {Object}
*/
RAM.prototype.save = function()
RAM8080.prototype.save = function()
{
return null;
};
@ -158,39 +158,39 @@ RAM.prototype.save = function()
/**
* restore(data)
*
* This implements restore support for the RAM component.
* This implements restore support for the RAM8080 component.
*
* @this {RAM}
* @this {RAM8080}
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
RAM.prototype.restore = function(data)
RAM8080.prototype.restore = function(data)
{
return true;
};
/**
* RAM.init()
* RAM8080.init()
*
* This function operates on every HTML element of class "ram", extracting the
* JSON-encoded parameters for the RAM constructor from the element's "data-value"
* attribute, invoking the constructor to create a RAM component, and then binding
* JSON-encoded parameters for the RAM8080 constructor from the element's "data-value"
* attribute, invoking the constructor to create a RAM8080 component, and then binding
* any associated HTML controls to the new component.
*/
RAM.init = function()
RAM8080.init = function()
{
var aeRAM = Component.getElementsByClass(document, PC8080.APPCLASS, "ram");
for (var iRAM = 0; iRAM < aeRAM.length; iRAM++) {
var eRAM = aeRAM[iRAM];
var parmsRAM = Component.getComponentParms(eRAM);
var ram = new RAM(parmsRAM);
var ram = new RAM8080(parmsRAM);
Component.bindComponentControls(ram, eRAM, PC8080.APPCLASS);
}
};
/*
* Initialize all the RAM modules on the page.
* Initialize all the RAM8080 modules on the page.
*/
web.onInit(RAM.init);
web.onInit(RAM8080.init);
if (NODE) module.exports = RAM;
if (NODE) module.exports = RAM8080;

View file

@ -36,14 +36,14 @@ if (NODE) {
var web = require("../../shared/lib/weblib");
var DumpAPI = require("../../shared/lib/dumpapi");
var Component = require("../../shared/lib/component");
var Memory = require("./memory");
var CPUDef = require("./cpudef");
var CPUDef8080 = require("./cpudef");
var Memory8080 = require("./memory");
}
/**
* ROM(parmsROM)
* ROM8080(parmsROM)
*
* The ROM component expects the following (parmsROM) properties:
* The ROM8080 component expects the following (parmsROM) properties:
*
* addr: physical address of ROM
* size: amount of ROM, in bytes
@ -68,9 +68,9 @@ if (NODE) {
* @extends Component
* @param {Object} parmsROM
*/
function ROM(parmsROM)
function ROM8080(parmsROM)
{
Component.call(this, "ROM", parmsROM, ROM);
Component.call(this, "ROM", parmsROM, ROM8080);
this.abROM = null;
this.addrROM = parmsROM['addr'];
@ -112,9 +112,9 @@ function ROM(parmsROM)
}
}
Component.subclass(ROM);
Component.subclass(ROM8080);
ROM.CPM = {
ROM8080.CPM = {
BIOS: {
VECTOR: 0x0000
},
@ -136,7 +136,7 @@ ROM.CPM = {
}
};
ROM.CPM.VECTORS = [ROM.CPM.BIOS.VECTOR, ROM.CPM.BDOS.VECTOR];
ROM8080.CPM.VECTORS = [ROM8080.CPM.BIOS.VECTOR, ROM8080.CPM.BDOS.VECTOR];
/*
* NOTE: There's currently no need for this component to have a reset() function, since
@ -154,13 +154,13 @@ ROM.CPM.VECTORS = [ROM.CPM.BIOS.VECTOR, ROM.CPM.BDOS.VECTOR];
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {ROM}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {ROM8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
ROM.prototype.initBus = function(cmp, bus, cpu, dbg)
ROM8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.bus = bus;
this.cpu = cpu;
@ -171,12 +171,12 @@ ROM.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* powerUp(data, fRepower)
*
* @this {ROM}
* @this {ROM8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
ROM.prototype.powerUp = function(data, fRepower)
ROM8080.prototype.powerUp = function(data, fRepower)
{
if (this.aSymbols) {
if (this.dbg) {
@ -199,12 +199,12 @@ ROM.prototype.powerUp = function(data, fRepower)
* useful down the road, like user-defined symbols (ie, symbols that the Debugger may have
* created, above and beyond those symbols we automatically loaded, if any, along with the ROM).
*
* @this {ROM}
* @this {ROM8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
ROM.prototype.powerDown = function(fSave, fShutdown)
ROM8080.prototype.powerDown = function(fSave, fShutdown)
{
return true;
};
@ -212,12 +212,12 @@ ROM.prototype.powerDown = function(fSave, fShutdown)
/**
* doneLoad(sURL, sROMData, nErrorCode)
*
* @this {ROM}
* @this {ROM8080}
* @param {string} sURL
* @param {string} sROMData
* @param {number} nErrorCode (response from server if anything other than 200)
*/
ROM.prototype.doneLoad = function(sURL, sROMData, nErrorCode)
ROM8080.prototype.doneLoad = function(sURL, sROMData, nErrorCode)
{
if (nErrorCode) {
this.notice("Unable to load system ROM (error " + nErrorCode + ": " + sURL + ")");
@ -291,9 +291,9 @@ ROM.prototype.doneLoad = function(sURL, sROMData, nErrorCode)
* until after initBus() has received the Bus component AND doneLoad() has received the abROM data. When both
* those criteria are satisfied, the component becomes "ready".
*
* @this {ROM}
* @this {ROM8080}
*/
ROM.prototype.copyROM = function()
ROM8080.prototype.copyROM = function()
{
if (!this.isReady()) {
if (!this.sFilePath) {
@ -346,13 +346,13 @@ ROM.prototype.copyROM = function()
/**
* addROM(addr)
*
* @this {ROM}
* @this {ROM8080}
* @param {number} addr
* @return {boolean}
*/
ROM.prototype.addROM = function(addr)
ROM8080.prototype.addROM = function(addr)
{
if (this.bus.addMemory(addr, this.sizeROM, this.fWritable? Memory.TYPE.RAM : Memory.TYPE.ROM)) {
if (this.bus.addMemory(addr, this.sizeROM, this.fWritable? Memory8080.TYPE.RAM : Memory8080.TYPE.ROM)) {
if (DEBUG) this.log("addROM(): copying ROM to " + str.toHexLong(addr) + " (" + str.toHexLong(this.abROM.length) + " bytes)");
var i;
for (i = 0; i < this.abROM.length; i++) {
@ -365,8 +365,8 @@ ROM.prototype.addROM = function(addr)
* (namely, 0x0000, which is the CP/M reset vector, and 0x0005, which is the CP/M system call vector) and
* then telling the CPU to call us whenever a HLT occurs, so we can check PC for one of these addresses.
*/
for (i = 0; i < ROM.CPM.VECTORS.length; i++) {
this.bus.setByteDirect(ROM.CPM.VECTORS[i], CPUDef.OPCODE.HLT);
for (i = 0; i < ROM8080.CPM.VECTORS.length; i++) {
this.bus.setByteDirect(ROM8080.CPM.VECTORS[i], CPUDef8080.OPCODE.HLT);
}
this.cpu.addHaltCheck(function(rom) {
@ -388,24 +388,24 @@ ROM.prototype.addROM = function(addr)
/**
* checkCPMVector(addr)
*
* @this {ROM}
* @this {ROM8080}
* @param {number} addr (of the HLT opcode)
* @return {boolean} true if special processing performed, false if not
*/
ROM.prototype.checkCPMVector = function(addr)
ROM8080.prototype.checkCPMVector = function(addr)
{
var i = ROM.CPM.VECTORS.indexOf(addr);
var i = ROM8080.CPM.VECTORS.indexOf(addr);
if (i >= 0) {
var fCPM = false;
var cpu = this.cpu;
var dbg = this.dbg;
if (addr == ROM.CPM.BDOS.VECTOR) {
if (addr == ROM8080.CPM.BDOS.VECTOR) {
fCPM = true;
switch(cpu.regC) {
case ROM.CPM.BDOS.FUNC.CON_WRITE:
case ROM8080.CPM.BDOS.FUNC.CON_WRITE:
this.writeCPMString(this.getCPMChar(cpu.regE));
break;
case ROM.CPM.BDOS.FUNC.STR_WRITE:
case ROM8080.CPM.BDOS.FUNC.STR_WRITE:
this.writeCPMString(this.getCPMString(cpu.getDE(), '$'));
break;
default:
@ -414,7 +414,7 @@ ROM.prototype.checkCPMVector = function(addr)
}
}
if (fCPM) {
CPUDef.opRET.call(cpu); // for recognized calls, automatically return
CPUDef8080.opRET.call(cpu); // for recognized calls, automatically return
}
else if (dbg) {
this.println("\nCP/M vector " + str.toHexWord(addr));
@ -430,11 +430,11 @@ ROM.prototype.checkCPMVector = function(addr)
/**
* getCPMChar(ch)
*
* @this {ROM}
* @this {ROM8080}
* @param {number} ch
* @return {string}
*/
ROM.prototype.getCPMChar = function(ch)
ROM8080.prototype.getCPMChar = function(ch)
{
return String.fromCharCode(ch);
};
@ -442,12 +442,12 @@ ROM.prototype.getCPMChar = function(ch)
/**
* getCPMString(addr, chEnd)
*
* @this {ROM}
* @this {ROM8080}
* @param {number} addr (of a string)
* @param {string|number} [chEnd] (terminating character, default is 0)
* @return {string}
*/
ROM.prototype.getCPMString = function(addr, chEnd)
ROM8080.prototype.getCPMString = function(addr, chEnd)
{
var s = "";
var cchMax = 255;
@ -463,10 +463,10 @@ ROM.prototype.getCPMString = function(addr, chEnd)
/**
* writeCPMString(s)
*
* @this {ROM}
* @this {ROM8080}
* @param {string} s
*/
ROM.prototype.writeCPMString = function(s)
ROM8080.prototype.writeCPMString = function(s)
{
s = s.replace(/\r/g, '');
if (this.controlPrint) {
@ -485,37 +485,37 @@ ROM.prototype.writeCPMString = function(s)
* Now that the Bus component provides low-level getMemoryBlocks() and setMemoryBlocks() methods
* to manually get and set the blocks of any memory range, it is now possible to create true aliases.
*
* @this {ROM}
* @this {ROM8080}
* @param {number} addr
*/
ROM.prototype.cloneROM = function(addr)
ROM8080.prototype.cloneROM = function(addr)
{
var aBlocks = this.bus.getMemoryBlocks(this.addrROM, this.sizeROM);
this.bus.setMemoryBlocks(addr, this.sizeROM, aBlocks);
};
/**
* ROM.init()
* ROM8080.init()
*
* This function operates on every HTML element of class "rom", extracting the
* JSON-encoded parameters for the ROM constructor from the element's "data-value"
* attribute, invoking the constructor to create a ROM component, and then binding
* JSON-encoded parameters for the ROM8080 constructor from the element's "data-value"
* attribute, invoking the constructor to create a ROM8080 component, and then binding
* any associated HTML controls to the new component.
*/
ROM.init = function()
ROM8080.init = function()
{
var aeROM = Component.getElementsByClass(document, PC8080.APPCLASS, "rom");
for (var iROM = 0; iROM < aeROM.length; iROM++) {
var eROM = aeROM[iROM];
var parmsROM = Component.getComponentParms(eROM);
var rom = new ROM(parmsROM);
var rom = new ROM8080(parmsROM);
Component.bindComponentControls(rom, eROM, PC8080.APPCLASS);
}
};
/*
* Initialize all the ROM modules on the page.
* Initialize all the ROM8080 modules on the page.
*/
web.onInit(ROM.init);
web.onInit(ROM8080.init);
if (NODE) module.exports = ROM;
if (NODE) module.exports = ROM8080;

View file

@ -35,14 +35,14 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Messages = require("./messages");
var State = require("./state");
var State = require("../../shared/lib/state");
var Messages8080= require("./messages");
}
/**
* SerialPort(parmsSerial)
* SerialPort8080(parmsSerial)
*
* The SerialPort component has the following component-specific (parmsSerial) properties:
* The SerialPort8080 component has the following component-specific (parmsSerial) properties:
*
* adapter: 0 if not defined
*
@ -62,7 +62,7 @@ if (NODE) {
* @extends Component
* @param {Object} parmsSerial
*/
function SerialPort(parmsSerial) {
function SerialPort8080(parmsSerial) {
this.iAdapter = +parmsSerial['adapter'];
@ -103,7 +103,18 @@ function SerialPort(parmsSerial) {
this.charBOL = parmsSerial['charBOL'];
this.iLogicalCol = 0;
Component.call(this, "SerialPort", parmsSerial, SerialPort, Messages.SERIAL);
/*
* fAutoXOFF enables some experimental auto-XOFF/XON processing. It assumes if the VT100 firmware
* issues an XOFF, receiveByte() should stop accepting more data until the firmware issues an XOFF.
*
* The downside is that this doesn't really do anything to stem the flow of incoming data; it just
* prevents the VT100's internal buffer from overflowing. TODO: Eliminate the need for this hack
* and add some *real* flow-control interfaces between connected SerialPort components.
*/
this.fAutoXOFF = true;
this.fAutoStop = false;
Component.call(this, "SerialPort", parmsSerial, SerialPort8080, Messages8080.SERIAL);
var sBinding = parmsSerial['binding'];
if (sBinding == "console") {
@ -112,11 +123,11 @@ function SerialPort(parmsSerial) {
/*
* NOTE: If sBinding is not the name of a valid Control Panel DOM element, this call does nothing.
*/
Component.bindExternalControl(this, sBinding, SerialPort.sIOBuffer);
Component.bindExternalControl(this, sBinding, SerialPort8080.sIOBuffer);
}
/*
* No connection until initBus() invokes initConnection().
* No connection until initConnection() is called.
*/
this.sDataReceived = "";
this.connection = this.sendData = null;
@ -130,7 +141,7 @@ function SerialPort(parmsSerial) {
}
/*
* class SerialPort
* class SerialPort8080
* property {number} iAdapter
* property {number} portBase
* property {number} nIRQ
@ -146,9 +157,9 @@ function SerialPort(parmsSerial) {
* for third-party apps.
*/
Component.subclass(SerialPort);
Component.subclass(SerialPort8080);
SerialPort.UART8251 = {
SerialPort8080.UART8251 = {
/*
* Format of MODE byte written to CONTROL port 0x1
*/
@ -212,6 +223,8 @@ SerialPort.UART8251 = {
* 0xD 36 4800
* 0xE 18 9600 (default)
* 0xF 9 19200
*
* NOTE: This is a VT100-specific port and baud rate table.
*/
BAUDRATES: {
RECV_RATE: 0x0F,
@ -223,20 +236,20 @@ SerialPort.UART8251 = {
]
};
SerialPort.UART8251.INIT = [
SerialPort8080.UART8251.INIT = [
false,
0,
0,
SerialPort.UART8251.STATUS.INIT,
SerialPort.UART8251.MODE.INIT,
SerialPort.UART8251.COMMAND.INIT,
SerialPort.UART8251.BAUDRATES.INIT
SerialPort8080.UART8251.STATUS.INIT,
SerialPort8080.UART8251.MODE.INIT,
SerialPort8080.UART8251.COMMAND.INIT,
SerialPort8080.UART8251.BAUDRATES.INIT
];
/*
* Internal name used for the I/O buffer control, if any, that we bind to the SerialPort.
* Internal name used for the I/O buffer control, if any, that we bind to a SerialPort8080.
*
* Alternatively, if SerialPort wants to use another component's control (eg, the Panel's
* Alternatively, if SerialPort8080 wants to use another component's control (eg, the Panel's
* "print" control), it can specify the name of that control with the 'binding' property.
*
* For that binding to succeed, we also need to know the target component; for now, that's
@ -244,24 +257,24 @@ SerialPort.UART8251.INIT = [
* upon initializing before we do, but it would be a simple matter to include a component type
* or ID as part of the 'binding' property as well, if we need more flexibility later.
*/
SerialPort.sIOBuffer = "buffer";
SerialPort8080.sIOBuffer = "buffer";
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "buffer")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
SerialPort8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
var serial = this;
switch (sBinding) {
case SerialPort.sIOBuffer:
case SerialPort8080.sIOBuffer:
this.bindings[sBinding] = this.controlIOBuffer = control;
/*
@ -325,10 +338,31 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
* that do not conflict with predefined controls (which, of course, is the only way you can get here).
*/
this.bindings[sBinding] = control;
/*
* Convert any "backslashed" sequences into the appropriate control characters.
* Backslash sequences like \n, \r and \\ have already been converted to LF, CR and backslash
* characters, by virtue of the eval() function that all our component parameter strings pass through;
* eval() treats strings like "source code", so any backslash sequence that JavaScript supports is
* automatically converted.
*
* The complete list of supported backslash sequences:
*
* \0 \' \" \\ \n \r \v \t \b \f \uXXXX \xXX
*
* We also want to support some additional sequences, like backslash-e for ESC. Only one problem: for
* any unrecognized backslash sequence, eval() simply removes the backslash. So we have to double-backslash
* it, which eval() will replace with a single backslash.
*
* So, additional supported backslash sequences include:
*
* \\e (ESC)
*
* Note that I've judiciously avoided using terms "escape notation" or "escape sequence" to talk about
* these sequences, because ESC is one of the additional characters I want to support, and using the word
* "escape" in both contexts is WAY confusing.
*/
sValue = sValue.replace(/\\n/g, "\n").replace(/\\r/g, "\r");
sValue = sValue.replace(/\\e/g, String.fromCharCode(0x1b));
control.onclick = function onClickTest(event) {
serial.receiveData(sValue);
/*
@ -347,13 +381,13 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {SerialPort}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {SerialPort8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
SerialPort8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.bus = bus;
@ -368,12 +402,10 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
serial.transmitData();
});
this.chipset = /** @type {ChipSet} */ (cmp.getMachineComponent("ChipSet"));
this.chipset = /** @type {ChipSet8080} */ (cmp.getMachineComponent("ChipSet"));
bus.addPortInputTable(this, SerialPort.aPortInput, this.portBase);
bus.addPortOutputTable(this, SerialPort.aPortOutput, this.portBase);
this.initConnection();
bus.addPortInputTable(this, SerialPort8080.aPortInput, this.portBase);
bus.addPortOutputTable(this, SerialPort8080.aPortOutput, this.portBase);
this.setReady();
};
@ -381,8 +413,8 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* initConnection()
*
* If a machine 'connection' parameter exists of the form "<sourcePort>=<targetMachine>.<targetPort>",
* and "<sourcePort>" matches our idComponent, then look for a component with id "<targetMachine>.<targetPort>".
* If a machine 'connection' parameter exists of the form "{sourcePort}->{targetMachine}.{targetPort}",
* and "{sourcePort}" matches our idComponent, then look for a component with id "{targetMachine}.{targetPort}".
*
* If the target component is found, then verify that it has exported functions with the following names:
*
@ -392,40 +424,52 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
* performs its own initConnection(), it will find our receiveByte(b) function, at which point communication in both
* directions should be established.
*
* @this {SerialPort}
* @this {SerialPort8080}
*/
SerialPort.prototype.initConnection = function()
SerialPort8080.prototype.initConnection = function()
{
var sConnection = this.cmp.getMachineParm("connection");
if (sConnection) {
var asParts = sConnection.split('=');
var asParts = sConnection.split('->');
if (asParts.length == 2) {
var sSourceID = str.trim(asParts[0]);
if (sSourceID != this.idComponent) return; // this connection string is intended for another instance
var sTargetID = str.trim(asParts[1]);
if (sSourceID == this.idComponent) {
this.connection = Component.getComponentByID(sTargetID);
if (this.connection) {
var exports = this.connection['exports'];
if (exports) {
this.sendData = exports['receiveData'];
}
this.connection = Component.getComponentByID(sTargetID);
if (this.connection) {
var exports = this.connection['exports'];
if (exports) {
this.sendData = exports['receiveData'];
this.status(this.idMachine + '.' + sSourceID + " connected to " + sTargetID);
return;
}
}
}
this.notice("Unable to establish connection: " + sConnection);
}
};
/**
* powerUp(data, fRepower)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
SerialPort.prototype.powerUp = function(data, fRepower)
SerialPort8080.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
/*
* We needed to wait until now to make our first inter-machine connection attempt;
* doing this in initBus() was still too early, because initBus() is called in the context
* of onInit() processing for all machines of the same type (eg, PCx86), and if we're
* trying to connect to the port of a machine of a DIFFERENT type (eg, PC8080), it may not
* have been initialized yet.
*/
this.initConnection();
if (!data || !this.restore) {
this.reset();
} else {
@ -438,12 +482,12 @@ SerialPort.prototype.powerUp = function(data, fRepower)
/**
* powerDown(fSave, fShutdown)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {boolean} [fSave]
* @param {boolean} [fShutdown]
* @return {Object|boolean} component state if fSave; otherwise, true if successful, false if failure
*/
SerialPort.prototype.powerDown = function(fSave, fShutdown)
SerialPort8080.prototype.powerDown = function(fSave, fShutdown)
{
return fSave? this.save() : true;
};
@ -451,9 +495,9 @@ SerialPort.prototype.powerDown = function(fSave, fShutdown)
/**
* reset()
*
* @this {SerialPort}
* @this {SerialPort8080}
*/
SerialPort.prototype.reset = function()
SerialPort8080.prototype.reset = function()
{
this.initState();
};
@ -461,12 +505,12 @@ SerialPort.prototype.reset = function()
/**
* save()
*
* This implements save support for the SerialPort component.
* This implements save support for the SerialPort8080 component.
*
* @this {SerialPort}
* @this {SerialPort8080}
* @return {Object}
*/
SerialPort.prototype.save = function()
SerialPort8080.prototype.save = function()
{
var state = new State(this);
state.set(0, this.saveRegisters());
@ -476,13 +520,13 @@ SerialPort.prototype.save = function()
/**
* restore(data)
*
* This implements restore support for the SerialPort component.
* This implements restore support for the SerialPort8080 component.
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {Object} data
* @return {boolean} true if successful, false if failure
*/
SerialPort.prototype.restore = function(data)
SerialPort8080.prototype.restore = function(data)
{
return this.initState(data[0]);
};
@ -490,15 +534,15 @@ SerialPort.prototype.restore = function(data)
/**
* initState(data)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {Array} [data]
* @return {boolean} true if successful, false if failure
*/
SerialPort.prototype.initState = function(data)
SerialPort8080.prototype.initState = function(data)
{
var i = 0;
if (data === undefined) {
data = SerialPort.UART8251.INIT;
data = SerialPort8080.UART8251.INIT;
}
this.fReady = data[i++];
this.bDataIn = data[i++];
@ -513,10 +557,10 @@ SerialPort.prototype.initState = function(data)
/**
* saveRegisters()
*
* @this {SerialPort}
* @this {SerialPort8080}
* @return {Array}
*/
SerialPort.prototype.saveRegisters = function()
SerialPort8080.prototype.saveRegisters = function()
{
var i = 0;
var data = [];
@ -533,18 +577,18 @@ SerialPort.prototype.saveRegisters = function()
/**
* getBaudTimeout(maskRate)
*
* @this {SerialPort}
* @param {number} maskRate (either SerialPort.UART8251.BAUDRATES.RECV_RATE or SerialPort.UART8251.BAUDRATES.XMIT_RATE)
* @this {SerialPort8080}
* @param {number} maskRate (either SerialPort8080.UART8251.BAUDRATES.RECV_RATE or SerialPort8080.UART8251.BAUDRATES.XMIT_RATE)
* @return {number} (number of milliseconds per byte)
*/
SerialPort.prototype.getBaudTimeout = function(maskRate)
SerialPort8080.prototype.getBaudTimeout = function(maskRate)
{
var indexRate = (this.bBaudRates & maskRate);
if (!(maskRate & 0xf)) indexRate >>= 4;
var nBaud = SerialPort.UART8251.BAUDTABLE[indexRate];
var nBits = ((this.bMode & SerialPort.UART8251.MODE.DATA_BITS) >> 2) + 6; // includes an extra +1 for start bit
if (this.bMode & SerialPort.UART8251.MODE.PARITY_ENABLE) nBits++;
nBits += ((((this.bMode & SerialPort.UART8251.MODE.STOP_BITS) >> 6) + 1) >> 1);
var nBaud = SerialPort8080.UART8251.BAUDTABLE[indexRate];
var nBits = ((this.bMode & SerialPort8080.UART8251.MODE.DATA_BITS) >> 2) + 6; // includes an extra +1 for start bit
if (this.bMode & SerialPort8080.UART8251.MODE.PARITY_ENABLE) nBits++;
nBits += ((((this.bMode & SerialPort8080.UART8251.MODE.STOP_BITS) >> 6) + 1) >> 1);
var nBytesPerSecond = Math.round(nBaud / nBits);
return 1000 / nBytesPerSecond;
};
@ -552,16 +596,16 @@ SerialPort.prototype.getBaudTimeout = function(maskRate)
/**
* receiveByte(b)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} b
* @return {boolean}
*/
SerialPort.prototype.receiveByte = function(b)
SerialPort8080.prototype.receiveByte = function(b)
{
this.printMessage("receiveByte(" + str.toHexByte(b) + "), status=" + str.toHexByte(this.bStatus));
if (!(this.bStatus & SerialPort.UART8251.STATUS.RECV_FULL)) {
if (!this.fAutoStop && !(this.bStatus & SerialPort8080.UART8251.STATUS.RECV_FULL)) {
this.bDataIn = b;
this.bStatus |= SerialPort.UART8251.STATUS.RECV_FULL;
this.bStatus |= SerialPort8080.UART8251.STATUS.RECV_FULL;
this.cpu.requestINTR(this.nIRQ);
return true;
}
@ -577,10 +621,11 @@ SerialPort.prototype.receiveByte = function(b)
* of a string. When we're called by another component, data will typically be a number (ie, byte). If no
* data is specified at all, then all we do is "clock" any remaining data into the receiver.
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number|string|undefined} [data]
* @return {boolean} true if received, false if not
*/
SerialPort.prototype.receiveData = function(data)
SerialPort8080.prototype.receiveData = function(data)
{
if (data != null) {
if (typeof data != "number") {
@ -594,24 +639,36 @@ SerialPort.prototype.receiveData = function(data)
this.sDataReceived = this.sDataReceived.substr(1);
}
if (this.sDataReceived && this.cpu) {
this.cpu.setTimer(this.timerReceiveNext, this.getBaudTimeout(SerialPort.UART8251.BAUDRATES.RECV_RATE));
this.cpu.setTimer(this.timerReceiveNext, this.getBaudTimeout(SerialPort8080.UART8251.BAUDRATES.RECV_RATE));
}
}
return true; // for now, return true regardless, since we're buffering everything anyway
};
/**
* transmitByte(b)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} b
* @return {boolean} true if transmitted, false if not
*/
SerialPort.prototype.transmitByte = function(b)
SerialPort8080.prototype.transmitByte = function(b)
{
var fTransmitted = false;
this.printMessage("transmitByte(" + str.toHexByte(b) + ")");
if (this.fAutoXOFF) {
if (b == 0x13) { // XOFF
this.fAutoStop = true;
return false;
}
if (b == 0x11) { // XON
this.fAutoStop = false;
return false;
}
}
if (this.sendData) {
if (this.sendData.call(this.connection, b)) {
fTransmitted = true;
@ -667,51 +724,51 @@ SerialPort.prototype.transmitByte = function(b)
* When timerTransmitNext fires, we have honored the programmed XMIT_RATE period, so we can
* set XMIT_READY (and XMIT_EMPTY), which signals the firmware that another byte can be transmitted.
*
* @this {SerialPort}
* @this {SerialPort8080}
*/
SerialPort.prototype.transmitData = function()
SerialPort8080.prototype.transmitData = function()
{
this.bStatus |= (SerialPort.UART8251.STATUS.XMIT_READY | SerialPort.UART8251.STATUS.XMIT_EMPTY);
this.bStatus |= (SerialPort8080.UART8251.STATUS.XMIT_READY | SerialPort8080.UART8251.STATUS.XMIT_EMPTY);
};
/**
* isTransmitterReady()
*
* Called whenever a ChipSet circuit needs the SerialPort UART's transmitter status.
* Called whenever a ChipSet circuit needs the SerialPort8080 UART's transmitter status.
*
* @this {SerialPort}
* @this {SerialPort8080}
* @return {boolean} (true if ready, false if not)
*/
SerialPort.prototype.isTransmitterReady = function()
SerialPort8080.prototype.isTransmitterReady = function()
{
return !!(this.bStatus & SerialPort.UART8251.STATUS.XMIT_READY);
return !!(this.bStatus & SerialPort8080.UART8251.STATUS.XMIT_READY);
};
/**
* inData(port, addrFrom)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} port (0x0)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inData = function(port, addrFrom)
SerialPort8080.prototype.inData = function(port, addrFrom)
{
var b = this.bDataIn;
this.printMessageIO(port, null, addrFrom, "DATA", b);
this.bStatus &= ~SerialPort.UART8251.STATUS.RECV_FULL;
this.bStatus &= ~SerialPort8080.UART8251.STATUS.RECV_FULL;
return b;
};
/**
* inControl(port, addrFrom)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} port (0x1)
* @param {number} [addrFrom] (not defined whenever the Debugger tries to read the specified port)
* @return {number} simulated port value
*/
SerialPort.prototype.inControl = function(port, addrFrom)
SerialPort8080.prototype.inControl = function(port, addrFrom)
{
var b = this.bStatus;
this.printMessageIO(port, null, addrFrom, "STATUS", b);
@ -721,22 +778,22 @@ SerialPort.prototype.inControl = function(port, addrFrom)
/**
* outData(port, bOut, addrFrom)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} port (0x0)
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outData = function(port, bOut, addrFrom)
SerialPort8080.prototype.outData = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, "DATA");
this.bDataOut = bOut;
this.bStatus &= ~(SerialPort.UART8251.STATUS.XMIT_READY | SerialPort.UART8251.STATUS.XMIT_EMPTY);
this.bStatus &= ~(SerialPort8080.UART8251.STATUS.XMIT_READY | SerialPort8080.UART8251.STATUS.XMIT_EMPTY);
/*
* If we're transmitting to a virtual device that has no measurable delay, this code may clear XMIT_READY
* too quickly.
*
* if (this.transmitByte(bOut)) {
* this.bStatus |= (SerialPort.UART8251.STATUS.XMIT_READY | SerialPort.UART8251.STATUS.XMIT_EMPTY);
* this.bStatus |= (SerialPort8080.UART8251.STATUS.XMIT_READY | SerialPort8080.UART8251.STATUS.XMIT_EMPTY);
* }
*
* A better solution is to arm a timer based on the XMIT_RATE baud rate, and clear the above bits when that
@ -744,7 +801,7 @@ SerialPort.prototype.outData = function(port, bOut, addrFrom)
*/
this.transmitByte(bOut);
if (this.cpu) {
this.cpu.setTimer(this.timerTransmitNext, this.getBaudTimeout(SerialPort.UART8251.BAUDRATES.XMIT_RATE));
this.cpu.setTimer(this.timerTransmitNext, this.getBaudTimeout(SerialPort8080.UART8251.BAUDRATES.XMIT_RATE));
}
};
@ -756,12 +813,12 @@ SerialPort.prototype.outData = function(port, bOut, addrFrom)
* has received that initial byte, the device is marked "ready", and all further bytes are
* interpreted as COMMAND bytes (until/unless a COMMAND byte with the INTERNAL_RESET bit is set).
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} port (0x1)
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outControl = function(port, bOut, addrFrom)
SerialPort8080.prototype.outControl = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, "CONTROL");
if (!this.fReady) {
@ -769,7 +826,7 @@ SerialPort.prototype.outControl = function(port, bOut, addrFrom)
this.fReady = true;
} else {
this.bCommand = bOut;
if (this.bCommand & SerialPort.UART8251.COMMAND.INTERNAL_RESET) {
if (this.bCommand & SerialPort8080.UART8251.COMMAND.INTERNAL_RESET) {
this.fReady = false;
}
}
@ -778,12 +835,12 @@ SerialPort.prototype.outControl = function(port, bOut, addrFrom)
/**
* outBaudRates(port, bOut, addrFrom)
*
* @this {SerialPort}
* @this {SerialPort8080}
* @param {number} port (0x2)
* @param {number} bOut
* @param {number} [addrFrom] (not defined whenever the Debugger tries to write the specified port)
*/
SerialPort.prototype.outBaudRates = function(port, bOut, addrFrom)
SerialPort8080.prototype.outBaudRates = function(port, bOut, addrFrom)
{
this.printMessageIO(port, bOut, addrFrom, "BAUDRATES");
this.bBaudRates = bOut;
@ -792,43 +849,43 @@ SerialPort.prototype.outBaudRates = function(port, bOut, addrFrom)
/*
* Port input notification table
*/
SerialPort.aPortInput = {
0x0: SerialPort.prototype.inData,
0x1: SerialPort.prototype.inControl
SerialPort8080.aPortInput = {
0x0: SerialPort8080.prototype.inData,
0x1: SerialPort8080.prototype.inControl
};
/*
* Port output notification table
*/
SerialPort.aPortOutput = {
0x0: SerialPort.prototype.outData,
0x1: SerialPort.prototype.outControl,
0x2: SerialPort.prototype.outBaudRates
SerialPort8080.aPortOutput = {
0x0: SerialPort8080.prototype.outData,
0x1: SerialPort8080.prototype.outControl,
0x2: SerialPort8080.prototype.outBaudRates
};
/**
* SerialPort.init()
* SerialPort8080.init()
*
* This function operates on every HTML element of class "serial", extracting the
* JSON-encoded parameters for the SerialPort constructor from the element's "data-value"
* attribute, invoking the constructor to create a SerialPort component, and then binding
* JSON-encoded parameters for the SerialPort8080 constructor from the element's "data-value"
* attribute, invoking the constructor to create a SerialPort8080 component, and then binding
* any associated HTML controls to the new component.
*/
SerialPort.init = function()
SerialPort8080.init = function()
{
var aeSerial = Component.getElementsByClass(document, PC8080.APPCLASS, "serial");
for (var iSerial = 0; iSerial < aeSerial.length; iSerial++) {
var eSerial = aeSerial[iSerial];
var parmsSerial = Component.getComponentParms(eSerial);
var serial = new SerialPort(parmsSerial);
var serial = new SerialPort8080(parmsSerial);
Component.bindComponentControls(serial, eSerial, PC8080.APPCLASS);
}
};
/*
* Initialize every SerialPort module on the page.
* Initialize every SerialPort8080 module on the page.
*/
web.onInit(SerialPort.init);
web.onInit(SerialPort8080.init);
if (NODE) module.exports = SerialPort;
if (NODE) module.exports = SerialPort8080;

View file

@ -1,396 +0,0 @@
/**
* @fileoverview The State class used by PCjs machines.
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
* @version 1.0
* Created 2016-Apr-19
*
* Copyright © 2012-2016 Jeff Parsons <Jeff@pcjs.org>
*
* This file is part of PCjs, a computer emulation software project at <http://pcjs.org/>.
*
* PCjs is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* PCjs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with PCjs. If not,
* see <http://www.gnu.org/licenses/gpl.html>.
*
* You are required to include the above copyright notice in every source code file of every
* copy or modified version of this work, and to display that copyright notice on every screen
* that loads or runs any version of this software (see COPYRIGHT in /modules/shared/lib/defines.js).
*
* Some PCjs files also attempt to load external resource files, such as character-image files,
* ROM files, and disk image files. Those external resource files are not considered part of PCjs
* for purposes of the GNU General Public License, and the author does not claim any copyright
* as to their contents.
*/
"use strict";
if (NODE) {
var web = require("./../../shared/lib/weblib");
var Component = require("./../../shared/lib/component");
var Messages = require("./messages");
}
/**
* State(component, sVersion, sSuffix)
*
* State objects are used by components to save/restore their state.
*
* During a save operation, components add data to a State object via set(),
* and then return the resulting data using data().
*
* During a restore operation, the Computer component passes the results of each
* data() call back to the originating component.
*
* WARNING: Since State objects are low-level objects that have no UI requirements,
* they do not inherit from the Component class, so you should only use class methods
* of Component, such as Component.assert(), or Debugger methods if the Debugger
* is available.
*
* @constructor
* @param {Component} component
* @param {string} [sVersion] is used to append a major version number to the key
* @param {string} [sSuffix] is used to append any additional suffixes to the key
*/
function State(component, sVersion, sSuffix) {
this.id = component.id;
this.key = State.key(component, sVersion, sSuffix);
this.dbg = component.dbg;
this.unload(component.parms);
}
/**
* State.key(component, sVersion, sSuffix)
*
* This encapsulates the key generation code.
*
* @param {Component} component
* @param {string} [sVersion] is used to append a major version number to the key
* @param {string} [sSuffix] is used to append any additional suffixes to the key
* @return {string} key
*/
State.key = function(component, sVersion, sSuffix) {
var key = component.id;
if (sVersion) {
var i = sVersion.indexOf('.');
if (i > 0) key += ".v" + sVersion.substr(0, i);
}
if (sSuffix) {
key += "." + sSuffix;
}
return key;
};
/**
* State.compress(aSrc)
*
* @param {Array.<number>|null} aSrc
* @return {Array.<number>|null} is either the original array (aSrc), or a smaller array of "count, value" pairs (aComp)
*/
State.compress = function(aSrc) {
if (aSrc) {
var iSrc = 0;
var iComp = 0;
var aComp = [];
while (iSrc < aSrc.length) {
var n = aSrc[iSrc];
Component.assert(n !== undefined);
var iCompare = iSrc + 1;
while (iCompare < aSrc.length && aSrc[iCompare] === n) iCompare++;
aComp[iComp++] = iCompare - iSrc;
aComp[iComp++] = n;
iSrc = iCompare;
}
if (aComp.length < aSrc.length) return aComp;
}
return aSrc;
};
/**
* State.decompress(aComp)
*
* @param {Array.<number>} aComp
* @param {number} nLength is expected length of decompressed data
* @return {Array.<number>}
*/
State.decompress = function(aComp, nLength) {
var iDst = 0;
var aDst = new Array(nLength);
var iComp = 0;
while (iComp < aComp.length - 1) {
var c = aComp[iComp++];
var n = aComp[iComp++];
while (c--) {
aDst[iDst++] = n;
}
}
Component.assert(aDst.length == nLength);
return aDst;
};
/**
* State.compressEvenOdd(aSrc)
*
* This is a very simple variation on compress() that compresses all the EVEN elements of aSrc first,
* followed by all the ODD elements. This tends to work better on EGA video memory, because when odd/even
* addressing is enabled (eg, for text modes), the DWORD values tend to alternate, which is the worst case
* for compress(), but the best case for compressEvenOdd().
*
* One wrinkle we support: if the first element is uninitialized, then we assume the entire array is undefined,
* and return an empty compressed array. Conversely, decompressEvenOdd() will take an empty compressed array
* and return an uninitialized array.
*
* @param {Array.<number>|null} aSrc
* @return {Array.<number>|null} is either the original array (aSrc), or a smaller array of "count, value" pairs (aComp)
*/
State.compressEvenOdd = function(aSrc) {
if (aSrc) {
var iComp = 0, aComp = [];
if (aSrc[0] !== undefined) {
for (var off = 0; off < 2; off++) {
var iSrc = off;
while (iSrc < aSrc.length) {
var n = aSrc[iSrc];
var iCompare = iSrc + 2;
while (iCompare < aSrc.length && aSrc[iCompare] === n) iCompare += 2;
aComp[iComp++] = (iCompare - iSrc) >> 1;
aComp[iComp++] = n;
iSrc = iCompare;
}
}
}
if (aComp.length < aSrc.length) return aComp;
}
return aSrc;
};
/**
* State.decompressEvenOdd(aComp, nLength)
*
* This is the counterpart to compressEvenOdd(). Note that because there's nothing in the compressed sequence
* that differentiates a compress() sequence from a compressEvenOdd() sequence, you simply have to be consistent:
* if you used even/odd compression, then you must use even/odd decompression.
*
* @param {Array.<number>} aComp
* @param {number} nLength is expected length of decompressed data
* @return {Array.<number>}
*/
State.decompressEvenOdd = function(aComp, nLength) {
var iDst = 0;
var aDst = new Array(nLength);
var iComp = 0;
while (iComp < aComp.length - 1) {
var c = aComp[iComp++];
var n = aComp[iComp++];
while (c--) {
aDst[iDst] = n;
iDst += 2;
}
/*
* The output of a "count,value" pair will never exceed the end of the output array, so as soon as we reach it
* the first time, we know it's time to switch to ODD elements, and as soon as we reach it again, we should be
* done.
*/
Component.assert(iDst <= nLength || iComp == aComp.length);
if (iDst == nLength) iDst = 1;
}
Component.assert(aDst.length == nLength);
return aDst;
};
State.prototype = {
constructor: State,
/**
* set(id, data)
*
* @this {State}
* @param {number|string} id
* @param {Object|string} data
*/
set: function(id, data) {
try {
this[this.id][id] = data;
} catch(e) {
Component.log(e.message);
}
},
/**
* get(id)
*
* @this {State}
* @param {number|string} id
* @return {Object|string|null}
*/
get: function(id) {
return this[this.id][id] || null;
},
/**
* value()
*
* Use this instead of data() if you haven't called parse() yet.
*
* @this {State}
* @return {string}
*/
value: function() {
return this[this.id];
},
/**
* data()
*
* @this {State}
* @return {Object}
*/
data: function() {
return this[this.id];
},
/**
* load(s)
*
* WARNING: Make sure you follow this call with either a call to parse() or unload(),
* because any stringified data that we've loaded isn't usable until it's been parsed.
*
* @this {State}
* @param {Object|string|null} [s]
* @return {boolean} true if state exists in localStorage, false if not
*/
load: function(s) {
if (s) {
this[this.id] = s;
this.fLoaded = true;
return true;
}
if (this.fLoaded) {
/*
* This is assumed to be a redundant load().
*/
return true;
}
if (web.hasLocalStorage()) {
s = web.getLocalStorageItem(this.key);
if (s) {
this[this.id] = s;
this.fLoaded = true;
if (DEBUG) this.printString("localStorage(" + this.key + "): " + s.length + " bytes loaded");
return true;
}
}
return false;
},
/**
* parse()
*
* This completes the load() operation, by parsing what was loaded, on the assumption there
* might be some benefit to deferring parsing until we've given the user a chance to confirm.
* Otherwise, load() could have just as easily done this, too.
*
* @this {State}
* @return {boolean} true if successful, false if error
*/
parse: function() {
var fSuccess = true;
try {
this[this.id] = JSON.parse(this[this.id]);
} catch (e) {
Component.error(e.message || e);
fSuccess = false;
}
return fSuccess;
},
/**
* store()
*
* @this {State}
* @return {boolean} true if successful, false if error
*/
store: function() {
var fSuccess = true;
if (web.hasLocalStorage()) {
var s = JSON.stringify(this[this.id]);
if (web.setLocalStorageItem(this.key, s)) {
if (DEBUG) this.printString("localStorage(" + this.key + "): " + s.length + " bytes stored");
} else {
/*
* WARNING: Because browsers tend to disable all alerts() during an "unload" operation,
* it's unlikely anyone will ever see the "quota" errors that occur at this point. Need to
* think of some way to notify the user that there's a problem, and offer a way of cleaning
* up old states.
*/
Component.error("Unable to store " + s.length + " bytes in browser local storage");
fSuccess = false;
}
}
return fSuccess;
},
/**
* toString()
*
* We can't know whether this might be called before parse() or after parse(), so we check.
* If before, then this[this.id] will still be in string form; if after, it will be an Object.
*
* @this {State}
* @return {string} JSON-encoded state
*/
toString: function() {
var value = this[this.id];
return (typeof value == "string"? value : JSON.stringify(value));
},
/**
* unload(parms)
*
* This discards any data saved via set() or loaded via load(), creating an empty State object.
* Note that you have to follow this call with an explicit call to store() if you want to remove
* the state from localStorage as well.
*
* @this {State}
* @param {Object} [parms]
*/
unload: function(parms) {
this[this.id] = {};
if (parms) this.set("parms", parms);
this.fLoaded = false;
},
/**
* clear(fAll)
*
* This unloads the current state, and then clears ALL localStorage for the current machine,
* independent of version, to reduce the chance of orphaned states wasting part of our limited allocation.
*
* @this {State}
* @param {boolean} [fAll] true to unconditionally clear ALL localStorage for the current domain
*/
clear: function(fAll) {
this.unload();
var aKeys = web.getLocalStorageKeys();
for (var i = 0; i < aKeys.length; i++) {
var sKey = aKeys[i];
if (sKey && (fAll || sKey.substr(0, this.key.length) == this.key)) {
web.removeLocalStorageItem(sKey);
if (DEBUG) this.printString("localStorage(" + sKey + ") removed");
aKeys.splice(i, 1);
i = 0;
}
}
},
/**
* printString(s)
*
* @this {State}
* @param {string} s is any caller-defined string
*/
printString: function(s) {
if (DEBUG && DEBUGGER && this.dbg) {
if (this.dbg.messageEnabled(Messages.LOG)) {
this.dbg.message(s);
}
}
}
};
if (NODE) module.exports = State;

View file

@ -36,16 +36,16 @@ if (NODE) {
var web = require("../../shared/lib/weblib");
var DumpAPI = require("../../shared/lib/dumpapi");
var Component = require("../../shared/lib/component");
var ChipSet = require("./chipset");
var Memory = require("./memory");
var Messages = require("./messages");
var State = require("./state");
var State = require("../../shared/lib/state");
var ChipSet8080 = require("./chipset");
var Memory8080 = require("./memory");
var Messages8080= require("./messages");
}
/**
* Video(parmsVideo, canvas, context, textarea, container)
* Video8080(parmsVideo, canvas, context, textarea, container)
*
* The Video component can be configured with the following (parmsVideo) properties:
* The Video8080 component can be configured with the following (parmsVideo) properties:
*
* screenWidth: width of the screen canvas, in pixels
* screenHeight: height of the screen canvas, in pixels
@ -54,7 +54,7 @@ if (NODE) {
* aspectRatio (eg, 1.33)
* bufferAddr: the starting address of the frame buffer (eg, 0x2400)
* bufferRAM: true to use existing RAM (default is false)
* bufferFormat: if defined, one of the recognized formats in Video.FORMATS (eg, "vt100")
* bufferFormat: if defined, one of the recognized formats in Video8080.FORMATS (eg, "vt100")
* bufferCols: the width of a single frame buffer row, in pixels (eg, 256)
* bufferRows: the number of frame buffer rows (eg, 224)
* bufferBits: the number of bits per column (default is 1)
@ -94,13 +94,13 @@ if (NODE) {
* @param {Object} [textarea]
* @param {Object} [container]
*/
function Video(parmsVideo, canvas, context, textarea, container)
function Video8080(parmsVideo, canvas, context, textarea, container)
{
var video = this;
this.fGecko = web.isUserAgent("Gecko/");
var i, sEvent, asWebPrefixes = ['', 'moz', 'ms', 'webkit'];
Component.call(this, "Video", parmsVideo, Video, Messages.VIDEO);
Component.call(this, "Video", parmsVideo, Video8080, Messages8080.VIDEO);
this.cxScreen = parmsVideo['screenWidth'];
this.cyScreen = parmsVideo['screenHeight'];
@ -109,7 +109,7 @@ function Video(parmsVideo, canvas, context, textarea, container)
this.fUseRAM = parmsVideo['bufferRAM'];
var sFormat = parmsVideo['bufferFormat'];
this.nFormat = sFormat && Video.FORMATS[sFormat.toUpperCase()] || Video.FORMAT.UNKNOWN;
this.nFormat = sFormat && Video8080.FORMATS[sFormat.toUpperCase()] || Video8080.FORMAT.UNKNOWN;
this.nColsBuffer = parmsVideo['bufferCols'];
this.nRowsBuffer = parmsVideo['bufferRows'];
@ -252,27 +252,27 @@ function Video(parmsVideo, canvas, context, textarea, container)
if (DEBUG) this.nCyclesPrev = 0;
}
Component.subclass(Video);
Component.subclass(Video8080);
Video.COLORS = {
Video8080.COLORS = {
OVERLAY_TOP: 0,
OVERLAY_BOTTOM: 1,
OVERLAY_TOTAL: 2
};
Video.FORMAT = {
Video8080.FORMAT = {
UNKNOWN: 0,
SI1978: 1,
VT100: 2
};
Video.FORMATS = {
"SI1978": Video.FORMAT.SI1978,
"VT100": Video.FORMAT.VT100
Video8080.FORMATS = {
"SI1978": Video8080.FORMAT.SI1978,
"VT100": Video8080.FORMAT.VT100
};
Video.VT100 = {
Video8080.VT100 = {
/*
* The following font IDs are nothing more than all the possible LINEATTR values masked with FONTMASK;
* also, note that double-high implies double-wide; the VT100 doesn't support a double-high single-wide font.
@ -297,10 +297,10 @@ Video.VT100 = {
/**
* initBuffers()
*
* @this {Video}
* @this {Video8080}
* @return {boolean}
*/
Video.prototype.initBuffers = function()
Video8080.prototype.initBuffers = function()
{
/*
* Allocate off-screen buffers now
@ -318,7 +318,7 @@ Video.prototype.initBuffers = function()
this.sizeBuffer = 0;
if (!this.fUseRAM) {
this.sizeBuffer = ((this.cxBuffer * this.nBitsPerPixel) >> 3) * this.cyBuffer;
if (!this.bus.addMemory(this.addrBuffer, this.sizeBuffer, Memory.TYPE.VIDEO)) {
if (!this.bus.addMemory(this.addrBuffer, this.sizeBuffer, Memory8080.TYPE.VIDEO)) {
return false;
}
}
@ -346,7 +346,7 @@ Video.prototype.initBuffers = function()
this.aFonts = {};
this.initColors();
if (this.nFormat == Video.FORMAT.VT100) {
if (this.nFormat == Video8080.FORMAT.VT100) {
/*
* Beyond fonts, VT100 support requires that we maintain a number of additional properties:
*
@ -397,13 +397,13 @@ Video.prototype.initBuffers = function()
/**
* initBus(cmp, bus, cpu, dbg)
*
* @this {Video}
* @param {Computer} cmp
* @param {Bus} bus
* @param {CPUState} cpu
* @param {Debugger} dbg
* @this {Video8080}
* @param {Computer8080} cmp
* @param {Bus8080} bus
* @param {CPUState8080} cpu
* @param {Debugger8080} dbg
*/
Video.prototype.initBus = function(cmp, bus, cpu, dbg)
Video8080.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.bus = bus;
@ -419,7 +419,7 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
* If we have an associated keyboard, then ensure that the keyboard will be notified
* whenever the canvas gets focus and receives input.
*/
this.kbd = /** @type {Keyboard} */ (cmp.getMachineComponent("Keyboard"));
this.kbd = /** @type {Keyboard8080} */ (cmp.getMachineComponent("Keyboard"));
if (this.kbd) {
for (var s in this.ledBindings) {
this.kbd.setBinding("led", s, this.ledBindings[s]);
@ -435,12 +435,12 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
/**
* doneLoad(sURL, sFontData, nErrorCode)
*
* @this {Video}
* @this {Video8080}
* @param {string} sURL
* @param {string} sFontData
* @param {number} nErrorCode (response from server if anything other than 200)
*/
Video.prototype.doneLoad = function(sURL, sFontData, nErrorCode)
Video8080.prototype.doneLoad = function(sURL, sFontData, nErrorCode)
{
if (nErrorCode) {
this.notice("Unable to load font ROM (error " + nErrorCode + ": " + sURL + ")");
@ -496,25 +496,25 @@ Video.prototype.doneLoad = function(sURL, sFontData, nErrorCode)
/**
* createFonts()
*
* @this {Video}
* @this {Video8080}
* @return {boolean}
*/
Video.prototype.createFonts = function()
Video8080.prototype.createFonts = function()
{
/*
* We retain abFontData in case we have to rebuild the fonts (eg, when we switch from 80 to 132 columns)
*/
if (this.abFontData) {
this.fDotStretcher = (this.nFormat == Video.FORMAT.VT100);
this.aFonts[Video.VT100.FONT.NORML] = [
this.fDotStretcher = (this.nFormat == Video8080.FORMAT.VT100);
this.aFonts[Video8080.VT100.FONT.NORML] = [
this.createFontVariation(this.cxCell, this.cyCell),
this.createFontVariation(this.cxCell, this.cyCell, this.fUnderline)
];
this.aFonts[Video.VT100.FONT.DWIDE] = [
this.aFonts[Video8080.VT100.FONT.DWIDE] = [
this.createFontVariation(this.cxCell*2, this.cyCell),
this.createFontVariation(this.cxCell*2, this.cyCell, this.fUnderline)
];
this.aFonts[Video.VT100.FONT.DHIGH] = this.aFonts[Video.VT100.FONT.DHIGH_BOT] = [
this.aFonts[Video8080.VT100.FONT.DHIGH] = this.aFonts[Video8080.VT100.FONT.DHIGH_BOT] = [
this.createFontVariation(this.cxCell*2, this.cyCell*2),
this.createFontVariation(this.cxCell*2, this.cyCell*2, this.fUnderline)
];
@ -533,13 +533,13 @@ Video.prototype.createFonts = function()
* 3) double-high double-wide characters (cell size is this.cxCell*2 x this.cyCell*2)
* 4) any of the above with either reverse video or underline enabled (default is neither)
*
* @this {Video}
* @this {Video8080}
* @param {number} cxCell is the target width of each character in the grid
* @param {number} cyCell is the target height of each character in the grid
* @param {boolean} [fUnderline] (null for unmodified font, false for reverse video, true for underline)
* @return {Object}
*/
Video.prototype.createFontVariation = function(cxCell, cyCell, fUnderline)
Video8080.prototype.createFontVariation = function(cxCell, cyCell, fUnderline)
{
/*
* On a VT100, cxCell,cyCell is initially 10,10, but may change to 9,10 for 132-column mode.
@ -606,12 +606,12 @@ Video.prototype.createFontVariation = function(cxCell, cyCell, fUnderline)
/**
* powerUp(data, fRepower)
*
* @this {Video}
* @this {Video8080}
* @param {Object|null} data
* @param {boolean} [fRepower]
* @return {boolean} true if successful, false if failure
*/
Video.prototype.powerUp = function(data, fRepower)
Video8080.prototype.powerUp = function(data, fRepower)
{
/*
* Because the VT100 frame buffer can be located anywhere in RAM (above 0x2000), we must defer this
@ -619,7 +619,7 @@ Video.prototype.powerUp = function(data, fRepower)
*
* TODO: Remove this display test code once the VT100 is fully operational.
*/
if (this.nFormat == Video.FORMAT.VT100) {
if (this.nFormat == Video8080.FORMAT.VT100) {
/*
* Build a test screen in the VT100 frame buffer; we'll mimic the "SET-UP A" screen, since it uses
* all the font variations. The process involves iterating over 0-based row numbers -2 (or -5 if 50Hz
@ -629,10 +629,10 @@ Video.prototype.powerUp = function(data, fRepower)
* default character attribute for subsequent strings. An empty array ends the screen build process.
*/
var aLineData = {
0: [Video.VT100.FONT.DHIGH, 'SET-UP A'],
2: [Video.VT100.FONT.DWIDE, 'TO EXIT PRESS "SET-UP"'],
22: [Video.VT100.FONT.NORML, ' T T T T T T T T T'],
23: [Video.VT100.FONT.NORML, '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890'],
0: [Video8080.VT100.FONT.DHIGH, 'SET-UP A'],
2: [Video8080.VT100.FONT.DWIDE, 'TO EXIT PRESS "SET-UP"'],
22: [Video8080.VT100.FONT.NORML, ' T T T T T T T T T'],
23: [Video8080.VT100.FONT.NORML, '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890', '1234567890'],
24: []
};
var addr = this.addrBuffer;
@ -644,9 +644,9 @@ Video.prototype.powerUp = function(data, fRepower)
var fBreak = false;
addrNext = addr + 2;
if (!lineData) {
if (font == Video.VT100.FONT.DHIGH) {
if (font == Video8080.VT100.FONT.DHIGH) {
lineData = aLineData[iRow-1];
font = Video.VT100.FONT.DHIGH_BOT;
font = Video8080.VT100.FONT.DHIGH_BOT;
}
}
else {
@ -657,7 +657,7 @@ Video.prototype.powerUp = function(data, fRepower)
fBreak = true;
}
}
b = (font & Video.VT100.LINEATTR.FONTMASK) | ((addrNext >> 8) & Video.VT100.LINEATTR.ADDRMASK) | Video.VT100.LINEATTR.ADDRBIAS;
b = (font & Video8080.VT100.LINEATTR.FONTMASK) | ((addrNext >> 8) & Video8080.VT100.LINEATTR.ADDRMASK) | Video8080.VT100.LINEATTR.ADDRBIAS;
this.bus.setByteDirect(addr++, b);
this.bus.setByteDirect(addr++, addrNext & 0xff);
if (fBreak) break;
@ -672,7 +672,7 @@ Video.prototype.powerUp = function(data, fRepower)
attr ^= 0x80;
}
}
this.bus.setByteDirect(addr++, Video.VT100.LINETERM);
this.bus.setByteDirect(addr++, Video8080.VT100.LINETERM);
addrNext = addr;
}
/*
@ -686,14 +686,14 @@ Video.prototype.powerUp = function(data, fRepower)
/**
* setBinding(sHTMLType, sBinding, control, sValue)
*
* @this {Video}
* @this {Video8080}
* @param {string|null} sHTMLType is the type of the HTML control (eg, "button", "list", "text", "submit", "textarea", "canvas")
* @param {string} sBinding is the value of the 'binding' parameter stored in the HTML control's "data-value" attribute (eg, "refresh")
* @param {Object} control is the HTML control DOM object (eg, HTMLButtonElement)
* @param {string} [sValue] optional data value
* @return {boolean} true if binding was successful, false if unrecognized binding request
*/
Video.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
Video8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
{
var video = this;
@ -730,11 +730,11 @@ Video.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
*
* Called from the ChipSet component whenever the screen dimensions have been dynamically altered.
*
* @this {Video}
* @this {Video8080}
* @param {number} nCols (should be either 80 or 132; 80 is the default)
* @param {number} nRows (should be either 24 or 14; 24 is the default)
*/
Video.prototype.updateDimensions = function(nCols, nRows)
Video8080.prototype.updateDimensions = function(nCols, nRows)
{
this.printMessage("updateDimensions(" + nCols + "," + nRows + ")");
this.nColsBuffer = nCols;
@ -757,10 +757,10 @@ Video.prototype.updateDimensions = function(nCols, nRows)
*
* Called from the ChipSet component whenever the monitor refresh rate has been dynamically altered.
*
* @this {Video}
* @this {Video8080}
* @param {number} nRate (should be either 50 or 60; 60 is the default)
*/
Video.prototype.updateRate = function(nRate)
Video8080.prototype.updateRate = function(nRate)
{
this.printMessage("updateRate(" + nRate + ")");
this.rateMonitor = nRate;
@ -771,10 +771,10 @@ Video.prototype.updateRate = function(nRate)
*
* Called from the ChipSet component whenever the screen scroll offset has been dynamically altered.
*
* @this {Video}
* @this {Video8080}
* @param {number} bScroll
*/
Video.prototype.updateScrollOffset = function(bScroll)
Video8080.prototype.updateScrollOffset = function(bScroll)
{
this.printMessage("updateScrollOffset(" + bScroll + ")");
if (this.bScrollOffset !== bScroll) {
@ -805,10 +805,10 @@ Video.prototype.updateScrollOffset = function(bScroll)
/**
* doFullScreen()
*
* @this {Video}
* @this {Video8080}
* @return {boolean} true if request successful, false if not (eg, failed OR not supported)
*/
Video.prototype.doFullScreen = function()
Video8080.prototype.doFullScreen = function()
{
var fSuccess = false;
if (this.container) {
@ -874,10 +874,10 @@ Video.prototype.doFullScreen = function()
/**
* notifyFullScreen(fFullScreen)
*
* @this {Video}
* @this {Video8080}
* @param {boolean|null} fFullScreen (null if there was a full-screen error)
*/
Video.prototype.notifyFullScreen = function(fFullScreen)
Video8080.prototype.notifyFullScreen = function(fFullScreen)
{
if (!fFullScreen && this.container) {
if (!this.fGecko) {
@ -892,9 +892,9 @@ Video.prototype.notifyFullScreen = function(fFullScreen)
/**
* setFocus()
*
* @this {Video}
* @this {Video8080}
*/
Video.prototype.setFocus = function()
Video8080.prototype.setFocus = function()
{
if (this.inputScreen) this.inputScreen.focus();
};
@ -902,10 +902,10 @@ Video.prototype.setFocus = function()
/**
* getRefreshRate()
*
* @this {Video}
* @this {Video8080}
* @return {number}
*/
Video.prototype.getRefreshRate = function()
Video8080.prototype.getRefreshRate = function()
{
return Math.max(this.rateRefresh, this.rateInterrupt);
};
@ -915,10 +915,10 @@ Video.prototype.getRefreshRate = function()
*
* Initializes the contents of our internal cell cache.
*
* @this {Video}
* @this {Video8080}
* @param {number} nCells
*/
Video.prototype.initCellCache = function(nCells)
Video8080.prototype.initCellCache = function(nCells)
{
this.nCellCache = nCells;
this.fCellCacheValid = false;
@ -932,35 +932,35 @@ Video.prototype.initCellCache = function(nCells)
*
* This creates an array of nColors, with additional OVERLAY_TOTAL colors tacked on to the end of the array.
*
* @this {Video}
* @this {Video8080}
*/
Video.prototype.initColors = function()
Video8080.prototype.initColors = function()
{
var rgbBlack = [0x00, 0x00, 0x00, 0xff];
var rgbWhite = [0xff, 0xff, 0xff, 0xff];
this.nColors = (1 << this.nBitsPerPixel);
this.aRGB = new Array(this.nColors + Video.COLORS.OVERLAY_TOTAL);
this.aRGB = new Array(this.nColors + Video8080.COLORS.OVERLAY_TOTAL);
this.aRGB[0] = rgbBlack;
this.aRGB[1] = rgbWhite;
if (this.nFormat == Video.FORMAT.SI1978) {
if (this.nFormat == Video8080.FORMAT.SI1978) {
var rgbGreen = [0x00, 0xff, 0x00, 0xff];
//noinspection UnnecessaryLocalVariableJS
var rgbYellow = [0xff, 0xff, 0x00, 0xff];
this.aRGB[this.nColors + Video.COLORS.OVERLAY_TOP] = rgbYellow;
this.aRGB[this.nColors + Video.COLORS.OVERLAY_BOTTOM] = rgbGreen;
this.aRGB[this.nColors + Video8080.COLORS.OVERLAY_TOP] = rgbYellow;
this.aRGB[this.nColors + Video8080.COLORS.OVERLAY_BOTTOM] = rgbGreen;
}
};
/**
* setPixel(image, x, y, bPixel)
*
* @this {Video}
* @this {Video8080}
* @param {Object} image
* @param {number} x
* @param {number} y
* @param {number} bPixel (ie, an index into aRGB)
*/
Video.prototype.setPixel = function(image, x, y, bPixel)
Video8080.prototype.setPixel = function(image, x, y, bPixel)
{
var index;
if (!this.rotateBuffer) {
@ -968,12 +968,12 @@ Video.prototype.setPixel = function(image, x, y, bPixel)
} else {
index = (image.height - x - 1) * image.width + y;
}
if (bPixel && this.nFormat == Video.FORMAT.SI1978) {
if (bPixel && this.nFormat == Video8080.FORMAT.SI1978) {
if (x >= 208 && x < 236) {
bPixel = this.nColors + Video.COLORS.OVERLAY_TOP;
bPixel = this.nColors + Video8080.COLORS.OVERLAY_TOP;
}
else if (x >= 28 && x < 72) {
bPixel = this.nColors + Video.COLORS.OVERLAY_BOTTOM;
bPixel = this.nColors + Video8080.COLORS.OVERLAY_BOTTOM;
}
}
var rgb = this.aRGB[bPixel];
@ -989,14 +989,14 @@ Video.prototype.setPixel = function(image, x, y, bPixel)
*
* Updates a particular character cell (row,col) in the associated window.
*
* @this {Video}
* @this {Video8080}
* @param {number} idFont
* @param {number} col
* @param {number} row
* @param {number} data
* @param {Object} [context]
*/
Video.prototype.updateChar = function(idFont, col, row, data, context)
Video8080.prototype.updateChar = function(idFont, col, row, data, context)
{
var bChar = data & 0x7f;
var font = this.aFonts[idFont][(data & 0x80)? 1 : 0];
@ -1037,7 +1037,7 @@ Video.prototype.updateChar = function(idFont, col, row, data, context)
* of the character should be drawn.
*/
if (font.cyCell > this.cyCell) {
if (idFont == Video.VT100.FONT.DHIGH_BOT) ySrc += this.cyCell;
if (idFont == Video8080.VT100.FONT.DHIGH_BOT) ySrc += this.cyCell;
cySrc = this.cyCell;
this.assert(font.cyCell == this.cyCell * 2);
}
@ -1054,10 +1054,10 @@ Video.prototype.updateChar = function(idFont, col, row, data, context)
/**
* updateVT100(fForced)
*
* @this {Video}
* @this {Video8080}
* @param {boolean} [fForced]
*/
Video.prototype.updateVT100 = function(fForced)
Video8080.prototype.updateVT100 = function(fForced)
{
var addrNext = this.addrBuffer, fontNext = -1;
@ -1075,14 +1075,14 @@ Video.prototype.updateVT100 = function(fForced)
var addr = addrNext;
var font = fontNext;
var nColsVisible = this.nColsBuffer;
if (font != Video.VT100.FONT.NORML) nColsVisible >>= 1;
if (font != Video8080.VT100.FONT.NORML) nColsVisible >>= 1;
while (true) {
var data = this.bus.getByteDirect(addr++);
if ((data & Video.VT100.LINETERM) == Video.VT100.LINETERM) {
if ((data & Video8080.VT100.LINETERM) == Video8080.VT100.LINETERM) {
var b = this.bus.getByteDirect(addr++);
fontNext = b & Video.VT100.LINEATTR.FONTMASK;
addrNext = ((b & Video.VT100.LINEATTR.ADDRMASK) << 8) | this.bus.getByteDirect(addr);
addrNext += (b & Video.VT100.LINEATTR.ADDRBIAS)? Video.VT100.ADDRBIAS_LO : Video.VT100.ADDRBIAS_HI;
fontNext = b & Video8080.VT100.LINEATTR.FONTMASK;
addrNext = ((b & Video8080.VT100.LINEATTR.ADDRMASK) << 8) | this.bus.getByteDirect(addr);
addrNext += (b & Video8080.VT100.LINEATTR.ADDRBIAS)? Video8080.VT100.ADDRBIAS_LO : Video8080.VT100.ADDRBIAS_HI;
break;
}
if (nCols < nColsVisible) {
@ -1192,10 +1192,10 @@ Video.prototype.updateVT100 = function(fForced)
* and then update the cell cache to match. Since initCellCache() sets every cell in the cell cache to an
* invalid value, we're assured that the next call to updateScreen() will redraw the entire (visible) video buffer.
*
* @this {Video}
* @this {Video8080}
* @param {number} n (where 0 <= n < getRefreshRate() for a normal update, or -1 for a forced update)
*/
Video.prototype.updateScreen = function(n)
Video8080.prototype.updateScreen = function(n)
{
var fClean;
var fUpdate = true;
@ -1259,13 +1259,13 @@ Video.prototype.updateScreen = function(n)
/**
* updateScreenText(fForced)
*
* @this {Video}
* @this {Video8080}
* @param {boolean} [fForced]
*/
Video.prototype.updateScreenText = function(fForced)
Video8080.prototype.updateScreenText = function(fForced)
{
switch(this.nFormat) {
case Video.FORMAT.VT100:
case Video8080.FORMAT.VT100:
this.updateVT100(fForced);
break;
}
@ -1274,10 +1274,10 @@ Video.prototype.updateScreenText = function(fForced)
/**
* updateScreenGraphics(fForced)
*
* @this {Video}
* @this {Video8080}
* @param {boolean} [fForced]
*/
Video.prototype.updateScreenGraphics = function(fForced)
Video8080.prototype.updateScreenGraphics = function(fForced)
{
var addr = this.addrBuffer;
var addrLimit = addr + this.sizeBuffer;
@ -1359,14 +1359,14 @@ Video.prototype.updateScreenGraphics = function(fForced)
};
/**
* Video.init()
* Video8080.init()
*
* This function operates on every HTML element of class "video", extracting the
* JSON-encoded parameters for the Video constructor from the element's "data-value"
* attribute, invoking the constructor to create a Video component, and then binding
* any associated HTML controls to the new component.
*/
Video.init = function()
Video8080.init = function()
{
var aeVideo = Component.getElementsByClass(document, PC8080.APPCLASS, "video");
for (var iVideo = 0; iVideo < aeVideo.length; iVideo++) {
@ -1486,7 +1486,7 @@ Video.init = function()
* Now we can create the Video object, record it, and wire it up to the associated document elements.
*/
var eContext = eCanvas.getContext("2d");
var video = new Video(parmsVideo, eCanvas, eContext, eTextArea /* || eInput */, eVideo);
var video = new Video8080(parmsVideo, eCanvas, eContext, eTextArea /* || eInput */, eVideo);
/*
* Bind any video-specific controls (eg, the Refresh button). There are no essential controls, however;
@ -1499,6 +1499,6 @@ Video.init = function()
/*
* Initialize every Video module on the page.
*/
web.onInit(Video.init);
web.onInit(Video8080.init);
if (NODE) module.exports = Video;
if (NODE) module.exports = Video8080;

View file

@ -69,8 +69,8 @@ At the time of this writing, the recommended order is:
* [pcx86/fdc.js](lib/fdc.js)
* [pcx86/hdc.js](lib/hdc.js)
* [pcx86/debugger.js](lib/debugger.js)
* [pcx86/state.js](lib/state.js)
* [pcx86/computer.js](lib/computer.js)
* [shared/state.js](../shared/lib/state.js)
* [shared/embed.js](../shared/lib/embed.js)
* [shared/save.js](../shared/lib/save.js)

View file

@ -35,9 +35,9 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var usr = require("../../shared/lib/usrlib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Memory = require("./memory");
var Messages = require("./messages");
var State = require("./state");
}
/**

View file

@ -36,9 +36,9 @@ if (NODE) {
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Interrupts = require("./interrupts");
var Messages = require("./messages");
var State = require("./state");
var X86 = require("./x86");
}

View file

@ -67,9 +67,9 @@ if (NODE) {
var UserAPI = require("../../shared/lib/userapi");
var ReportAPI = require("../../shared/lib/reportapi");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var Bus = require("./bus");
var State = require("./state");
}
/**
@ -1414,6 +1414,7 @@ Computer.prototype.onReset = function()
*/
Computer.prototype.getMachineComponent = function(sType, componentPrev)
{
var componentLast = componentPrev;
var aComponents = Component.getComponents(this.id);
for (var iComponent = 0; iComponent < aComponents.length; iComponent++) {
var component = aComponents[iComponent];
@ -1423,6 +1424,7 @@ Computer.prototype.getMachineComponent = function(sType, componentPrev)
}
if (component.type == sType) return component;
}
if (!componentLast) Component.log("Machine component type '" + sType + "' not found", "warning");
return null;
};

View file

@ -37,14 +37,15 @@ if (DEBUGGER) {
var usr = require("../../shared/lib/usrlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var Interrupts = require("./interrupts");
var Messages = require("./messages");
var Memory = require("./memory");
var Keyboard = require("./keyboard");
var State = require("./state");
var State = require("../../shared/lib/state");
var PCX86 = require("./defines");
var CPU = require("./cpu");
var X86 = require("./x86");
var X86Seg = require("./x86seg");
var Interrupts = require("./interrupts");
var Keyboard = require("./keyboard");
var Messages = require("./messages");
var Memory = require("./memory");
}
}
@ -258,19 +259,19 @@ function Debugger(parmsDbg)
* Make it easier to access Debugger commands from an external REPL (eg, the WebStorm
* "live" console window); eg:
*
* $('r')
* $('dw 0:0')
* $('h')
* pcx86('r')
* pcx86('dw 0:0')
* pcx86('h')
* ...
*/
var dbg = this;
if (window) {
if (window['$'] === undefined) {
window['$'] = function(s) { return dbg.doCommands(s); };
if (window[PCX86.APPCLASS] === undefined) {
window[PCX86.APPCLASS] = function(s) { return dbg.doCommands(s); };
}
} else {
if (global['$'] === undefined) {
global['$'] = function(s) { return dbg.doCommands(s); };
if (global[PCX86.APPCLASS] === undefined) {
global[PCX86.APPCLASS] = function(s) { return dbg.doCommands(s); };
}
}
@ -8080,7 +8081,7 @@ if (DEBUGGER) {
this.doClear(asArgs[0]);
break;
case 'd':
if (!COMPILED && sCmd == "debug") {
if (!PCX86.COMPILED && sCmd == "debug") {
window.DEBUG = true;
this.println("DEBUG checks on");
break;
@ -8162,7 +8163,7 @@ if (DEBUGGER) {
}
break;
}
this.println((APPNAME || "PCx86") + " version " + (XMLVERSION || APPVERSION) + " (" + this.cpu.model + (COMPILED? ",RELEASE" : (DEBUG? ",DEBUG" : ",NODEBUG")) + (PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (TYPEDARRAYS? ",TYPEDARRAYS" : (BYTEARRAYS? ",BYTEARRAYS" : ",LONGARRAYS")) + (BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')');
this.println((PCX86.APPNAME || "PCx86") + " version " + (XMLVERSION || PCX86.APPVERSION) + " (" + this.cpu.model + (PCX86.COMPILED? ",RELEASE" : (PCX86.DEBUG? ",DEBUG" : ",NODEBUG")) + (PCX86.PREFETCH? ",PREFETCH" : ",NOPREFETCH") + (PCX86.TYPEDARRAYS? ",TYPEDARRAYS" : (PCX86.BYTEARRAYS? ",BYTEARRAYS" : ",LONGARRAYS")) + (PCX86.BACKTRACK? ",BACKTRACK" : ",NOBACKTRACK") + ')');
this.println(web.getUserAgent());
break;
case 'x':
@ -8176,7 +8177,7 @@ if (DEBUGGER) {
this.doHelp();
break;
case 'n':
if (!COMPILED && sCmd == "nodebug") {
if (!PCX86.COMPILED && sCmd == "nodebug") {
window.DEBUG = false;
this.println("DEBUG checks off");
break;

View file

@ -188,7 +188,6 @@ if (NODE) {
global.DESKPRO386 = DESKPRO386;
global.PAGEBLOCKS = PAGEBLOCKS;
global.PCX86 = PCX86;
/*
* TODO: When we're "required" by Node, should we return anything via module.exports?
*/
module.exports = PCX86;
}

View file

@ -36,10 +36,10 @@ if (NODE) {
var web = require("../../shared/lib/weblib");
var DiskAPI = require("../../shared/lib/diskapi");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var Disk = require("./disk");
var State = require("./state");
}
/*

View file

@ -36,11 +36,11 @@ if (NODE) {
var web = require("../../shared/lib/weblib");
var DiskAPI = require("../../shared/lib/diskapi");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Interrupts = require("./interrupts");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var Disk = require("./disk");
var State = require("./state");
}
/**

View file

@ -35,9 +35,9 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var State = require("./state");
var CPU = require("./cpu");
}

View file

@ -35,9 +35,9 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var SerialPort = require("./serialport");
var State = require("./state");
}
/**
@ -623,7 +623,7 @@ Mouse.prototype.sendPacket = function(sDiag, xDiag, yDiag)
if (this.messageEnabled(Messages.SERIAL)) {
this.printMessage((sDiag? (sDiag + ": ") : "") + (yDiag !== undefined? ("mouse (" + xDiag + "," + yDiag + "): ") : "") + "serial packet [" + str.toHexByte(b1) + "," + str.toHexByte(b2) + "," + str.toHexByte(b3) + "]", 0, true);
}
this.componentAdapter.sendRBR([b1, b2, b3]);
this.componentAdapter.receiveData([b1, b2, b3]);
this.xDelta = this.yDelta = 0;
};
@ -681,7 +681,7 @@ Mouse.prototype.notifyMCR = function(bMCR)
* bytes on a reset. This doesn't seem to adversely affect serial mouse emulation for Windows 1.01, so
* I'm calling this good enough for now.
*/
this.componentAdapter.sendRBR([Mouse.ID_SERIAL, Mouse.ID_SERIAL]);
this.componentAdapter.receiveData([Mouse.ID_SERIAL, Mouse.ID_SERIAL]);
this.printMessage("serial mouse ID sent");
}
this.captureAll();

View file

@ -32,11 +32,12 @@
"use strict";
if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var State = require("./state");
}
/**
@ -93,7 +94,7 @@ function ParallelPort(parmsParallel) {
this.consoleOutput = null;
/**
* controlIOBuffer is a DOM element, if any, bound to the port (currently used for output only; see echoByte()).
* controlIOBuffer is a DOM element bound to the port (currently used for output only; see transmitByte()).
*
* @type {Object}
*/
@ -117,7 +118,7 @@ function ParallelPort(parmsParallel) {
* property {number} iAdapter
* property {number} portBase
* property {number} nIRQ
* property {Object} controlIOBuffer is a DOM element, if any, bound to the port (for rudimentary output; see echoByte())
* property {Object} controlIOBuffer is a DOM element bound to the port (for rudimentary output; see transmitByte())
*
* NOTE: This class declaration started as a way of informing the code inspector of the controlIOBuffer property,
* which remained undefined until a setBinding() call set it later, but I've since decided that explicitly
@ -406,7 +407,7 @@ ParallelPort.prototype.outData = function(port, bOut, addrFrom)
this.printMessageIO(port, bOut, addrFrom, "DATA");
this.bData = bOut;
this.bStatus |= ParallelPort.STATUS.NOTREADY;
if (this.echoByte(bOut)) {
if (this.transmitByte(bOut)) {
this.bStatus &= ~ParallelPort.STATUS.NOTREADY;
}
this.updateIRR();
@ -444,14 +445,18 @@ ParallelPort.prototype.updateIRR = function()
};
/**
* echoByte(b)
* transmitByte(b)
*
* @this {ParallelPort}
* @param {number} b
* @return {boolean} true if echoed, false if not
* @return {boolean} true if transmitted, false if not
*/
ParallelPort.prototype.echoByte = function(b)
ParallelPort.prototype.transmitByte = function(b)
{
var fTransmitted = false;
this.printMessage("transmitByte(" + str.toHexByte(b) + ")");
if (this.controlIOBuffer) {
if (b == 0x08) {
this.controlIOBuffer.value = this.controlIOBuffer.value.slice(0, -1);
@ -460,7 +465,7 @@ ParallelPort.prototype.echoByte = function(b)
this.controlIOBuffer.value += String.fromCharCode(b);
this.controlIOBuffer.scrollTop = this.controlIOBuffer.scrollHeight;
}
return true;
fTransmitted = true;
}
if (this.consoleOutput != null) {
if (b == 0x0A || this.consoleOutput.length >= 1024) {
@ -470,9 +475,10 @@ ParallelPort.prototype.echoByte = function(b)
if (b != 0x0A) {
this.consoleOutput += String.fromCharCode(b);
}
return true;
fTransmitted = true;
}
return false;
return fTransmitted;
};
/*

View file

@ -35,9 +35,9 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Memory = require("./memory");
var ROM = require("./rom");
var State = require("./state");
}
/**

View file

@ -35,9 +35,9 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var State = require("./state");
}
/**
@ -97,7 +97,16 @@ function SerialPort(parmsSerial) {
this.consoleOutput = null;
/**
* controlIOBuffer is a DOM element, if any, bound to the port (currently used for output only; see echoByte()).
* controlIOBuffer is a DOM element bound to the port (currently used for output only; see transmitByte()).
*
* Example: CTTY COM2
*
* The CTTY DOS command redirects all CON I/O to the specified serial port (eg, COM2), which it assumes is
* connected to a serial terminal, and therefore anything it *transmits* via COM2 will be displayed by the
* terminal. It further assumes that anything typed on such a terminal is NOT displayed, so as DOS *receives*
* serial input, DOS *transmits* the appropriate characters back to the terminal via COM2.
*
* As a result, controlIOBuffer only needs to be updated by the transmitByte() function.
*
* @type {Object}
*/
@ -105,7 +114,7 @@ function SerialPort(parmsSerial) {
/*
* If controlIOBuffer is being used AND 'tabSize' is set, then we make an attempt to monitor the characters
* being echoed via echoByte(), maintain a logical column position, and convert any tabs into the appropriate
* being echoed via transmitByte(), maintain a logical column position, and convert any tabs into the appropriate
* number of spaces.
*
* charBOL, if nonzero, is a character to automatically output at the beginning of every line. This probably
@ -126,6 +135,19 @@ function SerialPort(parmsSerial) {
*/
Component.bindExternalControl(this, sBinding, SerialPort.sIOBuffer);
}
/*
* No connection until initConnection() is called.
*/
this.sDataReceived = "";
this.connection = this.sendData = null;
/*
* Export all functions required by initConnection(); currently, this is the bare minimum, with no flow control.
*/
this['exports'] = {
'receiveData': this.receiveData
};
}
/*
@ -133,7 +155,7 @@ function SerialPort(parmsSerial) {
* property {number} iAdapter
* property {number} portBase
* property {number} nIRQ
* property {Object} controlIOBuffer is a DOM element, if any, bound to the port (for rudimentary output; see echoByte())
* property {Object} controlIOBuffer is a DOM element bound to the port (for rudimentary output; see transmitByte())
*
* NOTE: This class declaration started as a way of informing the code inspector of the controlIOBuffer property,
* which remained undefined until a setBinding() call set it later, but I've since decided that explicitly
@ -386,7 +408,7 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
if (keyCode === 0x08 || event.ctrlKey && keyCode >= 0x41 && keyCode <= 0x5A) {
if (event.preventDefault) event.preventDefault();
if (keyCode > 0x40) keyCode -= 0x40;
serial.sendRBR([keyCode]);
serial.receiveData(keyCode);
}
return true;
};
@ -398,7 +420,7 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
*/
event = event || window.event;
var keyCode = event.which || event.keyCode;
serial.sendRBR([keyCode]);
serial.receiveData(keyCode);
/*
* Since we're going to remove the "readonly" attribute from the <textarea> control
* (so that the soft keyboard activates on iOS), instead of calling preventDefault() for
@ -436,15 +458,58 @@ SerialPort.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
*/
SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
{
this.cmp = cmp;
this.bus = bus;
this.cpu = cpu;
this.dbg = dbg;
this.chipset = cmp.getMachineComponent("ChipSet");
bus.addPortInputTable(this, SerialPort.aPortInput, this.portBase);
bus.addPortOutputTable(this, SerialPort.aPortOutput, this.portBase);
this.setReady();
};
/**
* initConnection()
*
* If a machine 'connection' parameter exists of the form "{sourcePort}->{targetMachine}.{targetPort}",
* and "{sourcePort}" matches our idComponent, then look for a component with id "{targetMachine}.{targetPort}".
*
* If the target component is found, then verify that it has exported functions with the following names:
*
* receiveData(data): called when we have data to transmit; aliased internally to sendData(data)
*
* For now, we're not going to worry about communication in the other direction, because when the target component
* performs its own initConnection(), it will find our receiveByte(b) function, at which point communication in both
* directions should be established.
*
* @this {SerialPort}
*/
SerialPort.prototype.initConnection = function()
{
var sConnection = this.cmp.getMachineParm("connection");
if (sConnection) {
var asParts = sConnection.split('->');
if (asParts.length == 2) {
var sSourceID = str.trim(asParts[0]);
if (sSourceID != this.idComponent) return; // this connection string is intended for another instance
var sTargetID = str.trim(asParts[1]);
this.connection = Component.getComponentByID(sTargetID);
if (this.connection) {
var exports = this.connection['exports'];
if (exports) {
this.sendData = exports['receiveData'];
this.status(this.idMachine + '.' + sSourceID + " connected to " + sTargetID);
return;
}
}
}
this.notice("Unable to establish connection: " + sConnection);
}
};
/**
* powerUp(data, fRepower)
*
@ -456,6 +521,16 @@ SerialPort.prototype.initBus = function(cmp, bus, cpu, dbg)
SerialPort.prototype.powerUp = function(data, fRepower)
{
if (!fRepower) {
/*
* We needed to wait until now to make our first inter-machine connection attempt;
* doing this in initBus() was still too early, because initBus() is called in the context
* of onInit() processing for all machines of the same type (eg, PCx86), and if we're
* trying to connect to the port of a machine of a DIFFERENT type (eg, PC8080), it may not
* have been initialized yet.
*/
this.initConnection();
if (!data || !this.restore) {
this.reset();
} else {
@ -583,15 +658,31 @@ SerialPort.prototype.saveRegisters = function()
};
/**
* sendRBR(ab)
* receiveData(data)
*
* This replaces the old sendRBR() function, which expected an Array of bytes. We still support that,
* but in order to support connections with other SerialPort components (ie, the PC8080 SerialPort), we
* have added support for numbers and strings as well.
*
* @this {SerialPort}
* @param {Array} ab is an array of bytes to propagate to the bRBR (Receiver Buffer Register)
* @param {number|string|Array} data
* @return {boolean} true if received, false if not
*/
SerialPort.prototype.sendRBR = function(ab)
SerialPort.prototype.receiveData = function(data)
{
this.abReceive = this.abReceive.concat(ab);
if (typeof data == "number") {
this.abReceive.push(data);
}
else if (typeof data == "string") {
for (var i = 0; i < data.length; i++) {
this.abReceive.push(data.charCodeAt(i));
}
}
else {
this.abReceive = this.abReceive.concat(data);
}
this.advanceRBR();
return true; // for now, return true regardless, since we're buffering everything anyway
};
/**
@ -731,7 +822,7 @@ SerialPort.prototype.outTHR = function(port, bOut, addrFrom)
} else {
this.bTHR = bOut;
this.bLSR &= ~(SerialPort.LSR.THRE | SerialPort.LSR.TSRE);
if (this.echoByte(bOut)) {
if (this.transmitByte(bOut)) {
this.bLSR |= (SerialPort.LSR.THRE | SerialPort.LSR.TSRE);
/*
* QUESTION: Does this mean we should also flush/zero bTHR?
@ -816,14 +907,24 @@ SerialPort.prototype.updateIRR = function()
};
/**
* echoByte(b)
* transmitByte(b)
*
* @this {SerialPort}
* @param {number} b
* @return {boolean} true if echoed, false if not
* @return {boolean} true if transmitted, false if not
*/
SerialPort.prototype.echoByte = function(b)
SerialPort.prototype.transmitByte = function(b)
{
var fTransmitted = false;
this.printMessage("transmitByte(" + str.toHexByte(b) + ")");
if (this.sendData) {
if (this.sendData.call(this.connection, b)) {
fTransmitted = true;
}
}
if (this.controlIOBuffer) {
if (b == 0x0D) {
this.iLogicalCol = 0;
@ -836,8 +937,9 @@ SerialPort.prototype.echoByte = function(b)
if (this.iLogicalCol > 0) this.iLogicalCol--;
}
else {
var s = String.fromCharCode(b);
var nChars = (b >= 0x20? 1 : 0);
var s = str.toASCIICode(b); // formerly: String.fromCharCode(b);
var nChars = s.length; // formerly: (b >= 0x20? 1 : 0);
if (b < 0x20 && nChars == 1) nChars = 0;
if (b == 0x09) {
var tabSize = this.tabSize || 8;
nChars = tabSize - (this.iLogicalCol % tabSize);
@ -848,9 +950,9 @@ SerialPort.prototype.echoByte = function(b)
this.controlIOBuffer.scrollTop = this.controlIOBuffer.scrollHeight;
this.iLogicalCol += nChars;
}
return true;
fTransmitted = true;
}
if (this.consoleOutput != null) {
else if (this.consoleOutput != null) {
if (b == 0x0A || this.consoleOutput.length >= 1024) {
this.println(this.consoleOutput);
this.consoleOutput = "";
@ -858,9 +960,10 @@ SerialPort.prototype.echoByte = function(b)
if (b != 0x0A) {
this.consoleOutput += String.fromCharCode(b);
}
return true;
fTransmitted = true;
}
return false;
return fTransmitted;
};
/*

View file

@ -36,12 +36,12 @@ if (NODE) {
var web = require("../../shared/lib/weblib");
var DumpAPI = require("../../shared/lib/dumpapi");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Memory = require("./memory");
var Messages = require("./messages");
var ChipSet = require("./chipset");
var Keyboard = require("./keyboard");
var Mouse = require("./mouse");
var State = require("./state");
}
/**

View file

@ -35,9 +35,9 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("../../shared/lib/state");
var Messages = require("./messages");
var Memory = require("./memory");
var State = require("./state");
var CPU = require("./cpu");
var X86 = require("./x86");
var X86Seg = require("./x86seg");

View file

@ -38,7 +38,7 @@ if (NODE) {
var str = require("../../shared/lib/strlib");
var web = require("../../shared/lib/weblib");
var Component = require("../../shared/lib/component");
var State = require("./state");
var State = require("../../shared/lib/state");
var X86 = require("./x86");
}

View file

@ -85,18 +85,17 @@ function Component(type, parms, constructor, bitsMessage)
if (!parms) parms = {'id': "", 'name': ""};
this.id = parms['id'];
this.id = parms['id'] || "";
this.name = parms['name'];
this.comment = parms['comment'];
this.parms = parms;
if (this.id === undefined) this.id = "";
var i = this.id.indexOf('.');
if (i > 0) {
if (i < 0) {
this.idComponent = this.id;
} else {
this.idMachine = this.id.substr(0, i);
this.idComponent = this.id.substr(i + 1);
} else {
this.idComponent = this.id;
}
/*
@ -219,12 +218,35 @@ Component.subclass = function(subclass, superclass, methods, statics)
};
/*
* Every component created on the current page is recorded in this array (see Component.add()).
*
* This enables any component to locate another component by ID (see Component.getComponentByID())
* Every component created on the current page is recorded in this array (see Component.add()),
* enabling any component to locate another component by ID (see Component.getComponentByID())
* or by type (see Component.getComponentByType()).
*
* Every machine on the page are now recorded as well, by their machine ID. We then record the
* various resources used by that machine.
*/
Component.components = [];
if (window) {
if (!window['PCjs']) {
window['PCjs'] = {
'Machines': {},
'Components': []
};
}
/*
* Alias the new global objects above to their original property names, to minimize code changes.
*/
Component.machines = window['PCjs']['Machines'];
Component.components = window['PCjs']['Components'];
}
else {
/*
* Fallback for non-browser-based environments (ie, Node). TODO: This will need to be
* tailored to Node, probably using the global object instead of the window object, if we
* ever want to support multi-machine configs in that environment.
*/
Component.machines = {};
Component.components = [];
}
/**
* Component.add(component)
@ -241,12 +263,6 @@ Component.add = function(component)
Component.components.push(component);
};
/*
* Every machine on the page are now recorded as well, by their machine ID. We then record the various resources
* used by that machine.
*/
Component.machines = {};
/**
* Component.addMachine(idMachine)
*
@ -316,7 +332,6 @@ Component.log = function(s, type)
* Verifies conditions that must be true (for DEBUG builds only).
*
* The Closure Compiler should automatically remove all references to Component.assert() in non-DEBUG builds.
*
* TODO: Add a task to the build process that "asserts" there are no instances of "assertion failure" in RELEASE builds.
*
* @param {boolean} f is the expression we are asserting to be true

View file

@ -1,5 +1,5 @@
/**
* @fileoverview The State class used by C1Pjs and PCx86.
* @fileoverview The State class used by PCjs machines.
* @author <a href="mailto:Jeff@pcjs.org">Jeff Parsons</a>
* @version 1.0
* Created 2012-May-14
@ -34,7 +34,6 @@
if (NODE) {
var web = require("./../../shared/lib/weblib");
var Component = require("./../../shared/lib/component");
var Messages = require("./messages");
}
/**
@ -50,7 +49,7 @@ if (NODE) {
*
* WARNING: Since State objects are low-level objects that have no UI requirements, they do not
* inherit from the Component class, so you should only use class methods of Component, such as
* Component.assert(), or Debugger methods if the Debugger is available.
* Component.assert() (or Debugger methods if the Debugger is available).
*
* NOTE: 1.01 is the first version to provide limited save/restore support using localStorage.
* From that point on, care must be taken to insure that any new version that's incompatible with
@ -281,7 +280,7 @@ State.prototype = {
if (s) {
this[this.id] = s;
this.fLoaded = true;
if (DEBUG) this.printString("localStorage(" + this.key + "): " + s.length + " bytes loaded");
if (DEBUG) Component.log("localStorage(" + this.key + "): " + s.length + " bytes loaded");
return true;
}
}
@ -318,7 +317,7 @@ State.prototype = {
if (web.hasLocalStorage()) {
var s = JSON.stringify(this[this.id]);
if (web.setLocalStorageItem(this.key, s)) {
if (DEBUG) this.printString("localStorage(" + this.key + "): " + s.length + " bytes stored");
if (DEBUG) Component.log("localStorage(" + this.key + "): " + s.length + " bytes stored");
} else {
/*
* WARNING: Because browsers tend to disable all alerts() during an "unload" operation,
@ -376,24 +375,11 @@ State.prototype = {
var sKey = aKeys[i];
if (sKey && (fAll || sKey.substr(0, this.key.length) == this.key)) {
web.removeLocalStorageItem(sKey);
if (DEBUG) this.printString("localStorage(" + sKey + ") removed");
if (DEBUG) Component.log("localStorage(" + sKey + ") removed");
aKeys.splice(i, 1);
i = 0;
}
}
},
/**
* printString(s)
*
* @this {State}
* @param {string} s is any caller-defined string
*/
printString: function(s) {
if (DEBUG && DEBUGGER && this.dbg) {
if (this.dbg.messageEnabled(Messages.LOG)) {
this.dbg.message(s);
}
}
}
};

View file

@ -403,34 +403,37 @@ str.trim = function(s)
return s.replace(/^\s+|\s+$/g, "");
};
/*
* Any codes commented out in the following table are deemed "printable"
*/
str.aASCIICodes = {
0x00: "NUL",
0x01: "SOH", // Start of Heading
0x02: "STX", // Start of Text
0x03: "ETX", // End of Text
0x04: "EOT", // End of Transmission
0x05: "ENQ", // Enquiry
0x06: "ACK", // Acknowledge
0x07: "BEL", // Bell
0x08: "BS", // Backspace
0x09: "TAB", // Horizontal Tab
0x0A: "LF", // Line Feed (New Line)
0x0B: "VT", // Vertical Tab
0x0C: "FF", // Form Feed (New Page)
0x0D: "CR", // Carriage Return
0x0E: "SO", // Shift Out
0x0F: "SI", // Shift In
0x10: "DLE", // Data Link Escape
0x11: "DC1", // Device Control 1
0x12: "DC2", // Device Control 2
0x13: "DC3", // Device Control 3
0x14: "DC4", // Device Control 4
0x15: "NAK", // Negative Acknowledge
0x16: "SYN", // Synchronous Idle
0x17: "ETB", // End of Transmission Block
0x18: "CAN", // Cancel
0x19: "EM", // End of Medium
0x1A: "SUB", // Substitute
0x01: "SOH", // (CTRL_A) Start of Heading
0x02: "STX", // (CTRL_B) Start of Text
0x03: "ETX", // (CTRL_C) End of Text
0x04: "EOT", // (CTRL_D) End of Transmission
0x05: "ENQ", // (CTRL_E) Enquiry
0x06: "ACK", // (CTRL_F) Acknowledge
0x07: "BEL", // (CTRL_G) Bell
0x08: "BS", // (CTRL_H) Backspace
0x09: "TAB", // (CTRL_I) Horizontal Tab
// 0x0A: "LF", // (CTRL_J) Line Feed (New Line)
0x0B: "VT", // (CTRL_K) Vertical Tab
0x0C: "FF", // (CTRL_L) Form Feed (New Page)
0x0D: "CR", // (CTRL_M) Carriage Return
0x0E: "SO", // (CTRL_N) Shift Out
0x0F: "SI", // (CTRL_O) Shift In
0x10: "DLE", // (CTRL_P) Data Link Escape
0x11: "XON", // (CTRL_Q) Device Control 1 (aka DC1)
0x12: "DC2", // (CTRL_R) Device Control 2
0x13: "XOFF", // (CTRL_S) Device Control 3 (aka DC3)
0x14: "DC4", // (CTRL_T) Device Control 4
0x15: "NAK", // (CTRL_U) Negative Acknowledge
0x16: "SYN", // (CTRL_V) Synchronous Idle
0x17: "ETB", // (CTRL_W) End of Transmission Block
0x18: "CAN", // (CTRL_X) Cancel
0x19: "EM", // (CTRL_Y) End of Medium
0x1A: "SUB", // (CTRL_Z) Substitute
0x1B: "ESC", // Escape
0x1C: "FS", // File Separator
0x1D: "GS", // Group Separator

View file

@ -735,25 +735,34 @@ web.onClickRepeat = function(e, msDelay, msRepeat, fn)
};
web.aPageEventHandlers = {
'init': [], // list of window 'onload' handlers
'show': [], // list of window 'onpageshow' handlers
'exit': [] // list of window 'onunload' handlers (although we prefer to use 'onbeforeunload' if possible)
'init': [], // list of window 'onload' handlers
'show': [], // list of window 'onpageshow' handlers
'exit': [] // list of window 'onunload' handlers (although we prefer to use 'onbeforeunload' if possible)
};
web.fPageReady = false; // set once the browser's first page initialization has occurred
web.fPageEventsEnabled = true;
web.fPageLoaded = false; // set once the page's first 'onload' event has occurred
web.fPageShowed = false; // set once the page's first 'onpageshow' event has occurred
web.fPageEventsEnabled = true; // default is true, set to false (or true) by enablePageEvents()
/**
* onPageEvent(sName, fn)
*
* For 'onload', 'onunload', and 'onpageshow' events, most callers should NOT use this function, but
* instead use web.onInit(), web.onShow(), and web.onExit(), respectively.
*
* The only components that should still use onPageEvent() are THIS component (see the bottom of this file)
* and components that need to capture other events (eg, the 'onresize' event in the Video component).
*
* This function creates a chain of callbacks, allowing multiple JavaScript modules to define handlers
* for the same event, which wouldn't be possible if everyone modified window['onload'], window['onunload'],
* etc, themselves. However, that's less of a concern now, because assuming everyone else is now using
* onInit(), onExit(), etc, then there really IS only one component setting the window callback: this one.
*
* NOTE: It's risky to refer to obscure event handlers with "dot" names, because the Closure Compiler may
* erroneously replace them (eg, window.onpageshow is a good example).
*
* @param {string} sFunc
* @param {function()} fn
*
* Use this instead of setting window['onload'], window['onunload'], etc.
* Allows multiple JavaScript modules to define a handler for the same event.
*
* Moreover, it's risky to refer to obscure event handlers with "dot" names, because
* the Closure Compiler may erroneously replace them (eg, window.onpageshow is a good example).
*/
web.onPageEvent = function(sFunc, fn)
{
@ -777,9 +786,9 @@ web.onPageEvent = function(sFunc, fn)
/**
* onInit(fn)
*
* @param {function()} fn
*
* Use this instead of setting window.onload. Allows multiple JavaScript modules to define their own 'onload' event handler.
*
* @param {function()} fn
*/
web.onInit = function(fn)
{
@ -837,7 +846,8 @@ web.enablePageEvents = function(fEnable)
{
if (!web.fPageEventsEnabled && fEnable) {
web.fPageEventsEnabled = true;
if (web.fPageReady) web.sendPageEvent('init');
if (web.fPageLoaded) web.sendPageEvent('init');
if (web.fPageShowed) web.sendPageEvent('show');
return;
}
web.fPageEventsEnabled = fEnable;
@ -857,8 +867,18 @@ web.sendPageEvent = function(sEvent)
}
};
web.onPageEvent('onload', function onPageLoad() { web.fPageReady = true; web.doPageEvent(web.aPageEventHandlers['init']); });
web.onPageEvent('onpageshow', function onPageShow() { web.doPageEvent(web.aPageEventHandlers['show']); });
web.onPageEvent(web.isUserAgent("Opera") || web.isUserAgent("iOS")? 'onunload' : 'onbeforeunload', function onPageUnload() { web.doPageEvent(web.aPageEventHandlers['exit']); });
web.onPageEvent('onload', function onPageLoad() {
web.fPageLoaded = true;
web.doPageEvent(web.aPageEventHandlers['init']);
});
web.onPageEvent('onpageshow', function onPageShow() {
web.fPageShowed = true;
web.doPageEvent(web.aPageEventHandlers['show']);
});
web.onPageEvent(web.isUserAgent("Opera") || web.isUserAgent("iOS")? 'onunload' : 'onbeforeunload', function onPageUnload() {
web.doPageEvent(web.aPageEventHandlers['exit']);
});
if (NODE) module.exports = web;