Fixed DL11 for RT-11, and added more message capabilities

This commit is contained in:
Jeff Parsons 2016-11-22 16:54:45 -08:00 • committed by Jeff Parsons
commit 708869815d
12 changed files with 135 additions and 87 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -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;
}
}

View file

@ -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)
*

View file

@ -492,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

View file

@ -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));

View file

@ -34,23 +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: 0x00200000,
RK11: 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,
@ -75,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,
@ -83,11 +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,

View file

@ -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();

View file

@ -290,7 +290,7 @@ RK11.prototype.initBus = function(cmp, bus, cpu, dbg)
*/
this.initController();
this.triggerInterrupt = this.cpu.addTrigger(PDP11.RK11.VEC, PDP11.RK11.PRI);
this.triggerInterrupt = this.cpu.addTrigger(PDP11.RK11.VEC, PDP11.RK11.PRI, MessagesPDP11.RK11);
bus.addIOTable(this, RK11.UNIBUS_IOTABLE);
bus.addResetHandler(this.reset.bind(this));
@ -931,6 +931,10 @@ RK11.prototype.processCommand = function()
}
addr = (((this.csr & PDP11.RK11.RKCS.MEX)) << (16 - PDP11.RK11.RKCS.SHIFT.MEX)) | this.bar;
nWords = (0x10000 - this.wcr) & 0xffff;
if (DEBUG && this.messageEnabled(MessagesPDP11.READ)) {
var pos = ((((iCylinder << 1) + iHead) * drive.nSectors) + iSector) * 256;
this.printMessage((fnReadWrite == this.readData? "readData" : "writeData") + "(pos=" + pos + ",addr=" + str.toOct(addr) + ",bytes=" + (nWords * 2) + ")", true, true);
}
fInterrupt = fnReadWrite.call(this, drive, iCylinder, iHead, iSector, nWords, addr, this.endReadWrite.bind(this));
break;
@ -952,8 +956,6 @@ RK11.prototype.processCommand = function()
}
};
/**
* endReadWrite(err, iCylinder, iHead, iSector, nWords, addr)
*
@ -1002,6 +1004,7 @@ RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
nWords = 0;
}
var sWords = "";
while (nWords--) {
if (!sector) {
sector = drive.disk.seek(iCylinder, iHead, iSector + 1);
@ -1011,12 +1014,16 @@ RK11.prototype.readData = function(drive, iCylinder, iHead, iSector, nWords, add
}
ibSector = 0;
}
var b0, b1;
var b0, b1, data;
if ((b0 = drive.disk.read(sector, ibSector++)) < 0 || (b1 = drive.disk.read(sector, ibSector++)) < 0) {
err = PDP11.RK11.RKER.NXS;
break;
}
var data = this.bus.setWordDirect(addr, b0 | (b1 << 8));
this.bus.setWordDirect(addr, data = b0 | (b1 << 8));
if (DEBUG && this.messageEnabled(MessagesPDP11.READ) && sWords.length < 56) {
sWords += str.toOct(data) + ' ';
if (sWords.length >= 56) this.printMessage(sWords + '\n', true);
}
if (this.bus.checkFault()) {
err = PDP11.RK11.RKER.NXM;
break;

View file

@ -290,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));

View file

@ -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,7 +733,6 @@ 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;
/*
@ -735,7 +741,6 @@ SerialPortPDP11.prototype.writeXBUF = function(data, addr)
* of time spent waiting for XCSR.READY to be set again.
*/
this.cpu.setTimer(this.timerTransmitInterrupt, this.getBaudTimeout(this.nBaudTransmit));
}
};
/*

View file

@ -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,