Merge branch 'next-release'
This commit is contained in:
commit
08efc44370
264 changed files with 2318 additions and 421 deletions
|
|
@ -716,7 +716,7 @@ DiskDump.API = function(aParms)
|
|||
{
|
||||
var sDisk = aParms[DumpAPI.QUERY.DISK];
|
||||
var sFormat = aParms[DumpAPI.QUERY.FORMAT] || DumpAPI.FORMAT.JSON;
|
||||
var fComments = (aParms[DumpAPI.QUERY.COMMENTS]? true : false);
|
||||
var fComments = (!!aParms[DumpAPI.QUERY.COMMENTS]);
|
||||
|
||||
if (sDisk) {
|
||||
var disk = new DiskDump(sDisk, null, sFormat, fComments);
|
||||
|
|
@ -823,7 +823,7 @@ DiskDump.outputDisk = function(err, disk, sDiskPath, sOutputFile, fOverwrite, sM
|
|||
* We'll dump JSON to the console, but not a raw disk buffer; we could add an option to
|
||||
* "stringify" buffers, but if that's what the caller wants, they should use "--format=json".
|
||||
*/
|
||||
if (typeof data == "string") {
|
||||
if (typeof data === "string") {
|
||||
DiskDump.logConsole(data);
|
||||
} else {
|
||||
DiskDump.logConsole("specify --output={file} to save " + cbDisk + "-byte disk image");
|
||||
|
|
|
|||
|
|
@ -9,13 +9,10 @@ PDP-11 Machine Emulation Module (PDPjs)
|
|||
|
||||
Overview
|
||||
---
|
||||
PDPjs, our PDP-11 machine emulation module, is adapted from
|
||||
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.
|
||||
|
||||
See the list of available [PDP-11 Machines](/devices/pdp11/machine/), which includes a
|
||||
[PDP-11/70 with Front Panel](/devices/pdp11/machine/1170/panel/debugger/) and [PDP-11/70 with VT100 Terminal](/devices/pdp11/machine/1170/vt100/debugger/).
|
||||
|
||||
PDPjs is currently comprised of the following non-shared components, as listed in
|
||||
[package.json](../../package.json) (see the *pdp11Files* property):
|
||||
|
||||
|
|
@ -34,6 +31,7 @@ PDPjs is currently comprised of the following non-shared components, as listed i
|
|||
* [serialport.js](/modules/pdp11/lib/serialport.js)
|
||||
* [pc11.js](/modules/pdp11/lib/pc11.js)
|
||||
* [disk.js](/modules/pdp11/lib/disk.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)
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
}
|
||||
if (b >= 0) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS | afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.NAME] + ".readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true, !bus.nDisableFaults);
|
||||
}
|
||||
return b;
|
||||
|
|
@ -358,7 +358,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
}
|
||||
if (fWrite) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS | afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.NAME] + ".writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true, !bus.nDisableFaults);
|
||||
}
|
||||
return;
|
||||
|
|
@ -397,7 +397,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
}
|
||||
if (w >= 0) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS | afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.NAME] + ".readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true, !bus.nDisableFaults);
|
||||
}
|
||||
return w;
|
||||
|
|
@ -441,7 +441,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
}
|
||||
if (fWrite) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS | afn[BusPDP11.IOHANDLER.MSG_CATEGORY])) {
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.NAME] + ".writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true, !bus.nDisableFaults);
|
||||
}
|
||||
return;
|
||||
|
|
@ -1265,7 +1265,7 @@ BusPDP11.prototype.getMemorySize = function(type)
|
|||
};
|
||||
|
||||
/**
|
||||
* addIOHandlers(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, msgCategory, sName)
|
||||
* addIOHandlers(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, message, sName)
|
||||
*
|
||||
* Add I/O notification handlers to the master list (aIOHandlers). The start and end addresses are typically
|
||||
* relative to the starting IOPAGE address, but they can also be absolute; we simply mask all addresses with
|
||||
|
|
@ -1285,11 +1285,11 @@ BusPDP11.prototype.getMemorySize = function(type)
|
|||
* @param {function(number,number)|null|undefined} fnWriteByte
|
||||
* @param {function(number)|null|undefined} fnReadWord
|
||||
* @param {function(number,number)|null|undefined} fnWriteWord
|
||||
* @param {number} [msgCategory]
|
||||
* @param {number} [message]
|
||||
* @param {string} [sName]
|
||||
* @return {boolean} (true if entire range successfully registered, false if any conflicts)
|
||||
*/
|
||||
BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, msgCategory, sName)
|
||||
BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, message, sName)
|
||||
{
|
||||
for (var addr = start; addr <= end; addr += 2) {
|
||||
var off = addr & BusPDP11.IOPAGE_MASK;
|
||||
|
|
@ -1297,7 +1297,7 @@ BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte,
|
|||
Component.warning("I/O address already registered: " + str.toHexLong(addr));
|
||||
return false;
|
||||
}
|
||||
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, sName || "unknown", msgCategory, false];
|
||||
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, sName || "unknown", message || MessagesPDP11.BUS, false];
|
||||
if (MAXDEBUG) this.log("addIOHandlers(" + str.toHexLong(addr) + ")");
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1356,7 +1356,7 @@ BusPDP11.prototype.addIOTable = function(component, table)
|
|||
|
||||
for (var iReg = 0; iReg < nRegs; iReg++, addr += 2) {
|
||||
if (sReg && nRegs > 1) sReg = afn[4] + iReg;
|
||||
if (!this.addIOHandlers(addr, addr, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, afn[7] || component.bitsMessage || MessagesPDP11.BUS, sReg || component.idComponent)) {
|
||||
if (!this.addIOHandlers(addr, addr, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, afn[7] || component.bitsMessage, sReg || component.idComponent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ Component.subclass(CPUStatePDP11, CPUPDP11);
|
|||
* @typedef {{
|
||||
* vector: number,
|
||||
* priority: number,
|
||||
* message: number,
|
||||
* next: (Trigger|null)
|
||||
* }} Trigger
|
||||
*/
|
||||
|
|
@ -767,16 +768,17 @@ CPUStatePDP11.prototype.setSP = function(addr)
|
|||
};
|
||||
|
||||
/**
|
||||
* addTrigger(vector, priority)
|
||||
* addTrigger(vector, priority, message)
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {number} vector
|
||||
* @param {number} priority
|
||||
* @param {number} [message]
|
||||
* @return {Trigger}
|
||||
*/
|
||||
CPUStatePDP11.prototype.addTrigger = function(vector, priority)
|
||||
CPUStatePDP11.prototype.addTrigger = function(vector, priority, message)
|
||||
{
|
||||
var trigger = {vector: vector, priority: priority, next: null};
|
||||
var trigger = {vector: vector, priority: priority, message: message || 0, next: null};
|
||||
if (DEBUG) this.aTriggers.push(trigger);
|
||||
return trigger;
|
||||
};
|
||||
|
|
@ -842,14 +844,34 @@ CPUStatePDP11.prototype.removeTrigger = function(trigger)
|
|||
CPUStatePDP11.prototype.setTrigger = function(trigger)
|
||||
{
|
||||
this.insertTrigger(trigger);
|
||||
|
||||
/*
|
||||
* See the writeXCSR() function for an explanation of why signalling an INTQ hardware interrupt condition
|
||||
* should be done using INTQ_DELAY rather than setting INTQ directly.
|
||||
*/
|
||||
this.opFlags |= PDP11.OPFLAG.INTQ_DELAY;
|
||||
|
||||
if (trigger.message && this.messageEnabled(trigger.message | MessagesPDP11.INT)) {
|
||||
this.printMessage("setInterrupt(vector=" + str.toOct(trigger.vector) + ",priority=" + trigger.priority + ")", true, true);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* clearTrigger(trigger)
|
||||
*
|
||||
* @this {CPUStatePDP11}
|
||||
* @param {Trigger} trigger
|
||||
*/
|
||||
CPUStatePDP11.prototype.clearTrigger = function(trigger)
|
||||
{
|
||||
this.removeTrigger(trigger);
|
||||
|
||||
if (trigger.message && this.messageEnabled(trigger.message | MessagesPDP11.INT)) {
|
||||
this.printMessage("clearInterrupt(vector=" + str.toOct(trigger.vector) + ",priority=" + trigger.priority + ")", true, true);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* checkTriggers(priority)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1270,7 +1270,7 @@ if (DEBUGGER) {
|
|||
if (this.sMessagePrev && sMessage == this.sMessagePrev) return;
|
||||
this.sMessagePrev = sMessage;
|
||||
|
||||
var fRunning = false;
|
||||
var fRunning;
|
||||
if ((this.bitsMessage & MessagesPDP11.HALT) && this.cpu && (fRunning = this.cpu.isRunning()) || this.isBusy(true)) {
|
||||
this.stopCPU();
|
||||
if (fRunning) sMessage += " (cpu halted)";
|
||||
|
|
@ -3000,10 +3000,11 @@ if (DEBUGGER) {
|
|||
}
|
||||
sDumpers += ",state,symbols";
|
||||
this.println("dump memory commands:");
|
||||
this.println("\tdb [a] [#] dump # bytes at address a");
|
||||
this.println("\tdw [a] [#] dump # words at address a");
|
||||
this.println("\tdd [a] [#] dump # dwords at address a");
|
||||
this.println("\tdh [#] [#] dump # instructions from history");
|
||||
this.println("\tdb [a] [n] dump n bytes at address a");
|
||||
this.println("\tdw [a] [n] dump n words at address a");
|
||||
this.println("\tdd [a] [n] dump n dwords at address a");
|
||||
this.println("\tds [a] [n] dump n words at address a as JSON");
|
||||
this.println("\tdh [p] [n] dump n instructions from history position p");
|
||||
if (sDumpers.length) this.println("dump extension commands:\n\t" + sDumpers);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,6 +476,15 @@ var PDP11 = {
|
|||
RLMP: 0o174406, // RL11 Multi-Purpose Register
|
||||
RLBE: 0o174410, // RL11 Bus (Address) Extension Register (RLV12 controller only)
|
||||
|
||||
RKDS: 0o177400, // RK11 Drive Status Register
|
||||
RKER: 0o177402, // RK11 Error Register
|
||||
RKCS: 0o177404, // RK11 Control Status Register
|
||||
RKWC: 0o177406, // RK11 Word Count Register
|
||||
RKBA: 0o177410, // RK11 Bus Address Register
|
||||
RKDA: 0o177412, // RK11 Disk Address Register
|
||||
// NOTE: 177414 is unused
|
||||
RKDB: 0o177416, // RK11 Data Buffer Register
|
||||
|
||||
LKS: 0o177546, // KW11-L Clock Status
|
||||
|
||||
PRS: 0o177550, // PC11 (and PR11) Reader Status Register
|
||||
|
|
@ -483,10 +492,10 @@ var PDP11 = {
|
|||
PPS: 0o177554, // PC11 Punch Status Register
|
||||
PPB: 0o177556, // PC11 Punch Buffer Register
|
||||
|
||||
RCSR: 0o177560, // Display Terminal: Receiver Status Register
|
||||
RBUF: 0o177562, // Display Terminal: Receiver Data Buffer Register
|
||||
XCSR: 0o177564, // Display Terminal: Transmitter Status Register
|
||||
XBUF: 0o177566, // Display Terminal: Transmitter Data Buffer Register
|
||||
RCSR: 0o177560, // DL11 Display Terminal: Receiver Status Register
|
||||
RBUF: 0o177562, // DL11 Display Terminal: Receiver Data Buffer Register
|
||||
XCSR: 0o177564, // DL11 Display Terminal: Transmitter Status Register
|
||||
XBUF: 0o177566, // DL11 Display Terminal: Transmitter Data Buffer Register
|
||||
|
||||
CNSW: 0o177570, // Console (Front Panel) Switch/Display Register
|
||||
|
||||
|
|
@ -644,6 +653,84 @@ var PDP11 = {
|
|||
BAUD: 600
|
||||
},
|
||||
},
|
||||
RK11: { // RK11 Disk Controller
|
||||
PRI: 5,
|
||||
VEC: 0o220,
|
||||
RKDS: { // 177400: Drive Status Register
|
||||
SC: 0x000F, // Sector Counter
|
||||
SCESA: 0x0010, // Sector Counter Equals Sector Address
|
||||
WPS: 0x0020, // Write Protected Status (set if write-protected)
|
||||
RRDY: 0x0040, // Read/Write/Seek Ready
|
||||
DRDY: 0x0080, // Drive Ready
|
||||
SOK: 0x0100, // Sector Counter OK
|
||||
SIN: 0x0200, // Seek Incomplete
|
||||
DRU: 0x0400, // Drive Unsafe
|
||||
RK05: 0x0800, // RK05 is the selected disk drive (always set)
|
||||
DPL: 0x1000, // Drive Power Low
|
||||
ID: 0xE000, // Drive ID (logical drive number of an interrupting drive)
|
||||
SHIFT: {
|
||||
ID: 13
|
||||
}
|
||||
},
|
||||
RKER: { // 177402: Error Register
|
||||
WCE: 0x0001, // Write Check Error
|
||||
CSE: 0x0002, // Checksum Error
|
||||
UNUSED: 0x001C, // unused (returns zero)
|
||||
NXS: 0x0020, // Non-Existent Sector
|
||||
NXC: 0x0040, // Non-Existent Cylinder
|
||||
NXD: 0x0080, // Non-Existent Disk
|
||||
TE: 0x0100, // Timing Error
|
||||
DLT: 0x0200, // Date Late
|
||||
NXM: 0x0400, // Non-Existent Memory
|
||||
PGE: 0x0800, // Programming Error
|
||||
SKE: 0x1000, // Seek Error
|
||||
WLO: 0x2000, // Write Lock-Out Violation
|
||||
OVR: 0x4000, // Overrun
|
||||
DRE: 0x8000 // Drive Error
|
||||
},
|
||||
RKCS: { // 177404: Control Status Register
|
||||
GO: 0x0001, // Go (W/O)
|
||||
FUNC: 0x000E, // Function Code (F2,F1,F0) (R/W)
|
||||
MEX: 0x0030, // Memory Extension (R/W)
|
||||
IE: 0x0040, // Interrupt Enable (R/W)
|
||||
CRDY: 0x0080, // Controller Ready (R/O)
|
||||
SSE: 0x0100, // Stop on Soft Error (R/W)
|
||||
EXB: 0x0200, // Extra Bit (R/W)
|
||||
FMT: 0x0400, // Format (R/W)
|
||||
IBA: 0x0800, // Inhibit RKBA Increment (R/W)
|
||||
SCP: 0x2000, // Search Complete (R/O)
|
||||
HE: 0x4000, // Hard Error (R/O)
|
||||
ERR: 0x8000, // Composite Error (R/O) (set when any RKER bit is set)
|
||||
UNUSED: 0x1200, // unused
|
||||
RMASK: 0xEFFE, // bits readable
|
||||
WMASK: 0x0F7F, // bits writable
|
||||
SHIFT: {
|
||||
FUNC: 1,
|
||||
MEX: 4
|
||||
}
|
||||
},
|
||||
RKDA: { // 177412: Disk Address Register
|
||||
SA: 0x000F, // Sector Address
|
||||
HS: 0x0010, // Head Select (aka SUR: clear for upper disk head, set for lower)
|
||||
CA: 0x1FE0, // Cylinder Address (aka CYL ADDR)
|
||||
DS: 0xE000, // Drive Select (aka DR SEL)
|
||||
SHIFT: {
|
||||
HS: 4,
|
||||
CA: 5,
|
||||
DS: 13
|
||||
}
|
||||
},
|
||||
FUNC: { // NOTE: These function codes are pre-shifted to read/write directly from/to RKCS.FUNC
|
||||
CRESET: 0b0000, // Controller Reset
|
||||
WRITE: 0b0010, // Write
|
||||
READ: 0b0100, // Read
|
||||
WCHK: 0b0110, // Write Check
|
||||
SEEK: 0b1000, // Seek
|
||||
RCHK: 0b1010, // Read Check
|
||||
DRESET: 0b1100, // Drive Reset
|
||||
WLOCK: 0b1110 // Write Lock
|
||||
}
|
||||
},
|
||||
RL11: { // RL11 Disk Controller
|
||||
PRI: 5,
|
||||
VEC: 0o160,
|
||||
|
|
@ -663,6 +750,7 @@ var PDP11 = {
|
|||
WMASK: 0x03FE, // bits writable
|
||||
SHIFT: {
|
||||
FUNC: 1,
|
||||
BAE: 4,
|
||||
DS: 8
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ DevicePDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
device.interruptKW11();
|
||||
});
|
||||
|
||||
this.kw11.trigger = cpu.addTrigger(PDP11.KW11.VEC, PDP11.KW11.PRI);
|
||||
this.kw11.trigger = cpu.addTrigger(PDP11.KW11.VEC, PDP11.KW11.PRI, MessagesPDP11.KW11);
|
||||
|
||||
bus.addIOTable(this, DevicePDP11.UNIBUS_IOTABLE);
|
||||
bus.addResetHandler(this.reset.bind(this));
|
||||
|
|
@ -1167,6 +1167,10 @@ DevicePDP11.init = function()
|
|||
device = new RL11(parmsDevice);
|
||||
Component.bindComponentControls(device, eDevice, PDP11.APPCLASS);
|
||||
break;
|
||||
case 'rk11':
|
||||
device = new RK11(parmsDevice);
|
||||
Component.bindComponentControls(device, eDevice, PDP11.APPCLASS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ if (NODE) {
|
|||
*
|
||||
* @constructor
|
||||
* @extends Component
|
||||
* @param {RL11} controller
|
||||
* @param {RK11|RL11} controller
|
||||
* @param {Object} drive
|
||||
* @param {string} mode
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -34,22 +34,30 @@
|
|||
|
||||
var MessagesPDP11 = {
|
||||
CPU: 0x00000001,
|
||||
TRAP: 0x00000010,
|
||||
FAULT: 0x00000020,
|
||||
BUS: 0x00000040,
|
||||
MEMORY: 0x00000080,
|
||||
MMU: 0x00000100,
|
||||
ROM: 0x00000200,
|
||||
DEVICE: 0x00000400,
|
||||
PANEL: 0x00000800,
|
||||
KEYBOARD: 0x00010000,
|
||||
KEYS: 0x00020000,
|
||||
PAPER: 0x00100000,
|
||||
DISK: 0x00400000,
|
||||
RL11: 0x00800000,
|
||||
SERIAL: 0x01000000,
|
||||
SPEAKER: 0x02000000,
|
||||
COMPUTER: 0x04000000,
|
||||
TRAP: 0x00000002,
|
||||
FAULT: 0x00000004,
|
||||
INT: 0x00000008,
|
||||
BUS: 0x00000010,
|
||||
MEMORY: 0x00000020,
|
||||
MMU: 0x00000040,
|
||||
ROM: 0x00000080,
|
||||
DEVICE: 0x00000100,
|
||||
PANEL: 0x00000200,
|
||||
KEYBOARD: 0x00000400,
|
||||
KEYS: 0x00000800,
|
||||
PC11: 0x00001000,
|
||||
PAPER: 0x00001000,
|
||||
DISK: 0x00002000,
|
||||
READ: 0x00004000,
|
||||
WRITE: 0x00008000,
|
||||
RK11: 0x00010000,
|
||||
RL11: 0x00020000,
|
||||
DL11: 0x00040000,
|
||||
SERIAL: 0x00040000,
|
||||
KW11: 0x00080000,
|
||||
TIMER: 0x00080000,
|
||||
SPEAKER: 0x01000000,
|
||||
COMPUTER: 0x02000000,
|
||||
LOG: 0x10000000,
|
||||
WARN: 0x20000000,
|
||||
BUFFER: 0x40000000,
|
||||
|
|
@ -74,6 +82,7 @@ MessagesPDP11.CATEGORIES = {
|
|||
"cpu": MessagesPDP11.CPU,
|
||||
"trap": MessagesPDP11.TRAP,
|
||||
"fault": MessagesPDP11.FAULT,
|
||||
"int": MessagesPDP11.INT,
|
||||
"bus": MessagesPDP11.BUS,
|
||||
"memory": MessagesPDP11.MEMORY,
|
||||
"mmu": MessagesPDP11.MMU,
|
||||
|
|
@ -82,10 +91,17 @@ MessagesPDP11.CATEGORIES = {
|
|||
"panel": MessagesPDP11.PANEL,
|
||||
"keyboard": MessagesPDP11.KEYBOARD, // "kbd" is also allowed as shorthand for "keyboard"; see doMessages()
|
||||
"key": MessagesPDP11.KEYS, // using "key" instead of "keys", since the latter is a method on JavasScript objects
|
||||
"pc11": MessagesPDP11.PC11,
|
||||
"paper": MessagesPDP11.PAPER,
|
||||
"disk": MessagesPDP11.DISK,
|
||||
"read": MessagesPDP11.READ,
|
||||
"write": MessagesPDP11.WRITE,
|
||||
"rk11": MessagesPDP11.RK11,
|
||||
"rl11": MessagesPDP11.RL11,
|
||||
"dl11": MessagesPDP11.DL11,
|
||||
"serial": MessagesPDP11.SERIAL,
|
||||
"kw11": MessagesPDP11.KW11,
|
||||
"timer": MessagesPDP11.TIMER,
|
||||
"speaker": MessagesPDP11.SPEAKER,
|
||||
"computer": MessagesPDP11.COMPUTER,
|
||||
"log": MessagesPDP11.LOG,
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ PC11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
}
|
||||
}
|
||||
|
||||
this.triggerReaderInterrupt = this.cpu.addTrigger(PDP11.PC11.RVEC, PDP11.PC11.PRI);
|
||||
this.triggerReaderInterrupt = this.cpu.addTrigger(PDP11.PC11.RVEC, PDP11.PC11.PRI, MessagesPDP11.PC11);
|
||||
|
||||
this.timerReaderAdvance = this.cpu.addTimer(function readyReader() {
|
||||
pc11.advanceReader();
|
||||
|
|
|
|||
1296
modules/pdp11/lib/rk11.js
Normal file
1296
modules/pdp11/lib/rk11.js
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -58,7 +58,7 @@ function RL11(parms)
|
|||
* We record any 'autoMount' object now, but we no longer parse it until initBus(),
|
||||
* because the Computer's getMachineParm() service may have an override for us.
|
||||
*/
|
||||
this.configMount = parms['autoMount'] || null;
|
||||
this.configMount = parms['autoMount'] || {};
|
||||
this.cAutoMount = 0;
|
||||
|
||||
/*
|
||||
|
|
@ -256,23 +256,33 @@ RL11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.cpu = cpu;
|
||||
this.dbg = dbg;
|
||||
|
||||
this.configMount = this.cmp.getMachineParm('autoMount') || this.configMount;
|
||||
|
||||
if (this.configMount) {
|
||||
if (typeof this.configMount == "string") {
|
||||
var configMount = this.cmp.getMachineParm('autoMount');
|
||||
if (configMount) {
|
||||
if (typeof configMount == "string") {
|
||||
try {
|
||||
/*
|
||||
* The most likely source of any exception will be right here, where we're parsing
|
||||
* this JSON-encoded data.
|
||||
*/
|
||||
this.configMount = eval("(" + this.configMount + ")");
|
||||
configMount = eval("(" + configMount + ")");
|
||||
} catch (e) {
|
||||
Component.error("RL11 auto-mount error: " + e.message + " (" + this.configMount + ")");
|
||||
this.configMount = null;
|
||||
Component.error(this.type + " auto-mount error: " + e.message + " (" + configMount + ")");
|
||||
configMount = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add only drives from the machine-wide autoMount configuration that match drives managed by this component.
|
||||
*
|
||||
*/
|
||||
if (configMount) {
|
||||
for (var sDrive in configMount) {
|
||||
if (sDrive.substr(0, 2) != this.type.substr(0, 2)) continue;
|
||||
this.configMount[sDrive] = configMount[sDrive];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we didn't need auto-mount support, we could defer controller initialization until we received
|
||||
* a powerUp() notification, at which point reset() would call initController(), or restore() would restore
|
||||
|
|
@ -280,7 +290,7 @@ RL11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
*/
|
||||
this.initController();
|
||||
|
||||
this.triggerInterrupt = this.cpu.addTrigger(PDP11.RL11.VEC, PDP11.RL11.PRI);
|
||||
this.triggerInterrupt = this.cpu.addTrigger(PDP11.RL11.VEC, PDP11.RL11.PRI, MessagesPDP11.RL11);
|
||||
|
||||
bus.addIOTable(this, RL11.UNIBUS_IOTABLE);
|
||||
bus.addResetHandler(this.reset.bind(this));
|
||||
|
|
@ -442,22 +452,20 @@ RL11.prototype.saveController = function()
|
|||
RL11.prototype.autoMount = function(fRemount)
|
||||
{
|
||||
if (!fRemount) this.cAutoMount = 0;
|
||||
if (this.configMount) {
|
||||
for (var sDrive in this.configMount) {
|
||||
var configDrive = this.configMount[sDrive];
|
||||
var sDiskPath = configDrive['path'] || "";
|
||||
var sDiskName = configDrive['name'] || this.findDisk(sDiskPath);
|
||||
if (sDiskPath && sDiskName) {
|
||||
var iDrive = this.getDriveNumber(sDrive);
|
||||
if (iDrive >= 0 && iDrive < this.aDrives.length) {
|
||||
if (!this.loadDrive(iDrive, sDiskName, sDiskPath, true) && fRemount) {
|
||||
this.setReady(false);
|
||||
}
|
||||
continue;
|
||||
for (var sDrive in this.configMount) {
|
||||
var configDrive = this.configMount[sDrive];
|
||||
var sDiskPath = configDrive['path'] || "";
|
||||
var sDiskName = configDrive['name'] || this.findDisk(sDiskPath);
|
||||
if (sDiskPath && sDiskName) {
|
||||
var iDrive = this.getDriveNumber(sDrive);
|
||||
if (iDrive >= 0 && iDrive < this.aDrives.length) {
|
||||
if (!this.loadDrive(iDrive, sDiskName, sDiskPath, true) && fRemount) {
|
||||
this.setReady(false);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this.notice("Incorrect auto-mount settings for drive " + sDrive + " (" + JSON.stringify(configDrive) + ")");
|
||||
}
|
||||
this.notice("Incorrect auto-mount settings for drive " + sDrive + " (" + JSON.stringify(configDrive) + ")");
|
||||
}
|
||||
return !!this.cAutoMount;
|
||||
};
|
||||
|
|
@ -980,7 +988,7 @@ RL11.prototype.processCommand = function()
|
|||
RL11.prototype.endReadWrite = function(err, iCylinder, iHead, iSector, nWords, addr)
|
||||
{
|
||||
this.bar = addr & 0xffff;
|
||||
this.csr = (this.csr & ~PDP11.RL11.RLCS.BAE) | ((addr >> 12) & PDP11.RL11.RLCS.BAE);
|
||||
this.csr = (this.csr & ~PDP11.RL11.RLCS.BAE) | ((addr >> (16 - PDP11.RL11.RLCS.SHIFT.BAE)) & PDP11.RL11.RLCS.BAE);
|
||||
this.ber = (addr >> 16) & PDP11.RL11.RLBE.MASK; // 22 bit mode
|
||||
this.dar = (iCylinder << PDP11.RL11.RLDA.SHIFT.RW_CA) | (iHead? PDP11.RL11.RLDA.RW_HS : 0) | (iSector & PDP11.RL11.RLDA.RW_SA);
|
||||
this.darInternal = this.dar;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ if (NODE) {
|
|||
var str = require("../../shared/lib/strlib");
|
||||
var web = require("../../shared/lib/weblib");
|
||||
var Component = require("../../shared/lib/component");
|
||||
var Keys = require("../../shared/lib/keys");
|
||||
var State = require("../../shared/lib/state");
|
||||
var PDP11 = require("./defines");
|
||||
var MessagesPDP11 = require("./messages");
|
||||
|
|
@ -195,26 +196,24 @@ SerialPortPDP11.prototype.setBinding = function(sType, sBinding, control, sValue
|
|||
this.bindings[sBinding] = this.controlIOBuffer = control;
|
||||
|
||||
/*
|
||||
* By establishing an onkeypress handler here, we make it possible for DOS commands like
|
||||
* "CTTY COM1" to more or less work (use "CTTY CON" to restore control to the DOS console).
|
||||
* An onkeydown handler is required for certain keys that browsers tend to consume themselves;
|
||||
* for example, BACKSPACE is often defined as going back to the previous web page, and certain
|
||||
* CTRL keys are often used for browser shortcuts (usually on Windows-based browsers).
|
||||
*/
|
||||
control.onkeydown = function onKeyDown(event) {
|
||||
/*
|
||||
* This is required in addition to onkeypress, because it's the only way to prevent
|
||||
* BACKSPACE (keyCode 8) from being interpreted by the browser as a "Back" operation;
|
||||
* moreover, not all browsers generate an onkeypress notification for BACKSPACE.
|
||||
*
|
||||
* A related problem exists for Ctrl-key combinations in most Windows-based browsers
|
||||
* (eg, IE, Edge, Chrome for Windows, etc), because keys like Ctrl-C and Ctrl-S have
|
||||
* special meanings (eg, Copy, Save). To the extent the browser will allow it, we
|
||||
* attempt to disable that default behavior when this control receives an onkeydown
|
||||
* event for one of those keys (probably the only event the browser generates for them).
|
||||
*/
|
||||
event = event || window.event;
|
||||
var fProcess = false;
|
||||
var keyCode = event.keyCode;
|
||||
if (keyCode === 0x08 || event.ctrlKey && keyCode >= 0x41 && keyCode <= 0x5A) {
|
||||
if (keyCode == Keys.KEYCODE.BS) {
|
||||
fProcess = true;
|
||||
keyCode = Keys.ASCII.DEL;
|
||||
}
|
||||
else if (event.ctrlKey && keyCode >= Keys.ASCII.A && keyCode <= Keys.ASCII.Z) {
|
||||
fProcess = true;
|
||||
keyCode -= (Keys.ASCII.A - Keys.ASCII.CTRL_A);
|
||||
}
|
||||
if (fProcess) {
|
||||
if (event.preventDefault) event.preventDefault();
|
||||
if (keyCode > 0x40) keyCode -= 0x40;
|
||||
serial.receiveData(keyCode);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -285,7 +284,7 @@ SerialPortPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
|
||||
var serial = this;
|
||||
|
||||
this.triggerReceiveInterrupt = this.cpu.addTrigger(PDP11.DL11.RVEC, PDP11.DL11.PRI);
|
||||
this.triggerReceiveInterrupt = this.cpu.addTrigger(PDP11.DL11.RVEC, PDP11.DL11.PRI, MessagesPDP11.DL11);
|
||||
|
||||
this.timerReceiveInterrupt = this.cpu.addTimer(function readyReceiver() {
|
||||
if (!(serial.rcsr & PDP11.DL11.RCSR.RD)) {
|
||||
|
|
@ -315,7 +314,7 @@ SerialPortPDP11.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
}
|
||||
});
|
||||
|
||||
this.triggerTransmitInterrupt = this.cpu.addTrigger(PDP11.DL11.XVEC, PDP11.DL11.PRI);
|
||||
this.triggerTransmitInterrupt = this.cpu.addTrigger(PDP11.DL11.XVEC, PDP11.DL11.PRI, MessagesPDP11.DL11);
|
||||
|
||||
this.timerTransmitInterrupt = this.cpu.addTimer(function readyTransmitter() {
|
||||
serial.xcsr |= PDP11.DL11.XCSR.READY;
|
||||
|
|
@ -584,7 +583,15 @@ SerialPortPDP11.prototype.transmitByte = function(b)
|
|||
*/
|
||||
if (this.iLogicalCol > 0) this.iLogicalCol--;
|
||||
}
|
||||
else {
|
||||
else if (b) {
|
||||
/*
|
||||
* RT-11 outputs lots of NULL characters, at least after a "D 56=5015" (0x0A0D) command has
|
||||
* been issued, hence the "if (b)" check above.
|
||||
*
|
||||
* TODO: Also consider a check for Keys.ASCII.CTRL_C, because by default, RT-11 outputs "raw"
|
||||
* CTRL_C characters, which we capture below and render as <ETX>. RT-11 does this for other keys
|
||||
* as well, such as CTRL_K (<VT>) and CTRL_L (<FF>).
|
||||
*/
|
||||
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;
|
||||
|
|
@ -698,7 +705,7 @@ SerialPortPDP11.prototype.writeXCSR = function(data, addr)
|
|||
if (data & PDP11.DL11.XCSR.TIE) {
|
||||
this.cpu.setTrigger(this.triggerTransmitInterrupt);
|
||||
} else {
|
||||
this.cpu.removeTrigger(this.triggerTransmitInterrupt);
|
||||
this.cpu.clearTrigger(this.triggerTransmitInterrupt);
|
||||
}
|
||||
}
|
||||
this.xcsr = (this.xcsr & ~PDP11.DL11.XCSR.WMASK) | (data & PDP11.DL11.XCSR.WMASK);
|
||||
|
|
@ -726,16 +733,14 @@ SerialPortPDP11.prototype.readXBUF = function(addr)
|
|||
SerialPortPDP11.prototype.writeXBUF = function(data, addr)
|
||||
{
|
||||
data &= PDP11.DL11.XBUF.DATA;
|
||||
if (data) {
|
||||
this.transmitByte(data);
|
||||
this.xcsr &= ~PDP11.DL11.XCSR.READY;
|
||||
/*
|
||||
* NOTE: When debugging issues involving the SerialPort, such as debugging code between a pair of
|
||||
* transmitted bytes, you can pass 0 instead of getBaudTimeout() to setTimer() to minimize the amount
|
||||
* of time spent waiting for XCSR.READY to be set again.
|
||||
*/
|
||||
this.cpu.setTimer(this.timerTransmitInterrupt, this.getBaudTimeout(this.nBaudTransmit));
|
||||
}
|
||||
this.transmitByte(data);
|
||||
this.xcsr &= ~PDP11.DL11.XCSR.READY;
|
||||
/*
|
||||
* NOTE: When debugging issues involving the SerialPort, such as debugging code between a pair of
|
||||
* transmitted bytes, you can pass 0 instead of getBaudTimeout() to setTimer() to minimize the amount
|
||||
* of time spent waiting for XCSR.READY to be set again.
|
||||
*/
|
||||
this.cpu.setTimer(this.timerTransmitInterrupt, this.getBaudTimeout(this.nBaudTransmit));
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ DiskAPI.DISK_FORMATS = {
|
|||
/*
|
||||
* Assorted DEC disk pack formats.
|
||||
*/
|
||||
2494464: [203,2,12,512], // RK03 single-platter disk cartridge: 203 tracks, 2 heads, 12 sectors/track, 512 bytes/sector, for a total of 2494464 bytes
|
||||
5242880: [256,2,40,256], // RL01K single-platter disk cartridge: 256 tracks, 2 heads, 40 sectors/track, 256 bytes/sector, for a total of 5242880 bytes
|
||||
10485760:[512,2,40,256] // RL02K single-platter disk cartridge: 512 tracks, 2 heads, 40 sectors/track, 256 bytes/sector, for a total of 10485760 bytes
|
||||
};
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ var Keys = {
|
|||
'`': 96, a: 97, b: 98, c: 99, d: 100, e: 101, f: 102, g: 103,
|
||||
h: 104, i: 105, j: 106, k: 107, l: 108, m: 109, n: 110, o: 111,
|
||||
p: 112, q: 113, r: 114, s: 115, t: 116, u: 117, v: 118, w: 119,
|
||||
x: 120, y: 121, z: 122, '{':123, '|':124, '}':125, '~':126
|
||||
x: 120, y: 121, z: 122, '{':123, '|':124, '}':125, '~':126, DEL: 127
|
||||
},
|
||||
/*
|
||||
* Browser keyCodes we must pay particular attention to. For the most part, these are non-alphanumeric
|
||||
|
|
@ -62,10 +62,10 @@ var Keys = {
|
|||
* them using ASCII codes (eg, the LEFT arrow key uses the ASCII code for '%' or 37).
|
||||
*/
|
||||
KEYCODE: {
|
||||
/* 0x08 */ BS: 8,
|
||||
/* 0x08 */ BS: 8, // BACKSPACE
|
||||
/* 0x09 */ TAB: 9,
|
||||
/* 0x0A */ LF: 10, // TODO: Determine if any key actually generates this
|
||||
/* 0x0D */ CR: 13,
|
||||
/* 0x0A */ LF: 10, // LINE FEED (TODO: Determine if any key actually generates this)
|
||||
/* 0x0D */ CR: 13, // CARRIAGE RETURN
|
||||
/* 0x10 */ SHIFT: 16,
|
||||
/* 0x11 */ CTRL: 17,
|
||||
/* 0x12 */ ALT: 18,
|
||||
|
|
|
|||
Loading…
Reference in a new issue