Merge branch 'next-release'

This commit is contained in:
Jeff Parsons 2016-12-27 14:41:53 -08:00
commit 31d634eb72
28 changed files with 652 additions and 509 deletions

View file

@ -975,6 +975,7 @@ MarkOut.prototype.convertMDLinks = function(sBlock)
} else {
sURL = net.encodeURL(sURL, this.req, this.fDebug);
}
sURL = sURL.replace(/_/g, "%5F"); // this helps prevent emphasis detection in URLs
sBlock = str.replaceAll(aMatch[0], '<' + sTag + ' ' + sType + '="' + sURL + '"' + sTitle + '>' + sText + '</' + sTag + '>', sBlock);
}
return sBlock;

View file

@ -1043,7 +1043,7 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
kbd.addActiveKey(simCode);
};
}(this, sBinding, Keyboard.SOFTCODES[sBinding]);
var fnUp = function (kbd, sKey, simCode) {
var fnUp = function(kbd, sKey, simCode) {
return function onKeyboardBindingUp(event) {
kbd.removeActiveKey(simCode);
};
@ -1655,7 +1655,7 @@ Keyboard.prototype.injectKeysFromBuffer = function(msDelay)
this.addActiveKey(ch, true);
}
if (this.sInjectBuffer.length > 0) {
setTimeout(function (kbd) {
setTimeout(function(kbd) {
return function onInjectKeyTimeout() {
kbd.injectKeysFromBuffer(msDelay);
};

View file

@ -9,29 +9,94 @@ PDP-11 Machine Emulation Module (PDPjs)
Overview
---
PDPjs, our [PDP-11 Machine](/devices/pdp11/machine/) emulation module, is adapted from
the [PDP-11/70 Emulator (v1.4)](http://skn.noip.me/pdp11/pdp11.html) written by
Paul Nankervis.
PDPjs, our [PDP-11 Machine](/devices/pdp11/machine/) emulation module, was written in 2016. It was adapted from
the [PDP-11/70 Emulator (v1.4)](http://skn.noip.me/pdp11/pdp11.html) written by Paul Nankervis.
PDPjs is currently comprised of the following non-shared components, as listed in
[package.json](../../package.json) (see the *pdp11Files* property):
PDPjs is currently comprised of the following PDP-11 components, as listed in [package.json](../../package.json)
(see the *pdp11Files* property):
* [bus.js](/modules/pdp11/lib/bus.js)
* [computer.js](/modules/pdp11/lib/computer.js)
* [cpu.js](/modules/pdp11/lib/cpu.js)
* [cpuops.js](/modules/pdp11/lib/cpuops.js)
* [cpustate.js](/modules/pdp11/lib/cpustate.js)
* [debugger.js](/modules/pdp11/lib/debugger.js)
* [defines.js](/modules/pdp11/lib/defines.js)
* [device.js](/modules/pdp11/lib/device.js)
* [disk.js](/modules/pdp11/lib/disk.js)
* [keyboard.js](/modules/pdp11/lib/keyboard.js)
* [memory.js](/modules/pdp11/lib/memory.js)
* [messages.js](/modules/pdp11/lib/messages.js)
* [panel.js](/modules/pdp11/lib/panel.js)
* [bus.js](/modules/pdp11/lib/bus.js)
* [device.js](/modules/pdp11/lib/device.js)
* [memory.js](/modules/pdp11/lib/memory.js)
* [cpu.js](/modules/pdp11/lib/cpu.js)
* [cpustate.js](/modules/pdp11/lib/cpustate.js)
* [cpuops.js](/modules/pdp11/lib/cpuops.js)
* [rom.js](/modules/pdp11/lib/rom.js)
* [ram.js](/modules/pdp11/lib/ram.js)
* [keyboard.js](/modules/pdp11/lib/keyboard.js)
* [serialport.js](/modules/pdp11/lib/serialport.js)
* [pc11.js](/modules/pdp11/lib/pc11.js)
* [disk.js](/modules/pdp11/lib/disk.js)
* [ram.js](/modules/pdp11/lib/ram.js)
* [rk11.js](/modules/pdp11/lib/rk11.js)
* [rl11.js](/modules/pdp11/lib/rl11.js)
* [debugger.js](/modules/pdp11/lib/debugger.js)
* [computer.js](/modules/pdp11/lib/computer.js)
* [rom.js](/modules/pdp11/lib/rom.js)
* [serialport.js](/modules/pdp11/lib/serialport.js)
Since this module was written in 2016, it seemed appropriate to start adopting some of the more useful features of
[ECMAScript](http://www.ecma-international.org/ecma-262/6.0/index.html) 2015 (aka ES6), including:
* Classes
* *const* and *let*
* Computed Properties
* Default Parameters
* Octal and Binary Constants
* Template Literals
- String Interpolation (i.e., ${*expr*})
* New Built-in Methods
- String.repeat()
* *import* and *export*
However, I've still configured the Closure Compiler to "transpile" to ECMAScript 5 (aka ES5), because some people
may still be using older browsers that don't support ES6 -- or at least the subset of ES6 features I'm currently
using.
Eventually, I need to do some performance testing and determine whether the ES6 version performs any faster and/or
consumes fewer resources than the ES5 version. If it does, then I should either bite the bullet and generate ES6 code,
or generate both versions and use a loader that detects the browser's capabilities and loads the appropriate version.
Caveats
-------
### Shared modules
All PCjs machines rely on shared modules that are normally stored in [/shared/lib](/shared/lib/). However, until
ALL the machines have been converted to use ES6 classes, shared code must now exist in two flavors:
[/shared/lib](/shared/lib/) and [/shared/es6](/shared/es6/).
Once all the other machines have been converted to use ES6 classes, the shared ES6 code will be folded back into
[/shared/lib](/shared/lib/), and the temporary ES6 folder will go away. Obviously, there is incentive for me to do
this sooner rather than later, since in the interim, I must make any changes to shared code in both places.
There's also a less obvious problem: if you load a web page that attempts to load two or more PCjs machines, one of
which uses [/shared/lib](/shared/lib/) and another of which uses [/shared/es6](/shared/es6/), at least one of them will
fail to start, because the two sets of shared code cannot coexist. Well, they *could* have coexisted if I had been
willing to change the names of all the shared global objects (like **Component**), but I wasn't.
### *import* and *export*
With regard to *import* and *export* statements, the main reason I use them is to inform my development environment
(WebStorm) about each file's dependencies, thereby preventing inspection warnings. And ultimately, I plan to make PDPjs
run as a Node application, so explicitly declaring all imports and exports will be required, but for now, it's just
a web application, so strictly speaking, they're not required.
When loading uncompiled PDPjs files into a web browser, the Node-based web server bundled with PCjs still relies on
the `<script>` tag to load all JavaScript files, and as far as I know, no browser currently knows what to do with the
*import* and *export* keywords under those conditions. Chrome, for example, will immediately throw an exception when
it encounters a file containing them.
As a work-around, the bundled web server intercepts all requests for .js files and inserts line comments in front of
every *import* and *export* statement, so that your web browser won't barf on them. The statements are completely
superfluous anyway, since the web server generates `<script>` tags for all the necessary scripts, in the order they are
listed in [package.json](../../package.json).
This work-around assumes that all *export* statements appear AFTER the object they're exporting; e.g.:
export default ComputerPDP11;
and NOT as part of the object declaration; e.g.:
export default class ComputerPDP11 extends Component { ... }

View file

@ -494,7 +494,7 @@ class BusPDP11 extends Component {
var block = this.aBusBlocks[iBlock];
info.cbTotal += block.size;
if (block.size) {
info.aBlocks.push(Usr.initBitFields(BlockInfoPDP11, iBlock, 0, 0, block.type));
info.aBlocks.push(/** @type {BlockInfoPDP11} */ (Usr.initBitFields(BlockInfoPDP11, iBlock, 0, 0, block.type)));
info.cBlocks++
}
iBlock++;
@ -982,7 +982,7 @@ class BusPDP11 extends Component {
var fnWriteWord = afn[3]? afn[3].bind(component) : null;
/*
* As discussed in the IOController comments above, when handlers are being registered for these
* As discussed in the IOController comments below, when handlers are being registered for these
* BYTE-granular UNIBUS addresses, we must install custom fallback handlers for all BYTE accesses.
*/
if (addr >= PDP11.UNIBUS.R0SET0 && addr <= PDP11.UNIBUS.R6USER) {
@ -1131,12 +1131,14 @@ class BusPDP11 extends Component {
}
}
BusPDP11.IOPAGE_16BIT = 0xE000; /*000160000*/ // eg, PDP-11/20
BusPDP11.IOPAGE_18BIT = 0x3E000; /*000760000*/ // eg, PDP-11/45
BusPDP11.IOPAGE_16BIT = 0x00E000; /*000160000*/ // eg, PDP-11/20
BusPDP11.IOPAGE_18BIT = 0x03E000; /*000760000*/ // eg, PDP-11/45
BusPDP11.IOPAGE_22BIT = 0x3FE000; /*017760000*/ // eg, PDP-11/70
BusPDP11.IOPAGE_LENGTH = 0x2000; // ie, 8Kb
BusPDP11.IOPAGE_LENGTH = 0x002000; // ie, 8Kb
BusPDP11.IOPAGE_MASK = BusPDP11.IOPAGE_LENGTH - 1;
BusPDP11.MASK_18BIT = 0x03FFFF; /*000777777*/
BusPDP11.UNIBUS_22BIT = 0x3C0000; /*017000000*/
BusPDP11.MASK_22BIT = 0x3FFFFF; /*017777777*/

View file

@ -50,8 +50,8 @@ import MemoryPDP11 from "./memory";
* queue would constantly grow and shrink as requests were issued and dispatched, and as long as there was something
* in the queue, the CPU was constantly examining it.
*
* Now we are trying something more efficient. First, for devices that require delays (like a serial port's receiver
* and transmitter buffer registers that are supposed to "clock" the data in and out at a specific baud rate), the
* Now we are trying something more efficient. First, for devices that require delays (like the SerialPort's receiver
* and transmitter buffer registers, which are supposed to "clock" the data in and out at a specific baud rate), the
* CPU offers timer services that will "fire" a callback after a specified delay, which are much more efficient than
* requiring the CPU to dive into an interrupt queue and decrement delay counts on every instruction.
*
@ -337,11 +337,29 @@ class CPUStatePDP11 extends CPUPDP11 {
this.mmuLastPage = 0;
this.mmuMask = 0x3ffff;
this.addrLast = 0; // this is queried by the Panel when it's not using its own ADDRESS register
this.opLast = 0; // stores the PC and any auto-incs or auto-decs from the last opcode; used to update MMR1 and MMR2
/*
* This is queried and displayed by the Panel when it's not displaying its own ADDRESS register
* (which takes precedence when, for example, you've manually halted the CPU and are independently
* examining the contents of other addresses).
*
* We initialize it to whatever the current PC is, because according to @paulnank's pdp11.js: "Reset
* displays next instruction address" and initMMU() is called on a RESET.
*/
this.addrLast = this.regsGen[7];
/*
* This stores the PC in the lower 16 bits, and any auto-incs or auto-decs from the last opcode in the
* upper 16 bits; the lower 16 bits are used to update MMR2, and the upper 16 bits are used to update MMR1.
* The upper bits are automatically zeroed at the start of every operation when PC is copied to opLast.
*/
this.opLast = 0;
this.resetIRQs();
/*
* As initCPU() explains, we shouldn't be calling this function until well after initBus() has been
* called, but we still make absolutely sure we have Bus access.
*/
if (this.bus) {
this.setMemoryAccess();
this.addrInvalid = this.bus.getMemoryLimit(MemoryPDP11.TYPE.RAM);
@ -479,8 +497,8 @@ class CPUStatePDP11 extends CPUPDP11 {
getMMR1()
{
/*
* If updates to MMR1 have not been shut off (ie, MMR0.ABORT bits are clear),
* then we are allowed to sync MMR1 with its real-time counterpart in opLast.
* If updates to MMR1 have not been shut off (ie, MMR0.ABORT bits are clear), then we are allowed
* to sync MMR1 with its real-time counterpart in opLast.
*/
if (!(this.regMMR0 & PDP11.MMR0.ABORT)) {
this.regMMR1 = (this.opLast >> 16) & 0xffff;
@ -501,8 +519,8 @@ class CPUStatePDP11 extends CPUPDP11 {
getMMR2()
{
/*
* If updates to MMR2 have not been shut off (ie, MMR0.ABORT bits are clear),
* then we are allowed to sync MMR2 with its real-time counterpart in opLast.
* If updates to MMR2 have not been shut off (ie, MMR0.ABORT bits are clear), then we are allowed
* to sync MMR2 with its real-time counterpart in opLast.
*/
if (!(this.regMMR0 & PDP11.MMR0.ABORT)) {
this.regMMR2 = this.opLast & 0xffff;
@ -530,14 +548,14 @@ class CPUStatePDP11 extends CPUPDP11 {
setMMR3(newMMR3)
{
/*
* Don't allow the 11/45 to use 22-bit addressing or the UNIBUS map
* Don't allow the 11/45 to use 22-bit addressing or the UNIBUS map.
*/
if (this.model < PDP11.MODEL_1170) {
newMMR3 &= ~(PDP11.MMR3.MMU_22BIT | PDP11.MMR3.UNIBUS_MAP);
}
if (this.regMMR3 != newMMR3) {
this.regMMR3 = newMMR3;
this.mmuMask = (newMMR3 & PDP11.MMR3.MMU_22BIT)? 0x3fffff : 0x3ffff;
this.mmuMask = (newMMR3 & PDP11.MMR3.MMU_22BIT)? BusPDP11.MASK_22BIT : BusPDP11.MASK_18BIT;
this.setMemoryAccess();
}
}
@ -817,6 +835,26 @@ class CPUStatePDP11 extends CPUPDP11 {
return pc;
}
/**
* branch(opCode)
*
* @this {CPUStatePDP11}
* @param {number} opCode
* @param {boolean|number} condition
*/
branch(opCode, condition)
{
if (condition) {
var off = ((opCode << 24) >> 23);
if (DEBUG && DEBUGGER && this.dbg && off == -2) {
this.dbg.stopInstruction("branch to self");
}
this.setPC(this.getPC() + off);
this.nStepCycles -= 2;
}
this.nStepCycles -= (2 + 1);
}
/**
* getPC()
*
@ -2151,6 +2189,9 @@ class CPUStatePDP11 extends CPUPDP11 {
/**
* getByteChecked(addr)
*
* This is the getByte() handler whenever the Debugger has one or more virtual memory READ breakpoints set;
* otherwise, getByte() is bound to Bus.getByte().
*
* @this {CPUStatePDP11}
* @param {number} addr
* @return {number}
@ -2166,6 +2207,9 @@ class CPUStatePDP11 extends CPUPDP11 {
/**
* getWordChecked(addr)
*
* This is the getWord() handler whenever the Debugger has one or more virtual memory READ breakpoints set;
* otherwise, getWord() is bound to Bus.getWord().
*
* @this {CPUStatePDP11}
* @param {number} addr
* @return {number}
@ -2181,6 +2225,9 @@ class CPUStatePDP11 extends CPUPDP11 {
/**
* setByteChecked(addr, data)
*
* This is the setByte() handler whenever the Debugger has one or more virtual memory WRITE breakpoints set;
* otherwise, setByte() is bound to Bus.setByte().
*
* @this {CPUStatePDP11}
* @param {number} addr
* @param {number} data
@ -2196,6 +2243,9 @@ class CPUStatePDP11 extends CPUPDP11 {
/**
* setWordChecked(addr, data)
*
* This is the setWord() handler whenever the Debugger has one or more virtual memory WRITE breakpoints set;
* otherwise, setWord() is bound to Bus.setWord().
*
* @this {CPUStatePDP11}
* @param {number} addr
* @param {number} data
@ -2767,26 +2817,6 @@ class CPUStatePDP11 extends CPUPDP11 {
}
}
/**
* branch(opCode)
*
* @this {CPUStatePDP11}
* @param {number} opCode
* @param {boolean|number} condition
*/
branch(opCode, condition)
{
if (condition) {
var off = ((opCode << 24) >> 23);
if (DEBUG && DEBUGGER && this.dbg && off == -2) {
this.dbg.stopInstruction("branch to self");
}
this.setPC(this.getPC() + off);
this.nStepCycles -= 2;
}
this.nStepCycles -= (2 + 1);
}
/**
* stepCPU(nMinCycles)
*

View file

@ -55,7 +55,7 @@ import MessagesPDP11 from "./messages";
* aCmds preprocessed commands (from sCmd)
*
* @typedef {{
* addr:(number),
* addr:(number|null),
* fPhysical:(boolean),
* fTemporary:(boolean),
* nBase:(number|undefined),
@ -203,7 +203,7 @@ class DebuggerPDP11 extends Debugger {
* getAddr(dbgAddr, fWrite, nb)
*
* @this {DebuggerPDP11}
* @param {DbgAddrPDP11|null|undefined} dbgAddr
* @param {DbgAddrPDP11|null} [dbgAddr]
* @param {boolean} [fWrite]
* @param {number} [nb] number of bytes to check (1 or 2); default is 1
* @return {number} is the corresponding linear address, or PDP11.ADDR_INVALID
@ -221,14 +221,14 @@ class DebuggerPDP11 extends Debugger {
* Returns a NEW DbgAddrPDP11 object, initialized with specified values and/or defaults.
*
* @this {DebuggerPDP11}
* @param {number} [addr]
* @param {number|null} [addr]
* @param {boolean} [fPhysical]
* @param {number} [nBase]
* @return {DbgAddrPDP11}
*/
newAddr(addr, fPhysical, nBase)
{
return {addr: addr || 0, fPhysical: fPhysical || false, fTemporary: false, nBase: nBase};
return {addr: addr || null, fPhysical: fPhysical || false, fTemporary: false, nBase: nBase};
}
/**
@ -2918,7 +2918,7 @@ class DebuggerPDP11 extends Debugger {
* TODO: Tweak this output to accommodate 18-bit machines as well as 22-bit machines.
*/
var fPhysical = (dbgAddr.fPhysical || dbgAddr.addr > 0xffff);
var a = this.cpu.getAddrInfo(dbgAddr.addr, fPhysical);
var a = this.cpu.getAddrInfo(dbgAddr.addr || 0, fPhysical);
this.println(Str.pad("", fPhysical? 12: 19) + Str.toBin(dbgAddr.addr, fPhysical? 22 : 17, 3) + " " + Str.toOct(dbgAddr.addr, 8));
if (a.length < 6) {
if (a.length > 2) {

View file

@ -708,6 +708,7 @@ var PDP11 = {
RKER: { // 177402: Error Register
WCE: 0x0001, // Write Check Error
CSE: 0x0002, // Checksum Error
SE: 0x0003, // Soft Error bits (cleared at the start of a new function)
UNUSED: 0x001C, // unused (returns zero)
NXS: 0x0020, // Non-Existent Sector
NXC: 0x0040, // Non-Existent Cylinder
@ -719,7 +720,8 @@ var PDP11 = {
SKE: 0x1000, // Seek Error
WLO: 0x2000, // Write Lock-Out Violation
OVR: 0x4000, // Overrun
DRE: 0x8000 // Drive Error
DRE: 0x8000, // Drive Error
HE: 0x7FE0 // Hard Error bits (cleared only by Bus RESET or RK11 CRESET function)
},
RKCS: { // 177404: Control Status Register
GO: 0x0001, // (000001) Go (W/O)

View file

@ -35,11 +35,13 @@
import Str from "../../shared/es6/strlib";
import Web from "../../shared/es6/weblib";
import Component from "../../shared/es6/component";
import PDP11 from "./defines";
import BusPDP11 from "./bus";
import MemoryPDP11 from "./memory";
import MessagesPDP11 from "./messages";
import PC11 from "./pc11";
import RL11 from "./rl11";
import RK11 from "./rk11";
class DevicePDP11 extends Component {
/**

View file

@ -1020,7 +1020,7 @@ class PanelPDP11 extends Component {
}
/*
* Update the ADDRESS and DATA LEDs by selecting the appropriate values
* Update the ADDRESS and DATA LEDs by selecting the appropriate values.
*
* TODO: There is currently no mechanism for selecting regData over regDisplay;
* we are acting as if the DATASEL switch setting is locked to "DISPLAY REGISTER".

View file

@ -944,30 +944,20 @@ class RK11 extends Component {
processCommand()
{
var fInterrupt = true;
var fnReadWrite, sFunc = "";
var fnReadWrite, func, sFunc = "";
var iDrive = (this.regRKDA & PDP11.RK11.RKDA.DS) >> PDP11.RK11.RKDA.SHIFT.DS;
var drive = this.aDrives[iDrive];
var iCylinder, iHead, iSector, nWords, addr, inc;
this.regRKCS &= ~PDP11.RK11.RKCS.CRDY;
var func = this.regRKCS & PDP11.RK11.RKCS.FUNC;
this.regRKCS &= ~(PDP11.RK11.RKCS.CRDY | PDP11.RK11.RKCS.SCP);
this.regRKER &= ~(PDP11.RK11.RKER.SE);
switch(func) {
switch(func = this.regRKCS & PDP11.RK11.RKCS.FUNC) {
case PDP11.RK11.FUNC.CRESET:
if (this.messageEnabled()) this.printMessage(this.type + ": CRESET(" + iDrive + ")", true);
this.regRKER = 0;
this.regRKER = this.regRKDA = 0;
this.regRKCS = PDP11.RK11.RKCS.CRDY;
this.regRKDA = 0;
break;
case PDP11.RK11.FUNC.SEEK:
iCylinder = (this.regRKDA & PDP11.RK11.RKDA.CA) >> PDP11.RK11.RKDA.SHIFT.CA;
if (this.messageEnabled()) this.printMessage(this.type + ": SEEK(" + iCylinder + ")", true);
if (iCylinder >= drive.nCylinders) {
this.regRKER |= PDP11.RK11.RKER.DRE | PDP11.RK11.RKER.NXC;
this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR;
}
break;
case PDP11.RK11.FUNC.RCHK:
@ -997,21 +987,31 @@ class RK11 extends Component {
if (this.messageEnabled()) this.printMessage(this.type + ": " + sFunc + "(" + iCylinder + ":" + iHead + ":" + iSector + ") " + Str.toOct(addr) + "--" + Str.toOct(addr + (nWords << 1)), true, true);
if (iCylinder >= drive.nCylinders) {
this.regRKER |= PDP11.RK11.RKER.DRE | PDP11.RK11.RKER.NXC;
this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR;
this.regRKER |= PDP11.RK11.RKER.NXC;
break;
}
if (iSector >= drive.nSectors) {
this.regRKER |= PDP11.RK11.RKER.DRE | PDP11.RK11.RKER.NXS;
this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR;
this.regRKER |= PDP11.RK11.RKER.NXS;
break;
}
fInterrupt = fnReadWrite.call(this, drive, iCylinder, iHead, iSector, nWords, addr, inc, (func >= PDP11.RK11.FUNC.WCHK), this.doneReadWrite.bind(this));
break;
case PDP11.RK11.FUNC.SEEK:
iCylinder = (this.regRKDA & PDP11.RK11.RKDA.CA) >> PDP11.RK11.RKDA.SHIFT.CA;
if (this.messageEnabled()) this.printMessage(this.type + ": SEEK(" + iCylinder + ")", true);
if (iCylinder < drive.nCylinders) {
this.regRKCS |= PDP11.RK11.RKCS.SCP;
} else {
this.regRKER |= PDP11.RK11.RKER.NXC;
}
break;
case PDP11.RK11.FUNC.DRESET:
if (this.messageEnabled()) this.printMessage(this.type + ": DRESET(" + iDrive + ")");
this.regRKER = this.regRKDA = 0;
this.regRKCS = PDP11.RK11.RKCS.CRDY | PDP11.RK11.RKCS.SCP;
break;
default:
@ -1021,9 +1021,7 @@ class RK11 extends Component {
this.regRKDS = drive.status | (drive.disk? PDP11.RK11.RKDS.DRDY : 0) | (iDrive << PDP11.RK11.RKDS.SHIFT.ID) | (this.regRKDA & PDP11.RK11.RKDS.SC);
if (this.regRKER & PDP11.RK11.RKER.DRE) {
if (this.messageEnabled()) this.printMessage(this.type + ": ERROR: " + Str.toOct(this.regRKER));
}
this.updateErrors();
if (fInterrupt) {
this.regRKCS &= ~PDP11.RK11.RKCS.GO;
@ -1139,8 +1137,6 @@ class RK11 extends Component {
err = PDP11.RK11.RKER.NXM;
break;
}
addr += inc;
nWords--;
if (!sector) {
if (iCylinder >= disk.nCylinders) {
err = PDP11.RK11.RKER.NXC;
@ -1167,56 +1163,19 @@ class RK11 extends Component {
break;
}
/*
* TODO: Figure out why certain WCHK commands fail during the 11/70 CPU EXERCISER diagnostic,
* once the test starts reading/writing with physical addresses > 177777. I think all the
* UNIBUS address calculations are fine, so I'm at a loss to explain how a WCHK operation
* can succeed when the diagnostic itself appears to alter the memory immediately after the
* preceding WRITE operation.
* NOTE: During the 11/70 CPU EXERCISER diagnostic, a number of WCHK requests will fail
* when the test starts reading/writing with physical addresses > 177777. I'm pretty sure all
* the UNIBUS address calculations are fine, and therefore those failures are expected.
*
* The following machine is already primed with the diagnostic, as well as the recommended
* breakpoints and messages:
*
* http://www.pcjs.org/devices/pdp11/machine/1170/panel/debugger/cpuexer/
*
* If you're not using that machine, turn on RK11 messages ("m rk11 on"), set a breakpoint at
* 033330 ("bp 033330") and then take a look at the first RK11 operation after that breakpoint;
* it should be the first one using a UNIBUS address larger than 16 bits:
*
* RK11: WRITE(147:1:2) 00453610--00463610 @037772
*
* Use a breakpoint to halt the machine at 037772, and then use the Debugger's "da" command
* to determine where UNIBUS address 00453610 is mapped (make sure you specify it as a physical
* address using the % prefix):
*
* >> da %00453610
* 00,101,011,110,001,000 00453610
* UNIMAP[18]: 1,111,111,110,100,001,111,000 17764170
* OFFSET: 1,011,110,001,000 00013610
* PHYSICAL: 0,000,000,000,000,000,000,000 00000000
*
* So, you can see that the starting address for the WRITE is perfectly calculated to begin at
* physical address 0. And the "da" command indicates virtual address 0 points to the same
* memory:
*
* >> da 0
* 00,000,000,000,000,000 00000000
* 0,000,000,000,000 00000000
* + KIPAR0: 0,000,000,000,000,000,000,000 00000000
* & MMUMASK: 1,111,111,111,111,111,111,111 17777777
* = PHYSICAL: 0,000,000,000,000,000,000,000 00000000
*
* Strangely, the diagnostic (its interrupt handler to be exact) is updating the next RKCS command
* value at 001570, which is right in the middle of the first 2048 words of memory -- the same 2048
* words that the diagnostic is about to WRITE and then WCHK. Since that value is changing between
* the WRITE and the WCHK, how can WCHK succeed?
*
* For now, I just pretend that it does, by skipping the actual comparison.
*
* if (data != (b0 | (b1 << 8))) {
* err = PDP11.RK11.RKER.WCE;
* break;
* }
* Originally, those failures were causing me some grief because I was treating a WCE error like
* any other error; ie, as a HARD error. That was wrong. Two errors (WCE and CSE) are soft
* errors, so while they should still trigger the general-purpose RKCS ERR bit, they should NOT
* trigger the RKCS HE (Hard Error) bit. This is all taken care of in updateErrors() now.
*/
if (data != (b0 | (b1 << 8))) {
err = PDP11.RK11.RKER.WCE;
break;
}
} else {
if (!disk.write(sector, ibSector++, data & 0xff) || !disk.write(sector, ibSector++, data >> 8)) {
err = PDP11.RK11.RKER.NXS;
@ -1224,6 +1183,8 @@ class RK11 extends Component {
}
}
if (ibSector >= disk.cbSector) sector = null;
addr += inc;
nWords--;
}
return done? done(err, iCylinder, iHead, iSector, nWords, addr) : err;
}
@ -1246,13 +1207,39 @@ class RK11 extends Component {
this.regRKCS = (this.regRKCS & ~PDP11.RK11.RKCS.MEX) | ((addr >> (16 - PDP11.RK11.RKCS.SHIFT.MEX)) & PDP11.RK11.RKCS.MEX);
this.regRKWC = (0x10000 - nWords) & 0xffff;
this.regRKDA = (this.regRKDA & ~PDP11.RK11.RKDA.SA) | (iSector & PDP11.RK11.RKDA.SA);
if (err) {
this.regRKER |= err | PDP11.RK11.RKER.DRE;
this.regRKCS |= PDP11.RK11.RKCS.HE | PDP11.RK11.RKCS.ERR;
}
this.regRKER |= err;
this.updateErrors();
return true;
}
/**
* updateErrors()
*
* @this {RK11}
*/
updateErrors()
{
/*
* Reflect RKER bits to RKCS bits as appropriate.
*
* TODO: I'm not entirely sure about the handling of the DRE bit here. DEC's RK11 documentation says:
*
* Sets if one of the drives in the system senses a loss of either AC or DC power and a function is
* either initiated or in process while the selected drive is not ready or in some error condition.
*
* I'm not sure how to parse all the "ands" and "ors" in that sentence. For now, we're treating the DRE bit
* much like the high error bit found in other hardware registers: we always set it if any lower error bits
* are also set.
*/
this.regRKCS &= ~PDP11.RK11.RKCS.ERR;
if (this.regRKER) {
this.regRKER |= PDP11.RK11.RKER.DRE;
this.regRKCS |= PDP11.RK11.RKCS.ERR;
if (this.regRKER & PDP11.RK11.RKER.HE) this.regRKCS |= PDP11.RK11.RKCS.HE;
if (this.messageEnabled()) this.printMessage(this.type + ": ERROR: " + Str.toOct(this.regRKER));
}
}
/**
* readRKDS(addr)
*

View file

@ -0,0 +1,28 @@
Shared (ES6) Sources
====================
This folder contains a mix of shared code, with some files used only by Node (server) modules,
some used only by Browser (client) modules, and others used by both.
At the moment, only a few files are completely agnostic; eg: [strlib.js](strlib.js) and [usrlib.js](usrlib.js).
One give-away is that neither contain references to any globals (although references to each other
would be fine).
[netlib.js](netlib.js) is appropriate only for Node modules, because it contains code that relies on Node's
global *Buffer* object, as indicated by:
/* global Buffer: false */
[weblib.js](weblib.js) is appropriate only for client modules, because it contains code that relies on the
browser's global *window* object, as indicated by:
/* global window: true */
We declare *window* modifiable (true) so that [defines.js](defines.js) can set *global.window* to *false*
when running within Node, allowing any other code to test the existence of *window* with a simple:
if (window) {...}
instead of:
if (typeof window !== "undefined") {...}

View file

@ -1027,7 +1027,7 @@ if (!Array.prototype.indexOf) {
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
*/
if (!Array.isArray) {
Array.isArray = function (arg) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}

View file

@ -29,7 +29,7 @@
"use strict";
import Str from "../../shared/es6/strlib";
import Component from "../..shared/es6/component";
import Component from "../../shared/es6/component";
/**
* Debugger Address Object

View file

@ -156,7 +156,7 @@ class Net {
var options = url.parse(sURL);
options.method = "HEAD";
options.path = options.pathname; // TODO: Determine the necessity of aliasing this
var req = http.request(options, function (res)
var req = http.request(options, function(res)
{
var err = null;
var stat = null;
@ -179,7 +179,7 @@ class Net {
}
done(err, stat);
});
req.on('error', function (err)
req.on('error', function(err)
{
done(err, null);
});
@ -211,9 +211,9 @@ class Net {
*/
var sFile = "";
var bufFile = null;
http.get(sURL, function (res)
http.get(sURL, function(res)
{
res.on('data', function (data)
res.on('data', function(data)
{
if (sEncoding) {
sFile += data;
@ -241,7 +241,7 @@ class Net {
* bufFile = buf;
*/
bufFile = Buffer.concat([bufFile, data], bufFile.length + data.length);
}).on('end', function ()
}).on('end', function()
{
/*
* TODO: Decide what to do when res.statusCode is actually an error code (eg, 404), because
@ -252,7 +252,7 @@ class Net {
} else {
done(new Error(sEncoding ? sFile : bufFile), res.statusCode, null);
}
}).on('error', function (err)
}).on('error', function(err)
{
done(err, res.statusCode, null);
});
@ -279,12 +279,12 @@ class Net {
* Either the documentation isn't quite right for url.parse() or http.request() (the big brother
* of http.get), or one of those "options" properties is aliased to the other, or...?
*/
http.get(sURL, function (res)
http.get(sURL, function(res)
{
res.on('data', function (data)
res.on('data', function(data)
{
file.write(data);
}).on('end', function ()
}).on('end', function()
{
file.end();
/*
@ -295,7 +295,7 @@ class Net {
* in such cases, the file content will likely just be an HTML error page.
*/
done(null, res.statusCode);
}).on('error', function (err)
}).on('error', function(err)
{
done(err, res.statusCode);
});
@ -329,7 +329,7 @@ class Net {
var sBaseName = Str.getBaseName(sURL);
var sFile = path.join(Net.sServerRoot, sURL);
if (fAsync) {
fs.readFile(sFile, {encoding: "utf8"}, function (err, s)
fs.readFile(sFile, {encoding: "utf8"}, function(err, s)
{
/*
* TODO: If err is set, is there an error code we should return (instead of -1)?

View file

@ -44,7 +44,7 @@ class Proc {
*
* @return {{argc:number, argv:{}}}
*/
static getArgs = function ()
static getArgs()
{
var argc = 0;
var argv = {};

View file

@ -450,7 +450,7 @@ class Str {
*/
static escapeHTML(sHTML)
{
return sHTML.replace(/[&<>"']/g, function (m)
return sHTML.replace(/[&<>"']/g, function(m)
{
return Str.aHTMLEscapeMap[m];
});
@ -494,7 +494,7 @@ class Str {
k = k.replace(/([\\[\]*{}().+?])/g, "\\$1");
sMatch += (sMatch ? '|' : '') + k;
}
return s.replace(new RegExp('(' + sMatch + ')', "g"), function (m)
return s.replace(new RegExp('(' + sMatch + ')', "g"), function(m)
{
return a[m];
});
@ -553,7 +553,10 @@ class Str {
*/
static toASCIICode(b)
{
var s = (b != Str.ASCII.CR && b != Str.ASCII.LF ? Str.aASCIICodes[b] : null);
var s;
if (b != Str.ASCII.CR && b != Str.ASCII.LF) {
s = Str.aASCIICodes[b];
}
if (s) {
s = '<' + s + '>';
} else {

View file

@ -56,7 +56,7 @@ class Usr {
var right = a.length;
var found = 0;
if (fnCompare === undefined) {
fnCompare = function (a, b)
fnCompare = function(a, b)
{
return a > b ? 1 : a < b ? -1 : 0;
};

View file

@ -174,7 +174,7 @@ class Web {
return [sResource, nErrorCode];
}
else if (fAsync && typeof resources == 'function') {
resources(sURL, function (sResource, nErrorCode)
resources(sURL, function(sResource, nErrorCode)
{
if (done) done(sURL, sResource, nErrorCode);
});
@ -190,7 +190,7 @@ class Web {
var xmlHTTP = (window.XMLHttpRequest ? new window.XMLHttpRequest() : new window.ActiveXObject("Microsoft.XMLHTTP"));
if (fAsync) {
xmlHTTP.onreadystatechange = function ()
xmlHTTP.onreadystatechange = function()
{
if (xmlHTTP.readyState === 4) {
/*
@ -679,7 +679,7 @@ class Web {
var match;
var pl = /\+/g; // RegExp for replacing addition symbol with a space
var search = /([^&=]+)=?([^&]*)/g;
var decode = function (s)
var decode = function(s)
{
return decodeURIComponent(s.replace(pl, " "));
};
@ -777,7 +777,7 @@ class Web {
ms = msRepeat;
}
};
e.onmousedown = function ()
e.onmousedown = function()
{
// Web.log("onMouseDown()");
if (!fIgnoreMouseEvents) {
@ -787,7 +787,7 @@ class Web {
}
}
};
e.ontouchstart = function ()
e.ontouchstart = function()
{
// Web.log("onTouchStart()");
if (!timer) {
@ -795,7 +795,7 @@ class Web {
fnRepeat();
}
};
e.onmouseup = e.onmouseout = function ()
e.onmouseup = e.onmouseout = function()
{
// Web.log("onMouseUp()/onMouseOut()");
if (timer) {
@ -803,7 +803,7 @@ class Web {
timer = null;
}
};
e.ontouchend = e.ontouchcancel = function ()
e.ontouchend = e.ontouchcancel = function()
{
// Web.log("onTouchEnd()/onTouchCancel()");
if (timer) {

View file

@ -1,5 +1,5 @@
Shared Sources
===
==============
This folder contains a mix of shared code, with some files used only by Node (server) modules,
some used only by Browser (client) modules, and others used by both.
@ -8,7 +8,7 @@ At the moment, only a few files are completely agnostic; eg: [strlib.js](strlib.
One give-away is that neither contain references to any globals (although references to each other
would be fine).
**netlib.js** is appropriate only for Node modules, because it contains code that relies on Node's
[netlib.js](netlib.js) is appropriate only for Node modules, because it contains code that relies on Node's
global *Buffer* object, as indicated by:
/* global Buffer: false */

View file

@ -1081,7 +1081,7 @@ if (!Array.prototype.indexOf) {
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
*/
if (!Array.isArray) {
Array.isArray = function (arg) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}

View file

@ -34,6 +34,6 @@
var socket = io.connect();
// if we get an "info" emit from the socket server then console.log the data we receive
socket.on('info', function (data) {
socket.on('info', function(data) {
console.log(data);
});