Merge branch 'next-release'
This commit is contained in:
commit
f99a0c59a0
293 changed files with 14086 additions and 4715 deletions
|
|
@ -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:
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue