diff --git a/devices/pdp11/machine/1170/test/machine.xml b/devices/pdp11/machine/1170/test/machine.xml
index 40b787114..f10d95591 100644
--- a/devices/pdp11/machine/1170/test/machine.xml
+++ b/devices/pdp11/machine/1170/test/machine.xml
@@ -5,9 +5,10 @@
-
+
+
-
+
diff --git a/docs/pcx86/examples/pcx86-dbg.js b/docs/pcx86/examples/pcx86-dbg.js
index d66cee40c..27f8c4158 100644
--- a/docs/pcx86/examples/pcx86-dbg.js
+++ b/docs/pcx86/examples/pcx86-dbg.js
@@ -22,7 +22,7 @@ function ob(a,b){if(void 0!==a){var c;b&&0<(c=b.indexOf("."))&&(a=b.substr(0,c+1
function rb(a,b,c){var d;b&&(void 0===d&&(d="Panel"),(d=pb(d,a.id))&&(b=d.qa[b])&&a.Pb(null,c,b))}function sb(a,b){b=tb(b.parentNode,"pcx86-control");for(var c=0;c=a.lb+b&&(a.xb=b,a.kb++,a.kb>=a.ub&&(a.kb=0,a.be++))}l.Nm=function(){var a=this.F.M&255;!(this.F.G>>8)&&128>8||!this.N)||(a=!(this.N.vc[0].Ad&64));return a?!0:!1};
var Tp={800:Pp.prototype.Lm,801:Pp.prototype.Mm,802:Pp.prototype.Km},Sp={496:Pp.prototype.il,497:Pp.prototype.Sl,498:Pp.prototype.Ul,499:Pp.prototype.Vl,500:Pp.prototype.Ql,501:Pp.prototype.Pl,502:Pp.prototype.Rl,503:Pp.prototype.Wl},Vp={800:Pp.prototype.ho,801:Pp.prototype.ko,802:Pp.prototype.jo,803:Pp.prototype.io,807:Pp.prototype.pi,811:Pp.prototype.pi,815:Pp.prototype.pi},Up={496:Pp.prototype.qn,497:Pp.prototype.vn,498:Pp.prototype.tn,499:Pp.prototype.un,500:Pp.prototype.pn,501:Pp.prototype.on,
502:Pp.prototype.rn,503:Pp.prototype.nn,1014:Pp.prototype.sn};Xa(function(){for(var a=tb(document,"pcx86","hdc"),b=0;b=":6,">":6,"<=":6,"<":6,">>>":7,">>":7,"<<":7,"-":8,"+":8,"%":9,"/":9,"*":9};mq.prototype.oh=function(){return-1};mq.prototype.ph=function(){};
-mq.prototype.Pk=function(a,b){return a.replace("["+b+"]","unimplemented")};mq.prototype.Ng=function(a,b,c){if(b)if(a){0>this.A&&this.C.length&&(this.A=0);if(0>this.A||a!=this.C[this.A])this.C.splice(0,0,a),this.A=0;this.A--}else this.va?a="end":a=this.C[this.A+1];b=[];if(a){a=a.toLowerCase().replace(/""/g,"'");var d=0,e=null;c=c||";";for(var f=0;f<=a.length;f++){var g=a.charAt(f);if('"'==g||"'"==g)e?g==e&&(e=null):e=g;else if(g==c&&!e||!g)b.push(qa(a.substring(d,f))),d=f+1}}return b};
+mq.prototype.Pk=function(a,b){return a.replace("["+b+"]","unimplemented")};mq.prototype.Ng=function(a,b,c){if(b)if(a){0>this.A&&this.C.length&&(this.A=0);if(0>this.A||a!=this.C[this.A])this.C.splice(0,0,a),this.A=0;this.A--}else this.va?a="end":a=this.C[this.A+1];b=[];if(a){a=a.replace(/""/g,"'");var d=0,e=null;c=c||";";for(var f=0;f<=a.length;f++){var g=a.charAt(f);if('"'==g||"'"==g)e?g==e&&(e=null):e=g;else if(g==c&&!e||!g)b.push(qa(a.substring(d,f))),d=f+1}}return b};
function oq(a,b,c){for(c=c||-1;c--&&b.length;){var d=b.pop();if(2>a.length)return!1;var e=a.pop(),f=a.pop();switch(d){case "*":d=f*e;break;case "/":if(!e)return!1;d=f/e;break;case "%":if(!e)return!1;d=f%e;break;case "+":d=f+e;break;case "-":d=f-e;break;case "<<":d=f<>":d=f>>e;break;case ">>>":d=f>>>e;break;case "<":d=f":d=f>e?1:0;break;case ">=":d=f>=e?1:0;break;case "==":d=f==e?1:0;break;case "!=":d=f!=e?1:0;break;case "&":d=f&e;break;
case "^":d=f^e;break;case "|":d=f|e;break;case "&&":d=f&&e?1:0;break;case "||":d=f||e?1:0;break;default:return!1}a.push(d|0)}return!0}
function pq(a,b,c){var d;if(b){b=qq(a,b);for(var e=0,f=!1,g=b,h=[],k=[],m=b.split(/(\|\||&&|\||^|&|!=|==|>=|>>>|>>|>|<=|<<|<|-|\+|%|\/|\*)/);ec&&(d+=" '"+String.fromCharCode(c)+"'"));a.O((null!=b?b+": ":"")+d);return e}function uq(a,b){if(b)return sq(a,b,a.ya[b]);var c=0;for(b in a.ya)sq(a,b,a.ya[b]),c++;return 0= 0) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message(afn[5] + ".readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true);
+ this.dbg.printMessage(afn[5] + ".readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true);
}
return b;
}
- b = bus.fnAccess(addr, -1, 1);
+ b = bus.fnAccess(addr | BusPDP11.IOPAGE_22BIT, -1, 1);
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message("warning: unconverted read access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b));
+ this.dbg.printMessage("warning: unconverted read access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b));
}
return b;
},
@@ -275,13 +275,13 @@ BusPDP11.IOController = {
}
if (fWrite) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message(afn[5] + ".writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true);
+ this.dbg.printMessage(afn[5] + ".writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true);
}
return;
}
- bus.fnAccess(addr, b, 1);
+ bus.fnAccess(addr | BusPDP11.IOPAGE_22BIT, b, 1);
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message("warning: unconverted write access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b));
+ this.dbg.printMessage("warning: unconverted write access to byte @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(b));
}
},
@@ -308,13 +308,13 @@ BusPDP11.IOController = {
}
if (w >= 0) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message(afn[5] + ".readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true);
+ this.dbg.printMessage(afn[5] + ".readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true);
}
return w;
}
- w = bus.fnAccess(addr, -1, 0);
+ w = bus.fnAccess(addr | BusPDP11.IOPAGE_22BIT, -1, 0);
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message("warning: unconverted read access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w));
+ this.dbg.printMessage("warning: unconverted read access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w));
}
return w;
},
@@ -345,13 +345,13 @@ BusPDP11.IOController = {
}
if (fWrite) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message(afn[5] + ".writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true);
+ this.dbg.printMessage(afn[5] + ".writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true);
}
return;
}
- bus.fnAccess(addr, w, 0);
+ bus.fnAccess(addr | BusPDP11.IOPAGE_22BIT, w, 0);
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
- this.dbg.message("warning: unconverted write access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w));
+ this.dbg.printMessage("warning: unconverted write access to word @" + this.dbg.toStrBase(addr) + ": " + this.dbg.toStrBase(w));
}
}
};
@@ -426,7 +426,7 @@ BusPDP11.prototype.reset = function()
};
/**
- * access()
+ * access(addr, data, byteFlag)
*
* This is our default I/O handler, called whenever there's an IOPAGE access without a corresponding entry
* in aIOHandlers; in the interim, our Device component will override this default handler with its own function
@@ -440,6 +440,9 @@ BusPDP11.prototype.reset = function()
*/
BusPDP11.prototype.access = function(addr, data, byteFlag)
{
+ if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.BUS)) {
+ this.dbg.printMessage("warning: unrecognized access(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(data) + "," + byteFlag + ")");
+ }
return 0;
};
diff --git a/modules/pdp11/lib/debugger.js b/modules/pdp11/lib/debugger.js
index 73ba0081a..f10ea3082 100644
--- a/modules/pdp11/lib/debugger.js
+++ b/modules/pdp11/lib/debugger.js
@@ -214,8 +214,8 @@ if (DEBUGGER) {
's': "set options",
't [#]': "trace", // other variations: tr (trace and dump registers)
'u [#]': "unassemble",
- 'v': "print version",
- 'var': "assign variable"
+ 'var': "assign variable",
+ 'ver': "print version"
};
/*
@@ -1135,12 +1135,32 @@ if (DEBUGGER) {
return s;
};
+ /**
+ * disableMessages(s)
+ *
+ * @this {DebuggerPDP11}
+ */
+ DebuggerPDP11.prototype.disableMessages = function()
+ {
+ this.nDisableMessages++;
+ };
+
+ /**
+ * enableMessages(s)
+ *
+ * @this {DebuggerPDP11}
+ */
+ DebuggerPDP11.prototype.enableMessages = function()
+ {
+ this.nDisableMessages--;
+ };
+
/**
* message(sMessage, fAddress)
*
* @this {DebuggerPDP11}
* @param {string} sMessage is any caller-defined message string
- * @param {boolean} [fAddress] is true to display the current PC
+ * @param {boolean} [fAddress] is true to display the current address
*/
DebuggerPDP11.prototype.message = function(sMessage, fAddress)
{
@@ -3123,6 +3143,7 @@ if (DEBUGGER) {
DebuggerPDP11.prototype.doOptions = function(asArgs)
{
switch (asArgs[1]) {
+
case "base":
if (asArgs[2]) {
var nBase = +asArgs[2];
@@ -3135,6 +3156,7 @@ if (DEBUGGER) {
}
this.println("default base: " + this.nBase);
break;
+
case "cs":
var nCycles;
if (asArgs[3] !== undefined) nCycles = +asArgs[3]; // warning: decimal instead of hex conversion
@@ -3167,6 +3189,13 @@ if (DEBUGGER) {
this.println("target speed: " + this.cpu.getSpeedTarget() + " (" + this.cpu.getSpeed() + "x)");
return;
+ default:
+ if (asArgs[1]) {
+ this.println("unknown option: " + asArgs[1]);
+ return;
+ }
+ /* falls through */
+
case "?":
this.println("debugger options:");
this.println("\tbase #\t\tset default base to #");
@@ -3175,13 +3204,6 @@ if (DEBUGGER) {
this.println("\tcs stop #\tset checksum cycle stop count to #");
this.println("\tsp #\t\tset speed multiplier to #");
break;
-
- default:
- if (asArgs[1]) {
- this.println("unknown option: " + asArgs[1]);
- return;
- }
- break;
}
};
@@ -3310,7 +3332,11 @@ if (DEBUGGER) {
if (!a) {
this.parseExpression(sCmd, true);
} else {
- this.println(this.replaceRegs(a[2]));
+ if (a[2].length > 1) {
+ this.println(this.replaceRegs(a[2]));
+ } else {
+ this.printValue(null, a[2].charCodeAt(0));
+ }
}
};
@@ -3644,7 +3670,9 @@ if (DEBUGGER) {
sCmd = "a " + this.toStrAddr(this.dbgAddrAssemble) + ' ' + sCmd;
}
+ var fError = false;
var asArgs = this.shiftArgs(sCmd.replace(/ +/g, ' ').split(' '));
+ asArgs[0] = asArgs[0].toLowerCase();
switch (asArgs[0].charAt(0)) {
case 'a':
@@ -3679,7 +3707,9 @@ if (DEBUGGER) {
if (!this.doIf(sCmd.substr(2), fQuiet)) {
result = false;
}
+ break;
}
+ fError = true;
break;
case 'k':
this.doStackTrace(asArgs[0], asArgs[1]);
@@ -3689,6 +3719,7 @@ if (DEBUGGER) {
this.doList(asArgs[1], true);
break;
}
+ fError = true;
break;
case 'm':
this.doMessages(asArgs);
@@ -3723,8 +3754,12 @@ if (DEBUGGER) {
}
break;
}
- this.println((PDP11.APPNAME || "PDP11") + " version " + (XMLVERSION || PDP11.APPVERSION) + " (" + this.cpu.model + (PDP11.COMPILED? ",RELEASE" : (PDP11.DEBUG? ",DEBUG" : ",NODEBUG")) + (PDP11.TYPEDARRAYS? ",TYPEDARRAYS" : (PDP11.BYTEARRAYS? ",BYTEARRAYS" : ",LONGARRAYS")) + ')');
- this.println(web.getUserAgent());
+ if (asArgs[0] == "ver") {
+ this.println((PDP11.APPNAME || "PDP11") + " version " + (XMLVERSION || PDP11.APPVERSION) + " (" + this.cpu.model + (PDP11.COMPILED? ",RELEASE" : (PDP11.DEBUG? ",DEBUG" : ",NODEBUG")) + (PDP11.TYPEDARRAYS? ",TYPEDARRAYS" : (PDP11.BYTEARRAYS? ",BYTEARRAYS" : ",LONGARRAYS")) + ')');
+ this.println(web.getUserAgent());
+ break;
+ }
+ fError = true;
break;
case '?':
if (asArgs[1]) {
@@ -3742,9 +3777,12 @@ if (DEBUGGER) {
if (this.doInfo(asArgs)) break;
/* falls through */
default:
+ fError = true;
+ break;
+ }
+ if (fError) {
this.println("unknown command: " + sCmd);
result = false;
- break;
}
}
} catch(e) {
diff --git a/modules/pdp11/lib/device.js b/modules/pdp11/lib/device.js
index 181343bd3..8e0f53d25 100644
--- a/modules/pdp11/lib/device.js
+++ b/modules/pdp11/lib/device.js
@@ -60,14 +60,6 @@ function DevicePDP11(parmsDevice)
Component.call(this, "Device", parmsDevice, DevicePDP11);
this.sDeviceName = parmsDevice['name'];
- this.tty = {
- rbuf: [],
- rcsr: 0,
- xcsr: PDP11.DL11.XCSR.READY,
- delCode: 127,
- del: 0
- };
-
this.display = {
data: 0,
address: 0,
@@ -268,67 +260,6 @@ DevicePDP11.prototype.writeMMR0 = function(data, addr)
this.display.misc = (this.display.misc & ~7) | idx;
};
-/**
- * readRCSR(addr)
- *
- * @this {DevicePDP11}
- * @param {number} addr (eg, PDP11.UNIBUS.RCSR or 177560)
- * @return {number}
- */
-DevicePDP11.prototype.readRCSR = function(addr)
-{
- return this.tty.rcsr;
-};
-
-/**
- * writeRCSR(data, addr)
- *
- * @this {DevicePDP11}
- * @param {number} data
- * @param {number} addr (eg, PDP11.UNIBUS.RCSR or 177560)
- */
-DevicePDP11.prototype.writeRCSR = function(data, addr)
-{
- this.tty.rcsr = (this.tty.rcsr & 0x80) | (data & ~0x80);
-};
-
-/**
- * readXCSR(addr)
- *
- * @this {DevicePDP11}
- * @param {number} addr (eg, PDP11.UNIBUS.XCSR or 177564)
- * @return {number}
- */
-DevicePDP11.prototype.readXCSR = function(addr)
-{
- return this.tty.xcsr;
-};
-
-/**
- * writeXCSR(data, addr)
- *
- * @this {DevicePDP11}
- * @param {number} data
- * @param {number} addr (eg, PDP11.UNIBUS.XCSR or 177564)
- */
-DevicePDP11.prototype.writeXCSR = function(data, addr)
-{
- /*
- * If the device is READY, and INT_ENABLE is transitioning to *set*, then generate an interrupt.
- */
- if ((this.tty.xcsr & (PDP11.DL11.XCSR.READY | PDP11.DL11.XCSR.INT_ENABLE)) == PDP11.DL11.XCSR.READY && (data & PDP11.DL11.XCSR.INT_ENABLE)) {
- var device = this;
- this.cpu.interrupt(PDP11.DL11.DELAY, PDP11.DL11.PRI, PDP11.DL11.VEC, function() {
- device.tty.xcsr |= PDP11.DL11.XCSR.READY;
- return !!(device.tty.xcsr & PDP11.DL11.XCSR.INT_ENABLE);
- });
- }
- /*
- * In any event, propagate all bits from data *except* for READY.
- */
- this.tty.xcsr = (this.tty.xcsr & PDP11.DL11.XCSR.READY) | (data & ~PDP11.DL11.XCSR.READY);
-};
-
/**
* readPSW(addr)
*
@@ -924,8 +855,6 @@ DevicePDP11.prototype.writeData = function(meta, block, address, count)
DevicePDP11.prototype.reset = function()
{
this.display.misc = (this.display.misc & ~0x77) | 0x14; // kernel 16 bit
- this.tty.rcsr = 0;
- this.tty.xcsr = 0x80; /*0200*/
this.kw11.lks = 0;
this.rk11.rkcs = 0x80; /*0200*/
this.rl11.csr = 0x80;
@@ -1110,7 +1039,7 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
}
break;
case 0x3FFF40: /*017777500*/ // 017777500 - 017777577
- var tty = this.tty;
+ // var tty = this.tty;
var kw11 = this.kw11;
switch (physicalAddress & ~1) {
case 0x3FFF7E: /*017777576*/ // MMR2
@@ -1155,44 +1084,44 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
if (result >= 0) this.display.data = result;
}
break;
- case 0x3FFF76: /*017777566*/ // console xbuf
- if (data >= 0) {
- data &= 0x7f;
- if (data) {
- switch (data) {
- case 0:
- case 0xD: /*015*/
- /*
- if (document.forms.console.line.value.length > 9000) {
- document.forms.console.line.value = document.forms.console.line.value.substring(document.forms.console.line.value.length - 8192);
- }
- */
- break;
- case 0x8: /*010*/
- /*
- if (!tty.del) {
- document.forms.console.line.value = document.forms.console.line.value.substring(0, document.forms.console.line.value.length - 1);
- }
- */
- break;
- default:
- /*
- document.forms.console.line.value += String.fromCharCode(data);
- if (data == 0x0A) {
- document.forms.console.line.scrollTop = document.forms.console.line.scrollHeight;
- }
- */
- }
- tty.del = 0;
- }
- tty.xcsr &= ~0x80; /*0200*/
- cpu.interrupt(100, 4, 0x34, /*064*/ function() {
- tty.xcsr |= 0x80; /*0200*/
- return !!(tty.xcsr & 0x40); /*0100*/
- });
- }
- result = 0;
- break;
+ // case 0x3FFF76: /*017777566*/ // console xbuf
+ // if (data >= 0) {
+ // data &= 0x7f;
+ // if (data) {
+ // switch (data) {
+ // case 0:
+ // case 0xD: /*015*/
+ // /*
+ // if (document.forms.console.line.value.length > 9000) {
+ // document.forms.console.line.value = document.forms.console.line.value.substring(document.forms.console.line.value.length - 8192);
+ // }
+ // */
+ // break;
+ // case 0x8: /*010*/
+ // /*
+ // if (!tty.del) {
+ // document.forms.console.line.value = document.forms.console.line.value.substring(0, document.forms.console.line.value.length - 1);
+ // }
+ // */
+ // break;
+ // default:
+ // /*
+ // document.forms.console.line.value += String.fromCharCode(data);
+ // if (data == 0x0A) {
+ // document.forms.console.line.scrollTop = document.forms.console.line.scrollHeight;
+ // }
+ // */
+ // }
+ // tty.del = 0;
+ // }
+ // tty.xcsr &= ~0x80; /*0200*/
+ // cpu.interrupt(100, 4, 0x34, /*064*/ function() {
+ // tty.xcsr |= 0x80; /*0200*/
+ // return !!(tty.xcsr & 0x40); /*0100*/
+ // });
+ // }
+ // result = 0;
+ // break;
// case 0x3FFF74: /*017777564*/ // console xcsr
// if (data < 0) {
// result = tty.xcsr;
@@ -1209,29 +1138,29 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
// }
// }
// break;
- case 0x3FFF72: /*017777562*/ // console rbuf
- result = 0;
- if (data < 0) {
- tty.rcsr &= ~0x80; /*0200*/
- if (tty.rbuf.length > 0) {
- result = tty.rbuf.shift();
- if (tty.rbuf.length > 0) {
- setTimeout(function() {
- tty.rcsr |= 0x80; /*0200*/
- if (tty.rcsr & 0x40) /*0100*/ cpu.interrupt(40, 4, 0x30) /*060*/;
- }, 50);
- }
- }
- }
- break;
- case 0x3FFF70: /*017777560*/ // console rcsr
- if (data < 0) {
- result = tty.rcsr;
- } else {
- result = this.insertData(tty.rcsr, physicalAddress, data, byteFlag);
- if (result >= 0) tty.rcsr = (tty.rcsr & 0x80) /*0200*/ | (result & ~0x80) /*0200*/;
- }
- break;
+ // case 0x3FFF72: /*017777562*/ // console rbuf
+ // result = 0;
+ // if (data < 0) {
+ // tty.rcsr &= ~0x80; /*0200*/
+ // if (tty.rbuf.length > 0) {
+ // result = tty.rbuf.shift();
+ // if (tty.rbuf.length > 0) {
+ // setTimeout(function() {
+ // tty.rcsr |= 0x80; /*0200*/
+ // if (tty.rcsr & 0x40) /*0100*/ cpu.interrupt(40, 4, 0x30) /*060*/;
+ // }, 50);
+ // }
+ // }
+ // }
+ // break;
+ // case 0x3FFF70: /*017777560*/ // console rcsr
+ // if (data < 0) {
+ // result = tty.rcsr;
+ // } else {
+ // result = this.insertData(tty.rcsr, physicalAddress, data, byteFlag);
+ // if (result >= 0) tty.rcsr = (tty.rcsr & 0x80) /*0200*/ | (result & ~0x80) /*0200*/;
+ // }
+ // break;
// case 0x3FFF66: /*017777546*/ // kw11.lks
// if (data < 0) {
// result = kw11.lks;
@@ -1539,8 +1468,6 @@ DevicePDP11.prototype.access = function(physicalAddress, data, byteFlag)
*/
DevicePDP11.UNIBUS_IOTABLE = {
[PDP11.UNIBUS.LKS]: /* 177546 */ [null, null, DevicePDP11.prototype.readLKS, DevicePDP11.prototype.writeLKS, "LKS"],
- [PDP11.UNIBUS.RCSR]: /* 177560 */ [null, null, DevicePDP11.prototype.readRCSR, DevicePDP11.prototype.writeRCSR, "RCSR"],
- [PDP11.UNIBUS.XCSR]: /* 177564 */ [null, null, DevicePDP11.prototype.readXCSR, DevicePDP11.prototype.writeXCSR, "XCSR"],
[PDP11.UNIBUS.MMR0]: /* 177572 */ [null, null, DevicePDP11.prototype.readMMR0, DevicePDP11.prototype.writeMMR0, "MMR0"],
[PDP11.UNIBUS.PSW]: /* 177776 */ [null, null, DevicePDP11.prototype.readPSW, DevicePDP11.prototype.writePSW, "PSW"]
};
diff --git a/modules/pdp11/lib/memory.js b/modules/pdp11/lib/memory.js
index c3543e669..6f7f841fc 100644
--- a/modules/pdp11/lib/memory.js
+++ b/modules/pdp11/lib/memory.js
@@ -59,18 +59,18 @@ var littleEndian = (TYPEDARRAYS? (function() {
/**
* MemoryPDP11(addr, used, size, type, controller)
*
- * The Bus component allocates MemoryPDP11 objects so that each has a memory buffer with a
+ * The Bus component allocates Memory 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 MemoryPDP11 object's underlying buffer can be either zero or bus.nBlockSize;
+ * the size of any given Memory 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 MemoryPDP11 objects as the ranges require. Partial MemoryPDP11 blocks could
+ * as many new blockSize Memory objects as the ranges require. Partial Memory blocks could
* also be supported in theory, but in practice, they're not.
*
- * Because MemoryPDP11 blocks now allow us to have a "sparse" address space, we could choose to
+ * Because Memory 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
@@ -84,7 +84,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 MemoryPDP11 blocks are low-level objects that have no UI requirements, they
+ * WARNING: Since Memory 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).
@@ -188,7 +188,7 @@ function MemoryPDP11(addr, used, size, type, controller)
* '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 MemoryPDP11 writeByteDirect() interface), allowing the ROM component to
+ * interface (which in turn uses the Memory writeByteDirect() interface), allowing the ROM component to
* initialize its own memory. The CONTROLLER type is used to identify memory-mapped devices that do not
* need any default storage and always provide their own controller.
*
@@ -237,7 +237,7 @@ MemoryPDP11.prototype = {
/**
* init(addr)
*
- * Quick reinitializer when reusing a MemoryPDP11 block.
+ * Quick reinitializer when reusing a Memory block.
*
* @this {MemoryPDP11}
* @param {number} addr
@@ -248,7 +248,7 @@ MemoryPDP11.prototype = {
/**
* clone(mem, type)
*
- * Converts the current MemoryPDP11 block (this) into a clone of the given MemoryPDP11 block (mem),
+ * Converts the current Memory block (this) into a clone of the given Memory block (mem),
* and optionally overrides the current block's type with the specified type.
*
* @this {MemoryPDP11}
@@ -289,10 +289,10 @@ MemoryPDP11.prototype = {
/**
* save()
*
- * This gets the contents of a MemoryPDP11 block as an array of 32-bit values; used by BusPDP11.saveMemory(),
- * which in turn is called by CPUStatePDP11.save().
+ * This gets the contents of a Memory block as an array of 32-bit values; used by Bus.saveMemory(),
+ * which in turn is called by CPUState.save().
*
- * MemoryPDP11 blocks with custom memory controllers do NOT save their contents; that's the responsibility
+ * Memory blocks with custom memory controllers do NOT save their contents; that's the responsibility
* of the controller component.
*
* @this {MemoryPDP11}
@@ -335,9 +335,9 @@ MemoryPDP11.prototype = {
/**
* restore(adw)
*
- * This restores the contents of a MemoryPDP11 block from an array of 32-bit values;
- * used by BusPDP11.restoreMemory(), which is called by CPUStatePDP11.restore(), after all other
- * components have been restored and thus all MemoryPDP11 blocks have been allocated
+ * 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
* by their respective components.
*
* @this {MemoryPDP11}
@@ -386,7 +386,7 @@ MemoryPDP11.prototype = {
* The afn parameter should be a 4-entry function table containing two byte handlers and
* two word handlers. See the static afnMemory table for an example.
*
- * If no function table is specified, a default is selected based on the MemoryPDP11 type;
+ * If no function table is specified, a default is selected based on the Memory type;
* similarly, any undefined entries in the table are filled with default handlers that fall
* back to the byte handlers, and if one or both byte handlers are undefined, they default
* to handlers that simply ignore the access.
@@ -469,7 +469,7 @@ MemoryPDP11.prototype = {
*/
printAddr: function(sMessage) {
if (DEBUG && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM)) {
- this.dbg.printMessage(sMessage + ' ' + (this.addr != null? ('%' + str.toHex(this.addr)) : '#' + this.id), true);
+ this.dbg.printMessage(sMessage + ' ' + (this.addr != null? ('@' + this.dbg.toStrBase(this.addr)) : '#' + this.id), true);
}
},
/**
@@ -548,7 +548,7 @@ MemoryPDP11.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
- * MemoryPDP11 interfaces have always returned values that are properly masked to 8, 16 or 32 bits, respectively.
+ * Memory interfaces have always returned values that are properly masked to 8, 16 or 32 bits, respectively.
*
* @this {MemoryPDP11}
* @param {number} off
@@ -557,7 +557,8 @@ MemoryPDP11.prototype = {
*/
readNone: function readNone(off, addr) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM) /* && !off */) {
- this.dbg.message("attempt to read invalid block %" + str.toHex(this.addr), true);
+ this.dbg.printMessage("attempt to read invalid block %" + str.toHex(this.addr), true);
+ this.dbg.stopCPU();
}
return 0xff;
},
@@ -571,7 +572,8 @@ MemoryPDP11.prototype = {
*/
writeNone: function writeNone(off, v, addr) {
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM) /* && !off */) {
- this.dbg.message("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
+ this.dbg.printMessage("attempt to write " + str.toHexWord(v) + " to invalid block %" + str.toHex(this.addr), true);
+ this.dbg.stopCPU();
}
},
/**
@@ -755,7 +757,7 @@ MemoryPDP11.prototype = {
readByteLE: function readByteLE(off, addr) {
var b = this.ab[off];
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM)) {
- this.dbg.message("Memory.readByteLE(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true);
+ this.dbg.printMessage("Memory.readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true);
}
return b;
},
@@ -785,7 +787,7 @@ MemoryPDP11.prototype = {
*/
var w = (off & 0x1)? (this.ab[off] | (this.ab[off+1] << 8)) : this.aw[off >> 1];
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM)) {
- this.dbg.message("Memory.readWordLE(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true);
+ this.dbg.printMessage("Memory.readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true);
}
return w;
},
@@ -813,7 +815,7 @@ MemoryPDP11.prototype = {
this.ab[off] = b;
this.fDirty = true;
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM)) {
- this.dbg.message("Memory.writeByteLE(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true);
+ this.dbg.printMessage("Memory.writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true);
}
},
/**
@@ -849,7 +851,7 @@ MemoryPDP11.prototype = {
}
this.fDirty = true;
if (DEBUGGER && this.dbg && this.dbg.messageEnabled(MessagesPDP11.MEM)) {
- this.dbg.message("Memory.writeWordLE(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true);
+ this.dbg.printMessage("Memory.writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true);
}
}
};
diff --git a/modules/pdp11/lib/rom.js b/modules/pdp11/lib/rom.js
index be9486101..a8d0844f8 100644
--- a/modules/pdp11/lib/rom.js
+++ b/modules/pdp11/lib/rom.js
@@ -342,7 +342,9 @@ ROMPDP11.prototype.addROM = function(addr)
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++) {
+ if (DEBUGGER && this.dbg) this.dbg.disableMessages();
this.bus.setByteDirect(addr + i, this.abROM[i]);
+ if (DEBUGGER && this.dbg) this.dbg.enableMessages();
}
return true;
}
diff --git a/modules/pdp11/lib/serialport.js b/modules/pdp11/lib/serialport.js
new file mode 100644
index 000000000..bb94d0465
--- /dev/null
+++ b/modules/pdp11/lib/serialport.js
@@ -0,0 +1,694 @@
+/**
+ * @fileoverview Implements the PDP11 SerialPort component.
+ * @author Jeff Parsons
+ * @version 1.0
+ * Created 2016-Oct-04
+ *
+ * This file is part of PCjs, a computer emulation software project at .
+ *
+ * It has been adapted from the JavaScript PDP 11/70 Emulator v1.3 written by Paul Nankervis
+ * (paulnank@hotmail.com) as of August 2016 from http://skn.noip.me/pdp11/pdp11.html. This code
+ * may be used freely provided the original author name is acknowledged in any modified source code.
+ *
+ * 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 .
+ *
+ * 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 str = require("../../shared/lib/strlib");
+ var web = require("../../shared/lib/weblib");
+ var Component = require("../../shared/lib/component");
+ var State = require("../../shared/lib/state");
+ var PDP11 = require("./defines");
+ var MessagesPDP11 = require("./messages");
+}
+
+/**
+ * SerialPortPDP11(parmsSerial)
+ *
+ * The SerialPort component has the following component-specific (parmsSerial) properties:
+ *
+ * adapter: adapter number; 0 if not defined
+ *
+ * binding: name of a control (based on its "binding" attribute) to bind to this port's I/O
+ *
+ * tabSize: set to a non-zero number to convert tabs to spaces (applies only to output to
+ * the above binding); default is 0 (no conversion)
+ *
+ * In the future, we may support 'port' and 'irq' properties that allow the machine to define a
+ * non-standard serial port configuration, instead of only our pre-defined 'adapter' configurations.
+ *
+ * NOTE: Since the XSL file defines 'adapter' as a number, not a string, there's no need to use
+ * parseInt(), and as an added benefit, we don't need to worry about whether a hex or decimal format
+ * was used.
+ *
+ * @constructor
+ * @extends Component
+ * @param {Object} parmsSerial
+ */
+function SerialPortPDP11(parmsSerial) {
+
+ this.iAdapter = parmsSerial['adapter'];
+
+ this.tty = {
+ rbuf: [],
+ rcsr: 0,
+ xcsr: PDP11.DL11.XCSR.READY,
+ delCode: 127,
+ del: 0
+ };
+
+ /**
+ * consoleOutput becomes a string that records serial port output if the 'binding' property is set to the
+ * reserved name "console". Nothing is written to the console, however, until a linefeed (0x0A) is output
+ * or the string length reaches a threshold (currently, 1024 characters).
+ *
+ * @type {string|null}
+ */
+ this.consoleOutput = null;
+
+ /**
+ * 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}
+ */
+ this.controlIOBuffer = null;
+
+ /*
+ * If controlIOBuffer is being used AND 'tabSize' is set, then we make an attempt to monitor the characters
+ * 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
+ * isn't generally useful; I use it internally to preformat serial output.
+ */
+ this.tabSize = parmsSerial['tabSize'];
+ this.charBOL = parmsSerial['charBOL'];
+ this.iLogicalCol = 0;
+
+ Component.call(this, "SerialPort", parmsSerial, SerialPortPDP11, MessagesPDP11.SERIAL);
+
+ var sBinding = parmsSerial['binding'];
+ if (sBinding == "console") {
+ this.consoleOutput = "";
+ } else {
+ /*
+ * NOTE: If sBinding is not the name of a valid Control Panel DOM element, this call does nothing.
+ */
+ Component.bindExternalControl(this, sBinding, SerialPortPDP11.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 (no flow control yet).
+ */
+ this['exports'] = {
+ 'connect': this.initConnection,
+ 'receiveData': this.receiveData
+ };
+}
+
+/*
+ * class SerialPortPDP11
+ * property {number} iAdapter
+ * property {number} portBase
+ * property {number} nIRQ
+ * 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
+ * initializing such properties in the constructor is a better way to go -- even though it's more code -- because
+ * JavaScript compilers are supposed to be happier when the underlying object structures aren't constantly changing.
+ *
+ * Besides, I'm not sure I want to get into documenting every property this way, for this or any/every other class,
+ * let alone getting into which ones should be considered private or protected, because PCjs isn't really a library
+ * for third-party apps.
+ */
+
+Component.subclass(SerialPortPDP11);
+
+/*
+ * Internal name used for the I/O buffer control, if any, that we bind to the SerialPort.
+ *
+ * Alternatively, if SerialPort 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
+ * been hard-coded to "Panel", in part because that's one of the few components we can rely
+ * 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.
+ */
+SerialPortPDP11.sIOBuffer = "buffer";
+
+/**
+ * setBinding(sHTMLType, sBinding, control, sValue)
+ *
+ * @this {SerialPortPDP11}
+ * @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
+ */
+SerialPortPDP11.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
+{
+ var serial = this;
+
+ switch (sBinding) {
+ case SerialPortPDP11.sIOBuffer:
+ 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).
+ */
+ 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 keyCode = event.keyCode;
+ if (keyCode === 0x08 || event.ctrlKey && keyCode >= 0x41 && keyCode <= 0x5A) {
+ if (event.preventDefault) event.preventDefault();
+ if (keyCode > 0x40) keyCode -= 0x40;
+ serial.receiveData(keyCode);
+ }
+ return true;
+ };
+
+ control.onkeypress = function onKeyPress(event) {
+ /*
+ * Browser-independent keyCode extraction; refer to onKeyPress() and the other key event
+ * handlers in keyboard.js.
+ */
+ event = event || window.event;
+ var keyCode = event.which || event.keyCode;
+ serial.receiveData(keyCode);
+ /*
+ * Since we're going to remove the "readonly" attribute from the