Merge branch 'next-release'
This commit is contained in:
commit
fdab27f44d
15 changed files with 712 additions and 557 deletions
|
|
@ -111,13 +111,25 @@ Keyboard8080.WASDCODES[Keys.ASCII.D] = Keys.KEYCODE.RIGHT;
|
|||
Keyboard8080.WASDCODES[Keys.ASCII.L] = Keys.KEYCODE.SPACE;
|
||||
|
||||
/*
|
||||
* Supported configurations
|
||||
* Supported keyboard configurations.
|
||||
*
|
||||
* A word (or two) about SOFTCODES. Their main purpose is to provide a naming convention for machine-specific
|
||||
* controls, without tying us to any particular keyboard mapping. They are used in two main ways.
|
||||
*
|
||||
* First, if we have a binding to the machine's "screen", there will, at a minimum, be onkeydown and onkeyup
|
||||
* handlers attached to the screen, and those handlers will need to iterate through the SOFTCODES table, looking
|
||||
* for key codes that we care about and converting them to corresponding soft codes. Some machines, like
|
||||
* Space Invaders, will then act directly upon the soft code (eg, converting it to a machine-specific status bit).
|
||||
*
|
||||
* Second, a machine may have other bindings (eg, buttons) to one or more of these soft codes, and those bindings
|
||||
* will need to know which key codes they're supposed to generate. Some machines, like the VT100, will then use
|
||||
* another table (KEYMAP) to convert key codes into a machine-specific "key addresses".
|
||||
*/
|
||||
Keyboard8080.SI1978 = {
|
||||
MODEL: 1978.1,
|
||||
KEYMAP: {},
|
||||
ALTCODES: Keyboard8080.WASDCODES,
|
||||
LEDCODES: {},
|
||||
KEYMAP: {},
|
||||
ALTCODES: Keyboard8080.WASDCODES,
|
||||
LEDCODES: {},
|
||||
SOFTCODES: {
|
||||
'1p': Keys.KEYCODE.ONE,
|
||||
'2p': Keys.KEYCODE.TWO,
|
||||
|
|
@ -234,7 +246,7 @@ Keyboard8080.VT100 = {
|
|||
ALTCODES: {},
|
||||
LEDCODES: {},
|
||||
SOFTCODES: {
|
||||
'num-comma': Keys.KEYCODE.F5, // since modern keypads don't typically have a comma...
|
||||
'num-comma': Keys.KEYCODE.F5,// since modern keypads don't typically have a comma...
|
||||
'break': Keys.KEYCODE.F6,
|
||||
'line-feed': Keys.KEYCODE.F7,
|
||||
'no-scroll': Keys.KEYCODE.F8,
|
||||
|
|
@ -277,7 +289,7 @@ Keyboard8080.VT100 = {
|
|||
CLICK: 0x80,
|
||||
INIT: 0x00
|
||||
},
|
||||
KEYLAST: 0x7F // special end-of-scan key address (all valid key addresses are < KEYLAST)
|
||||
KEYLAST: 0x7F // special end-of-scan key address (all valid key addresses are < KEYLAST)
|
||||
};
|
||||
|
||||
Keyboard8080.VT100.LEDCODES = {
|
||||
|
|
@ -312,17 +324,17 @@ Keyboard8080.MODELS = {
|
|||
Keyboard8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
{
|
||||
/*
|
||||
* There's a special binding that the Video component uses ("kbd") to effectively bind its
|
||||
* There's a special binding that the Video component uses ("screen") to effectively bind its
|
||||
* screen to the entire keyboard, in Video.powerUp(); ie:
|
||||
*
|
||||
* video.kbd.setBinding("canvas", "kbd", video.canvasScreen);
|
||||
* video.kbd.setBinding("canvas", "screen", video.canvasScreen);
|
||||
* or:
|
||||
* video.kbd.setBinding("textarea", "kbd", video.textareaScreen);
|
||||
* video.kbd.setBinding("textarea", "screen", video.textareaScreen);
|
||||
*
|
||||
* However, it's also possible for the keyboard XML definition to define a control that serves
|
||||
* a similar purpose; eg:
|
||||
*
|
||||
* <control type="text" binding="kbd" width="2em">Kbd</control>
|
||||
* <control type="text" binding="kbd" width="2em">Keyboard</control>
|
||||
*
|
||||
* The latter is purely experimental, while we work on finding ways to trigger the soft keyboard on
|
||||
* certain pesky devices (like the Kindle Fire). Note that even if you use the latter, the former will
|
||||
|
|
@ -341,10 +353,11 @@ Keyboard8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValu
|
|||
|
||||
switch (sBinding) {
|
||||
case "kbd":
|
||||
case "screen":
|
||||
/*
|
||||
* Recording the binding ID prevents multiple controls (or components) from attempting to erroneously
|
||||
* bind a control to the same ID, but in the case of a "dual display" configuration, we actually want
|
||||
* to allow BOTH video components to call setBinding() for "kbd", so that it doesn't matter which
|
||||
* to allow BOTH video components to call setBinding() for "screen", so that it doesn't matter which
|
||||
* display the user gives focus to.
|
||||
*
|
||||
* this.bindings[id] = control;
|
||||
|
|
@ -366,14 +379,14 @@ Keyboard8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValu
|
|||
default:
|
||||
if (this.config.SOFTCODES && this.config.SOFTCODES[sBinding] !== undefined) {
|
||||
this.bindings[id] = control;
|
||||
var fnDown = function(kbd, softCode) {
|
||||
control.onclick = function(kbd, keyCode) {
|
||||
return function onKeyboardBindingDown(event) {
|
||||
/*
|
||||
* iOS Usability Improvement: Calling preventDefault() prevents rapid clicks from
|
||||
* also being (mis)interpreted as a desire to "zoom" in on the machine.
|
||||
*/
|
||||
if (event.preventDefault) event.preventDefault();
|
||||
kbd.onSoftKeyDown(softCode, true);
|
||||
kbd.onSoftKeyDown(keyCode, true, true);
|
||||
/*
|
||||
* I'm assuming we only need to give focus back on the "up" event...
|
||||
*
|
||||
|
|
@ -381,26 +394,38 @@ Keyboard8080.prototype.setBinding = function(sHTMLType, sBinding, control, sValu
|
|||
*/
|
||||
};
|
||||
}(this, this.config.SOFTCODES[sBinding]);
|
||||
var fnUp = function (kbd, softCode) {
|
||||
return function onKeyboardBindingUp(event) {
|
||||
kbd.onSoftKeyDown(softCode, false);
|
||||
/*
|
||||
* Give focus back to the machine (since clicking the button takes focus away).
|
||||
*
|
||||
* if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
*
|
||||
* iOS Usability Improvement: NOT calling updateFocus() keeps the soft keyboard down
|
||||
* (assuming it was already down).
|
||||
*/
|
||||
};
|
||||
}(this, this.config.SOFTCODES[sBinding]);
|
||||
if ('ontouchstart' in window) {
|
||||
control.ontouchstart = fnDown;
|
||||
control.ontouchend = fnUp;
|
||||
} else {
|
||||
control.onmousedown = fnDown;
|
||||
control.onmouseup = control.onmouseout = fnUp;
|
||||
}
|
||||
//
|
||||
// var fnUp = function (kbd, keyCode) {
|
||||
// return function onKeyboardBindingUp(event) {
|
||||
// kbd.onSoftKeyDown(keyCode, false);
|
||||
// /*
|
||||
// * Give focus back to the machine (since clicking the button takes focus away).
|
||||
// *
|
||||
// * if (kbd.cmp) kbd.cmp.updateFocus();
|
||||
// *
|
||||
// * iOS Usability Improvement: NOT calling updateFocus() keeps the soft keyboard down
|
||||
// * (assuming it was already down).
|
||||
// */
|
||||
// };
|
||||
// }(this, this.config.SOFTCODES[sBinding]);
|
||||
//
|
||||
// if ('ontouchstart' in window) {
|
||||
// control.ontouchstart = fnDown;
|
||||
// control.ontouchend = fnUp;
|
||||
// } else {
|
||||
// control.onmousedown = fnDown;
|
||||
// control.onmouseup = control.onmouseout = fnUp;
|
||||
// }
|
||||
//
|
||||
// UPDATE: Since the only controls that we explicitly bind to SOFTCODES are buttons, I'm simplifying
|
||||
// the above code with a conventional "onclick" handler. The only corresponding change I had to make
|
||||
// to the onclick (formerly fnDown) function was to set fAutoRelease on its call to onSoftKeyDown(),
|
||||
// since we're no longer attempting to detect when the control (ie, the button) is actually released.
|
||||
//
|
||||
// This change also resolves a problem I ran into with the Epiphany (WebKit-based) web browser running
|
||||
// on the "elementary" (Ubuntu-based) OS, where clicks on the SET-UP button were ignored; perhaps its
|
||||
// buttons don't generate mouse and/or touch events. Anyway, an argument for keeping things simple.
|
||||
//
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
|
@ -848,17 +873,17 @@ Keyboard8080.prototype.onSoftKeyDown = function(softCode, fDown, fAutoRelease)
|
|||
var i = this.indexOfSoftKey(softCode);
|
||||
if (fDown) {
|
||||
// this.println(softCode + " down");
|
||||
fAutoRelease = fAutoRelease || false;
|
||||
if (i < 0) {
|
||||
this.aKeysActive.push({
|
||||
softCode: softCode,
|
||||
msDown: Date.now(),
|
||||
fAutoRelease: fAutoRelease
|
||||
fAutoRelease: fAutoRelease || false
|
||||
});
|
||||
} else {
|
||||
this.aKeysActive[i].msDown = Date.now();
|
||||
this.aKeysActive[i].fAutoRelease = fAutoRelease;
|
||||
this.aKeysActive[i].fAutoRelease = fAutoRelease || false;
|
||||
}
|
||||
if (fAutoRelease) this.checkSoftKeysToRelease(); // prime the pump
|
||||
} else if (i >= 0) {
|
||||
// this.println(softCode + " up");
|
||||
if (!this.aKeysActive[i].fAutoRelease) {
|
||||
|
|
|
|||
|
|
@ -421,7 +421,7 @@ Video8080.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
this.kbd.setBinding("led", s, this.ledBindings[s]);
|
||||
}
|
||||
if (this.canvasScreen) {
|
||||
this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "kbd", this.inputScreen);
|
||||
this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "screen", this.inputScreen);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -951,17 +951,17 @@ Keyboard.LIMIT = {
|
|||
Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
||||
{
|
||||
/*
|
||||
* There's a special binding that the Video component uses ("kbd") to effectively bind its
|
||||
* There's a special binding that the Video component uses ("screen") to effectively bind its
|
||||
* screen to the entire keyboard, in Video.powerUp(); ie:
|
||||
*
|
||||
* video.kbd.setBinding("canvas", "kbd", video.canvasScreen);
|
||||
* video.kbd.setBinding("canvas", "screen", video.canvasScreen);
|
||||
* or:
|
||||
* video.kbd.setBinding("textarea", "kbd", video.textareaScreen);
|
||||
* video.kbd.setBinding("textarea", "screen", video.textareaScreen);
|
||||
*
|
||||
* However, it's also possible for the keyboard XML definition to define a control that serves
|
||||
* a similar purpose; eg:
|
||||
*
|
||||
* <control type="text" binding="kbd" width="2em">Kbd</control>
|
||||
* <control type="text" binding="kbd" width="2em">Keyboard</control>
|
||||
*
|
||||
* The latter is purely experimental, while we work on finding ways to trigger the soft keyboard on
|
||||
* certain pesky devices (like the Kindle Fire). Note that even if you use the latter, the former will
|
||||
|
|
@ -974,10 +974,11 @@ Keyboard.prototype.setBinding = function(sHTMLType, sBinding, control, sValue)
|
|||
if (this.bindings[id] === undefined) {
|
||||
switch (sBinding) {
|
||||
case "kbd":
|
||||
case "screen":
|
||||
/*
|
||||
* Recording the binding ID prevents multiple controls (or components) from attempting to erroneously
|
||||
* bind a control to the same ID, but in the case of a "dual display" configuration, we actually want
|
||||
* to allow BOTH video components to call setBinding() for "kbd", so that it doesn't matter which
|
||||
* to allow BOTH video components to call setBinding() for "screen", so that it doesn't matter which
|
||||
* display the user gives focus to.
|
||||
*
|
||||
* this.bindings[id] = control;
|
||||
|
|
|
|||
|
|
@ -2961,7 +2961,7 @@ Video.prototype.initBus = function(cmp, bus, cpu, dbg)
|
|||
for (var s in this.bindings) {
|
||||
if (s.indexOf("lock") > 0) this.kbd.setBinding("led", s, this.bindings[s]);
|
||||
}
|
||||
this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "kbd", this.inputScreen);
|
||||
this.kbd.setBinding(this.textareaScreen? "textarea" : "canvas", "screen", this.inputScreen);
|
||||
}
|
||||
|
||||
this.bEGASwitches = 0x09; // our default "switches" setting (see aEGAMonitorSwitches)
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ BusPDP11.IOHANDLER = {
|
|||
WRITE_BYTE: 1,
|
||||
READ_WORD: 2,
|
||||
WRITE_WORD: 3,
|
||||
NAME: 4,
|
||||
REG_NAME: 4,
|
||||
MSG_CATEGORY: 5,
|
||||
DBG_BREAK: 6
|
||||
};
|
||||
|
|
@ -235,6 +235,10 @@ BusPDP11.IOController = {
|
|||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryRead(addr, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
|
|
@ -268,7 +272,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (b >= 0) {
|
||||
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);
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.REG_NAME] + ".readByte(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(b), true, !bus.nDisableFaults);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
|
@ -295,6 +299,10 @@ BusPDP11.IOController = {
|
|||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryWrite(addr, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
|
|
@ -349,7 +357,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (fWrite) {
|
||||
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);
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.REG_NAME] + ".writeByte(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(b) + ")", true, !bus.nDisableFaults);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -373,6 +381,10 @@ BusPDP11.IOController = {
|
|||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryRead(addr, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
|
|
@ -388,7 +400,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (w >= 0) {
|
||||
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);
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.REG_NAME] + ".readWord(" + this.dbg.toStrBase(addr) + "): " + this.dbg.toStrBase(w), true, !bus.nDisableFaults);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
|
@ -414,6 +426,10 @@ BusPDP11.IOController = {
|
|||
var bus = this.controller;
|
||||
var afn = bus.aIOHandlers[off];
|
||||
|
||||
if (DEBUGGER && this.dbg) {
|
||||
this.dbg.checkMemoryWrite(addr, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since addr is primarily used to advise an I/O handler of the target IOPAGE address, and since we don't want
|
||||
* our handlers to worry about the current IOPAGE location, we truncate addr to 16 bits (the IOPAGE's lowest location).
|
||||
|
|
@ -432,7 +448,7 @@ BusPDP11.IOController = {
|
|||
}
|
||||
if (fWrite) {
|
||||
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);
|
||||
this.dbg.printMessage(afn[BusPDP11.IOHANDLER.REG_NAME] + ".writeWord(" + this.dbg.toStrBase(addr) + "," + this.dbg.toStrBase(w) + ")", true, !bus.nDisableFaults);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -467,11 +483,14 @@ BusPDP11.prototype.initMemory = function()
|
|||
for (var iBlock = 0; iBlock < this.nBlockTotal; iBlock++) {
|
||||
this.aBusBlocks[iBlock] = this.aMemBlocks[iBlock] = block;
|
||||
}
|
||||
/*
|
||||
* NOTE: Don't confuse the Bus addrIOPage with the CPU's addrIOPage; ours is fixed,
|
||||
* based on the machine's Bus width, whereas the CPU's varies according to the MMU setting.
|
||||
*/
|
||||
this.addrIOPage = this.addrTotal - BusPDP11.IOPAGE_LENGTH;
|
||||
this.addMemory(this.addrIOPage, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
|
||||
|
||||
var addrIOPage = this.addrTotal - BusPDP11.IOPAGE_LENGTH;
|
||||
this.addMemory(addrIOPage, BusPDP11.IOPAGE_LENGTH, MemoryPDP11.TYPE.CONTROLLER, this);
|
||||
|
||||
this.iBlockIOPageBus = (addrIOPage & this.nBusMask) >>> this.nBlockShift;
|
||||
this.iBlockIOPageBus = (this.addrIOPage & this.nBusMask) >>> this.nBlockShift;
|
||||
this.iBlockIOPageMem = this.iBlockIOPageBus;
|
||||
|
||||
this.nIOPageRange = 0;
|
||||
|
|
@ -1224,13 +1243,16 @@ BusPDP11.prototype.getMemoryLimit = function(type)
|
|||
*/
|
||||
BusPDP11.prototype.addIOHandlers = function(start, end, fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, message, sName)
|
||||
{
|
||||
var index = (start == end? -1 : 0);
|
||||
for (var addr = start; addr <= end; addr += 2) {
|
||||
var off = addr & BusPDP11.IOPAGE_MASK;
|
||||
if (this.aIOHandlers[off] !== undefined) {
|
||||
Component.warning("I/O address already registered: " + str.toHexLong(addr));
|
||||
return false;
|
||||
}
|
||||
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, sName || "unknown", message || MessagesPDP11.BUS, false];
|
||||
var s = sName || "unknown";
|
||||
if (s && index >= 0) s += index++;
|
||||
this.aIOHandlers[off] = [fnReadByte, fnWriteByte, fnReadWord, fnWriteWord, s, message || MessagesPDP11.BUS, false];
|
||||
if (MAXDEBUG) this.log("addIOHandlers(" + str.toHexLong(addr) + ")");
|
||||
}
|
||||
return true;
|
||||
|
|
@ -1298,6 +1320,48 @@ BusPDP11.prototype.addIOTable = function(component, table, offReg)
|
|||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* getAddrInfo(addr)
|
||||
*
|
||||
* Determine if the physical address is a known IOPAGE address, and return information about it (ie, the name).
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
* @param {number} addr (physical)
|
||||
* @return {string|null}
|
||||
*/
|
||||
BusPDP11.prototype.getAddrInfo = function(addr)
|
||||
{
|
||||
var sName = null;
|
||||
if (addr >= this.addrIOPage) {
|
||||
var off = addr & BusPDP11.IOPAGE_MASK;
|
||||
var afn = this.aIOHandlers[off];
|
||||
if (afn) sName = afn[BusPDP11.IOHANDLER.REG_NAME];
|
||||
}
|
||||
return sName;
|
||||
};
|
||||
|
||||
/**
|
||||
* getAddrByName(sName)
|
||||
*
|
||||
* Determine if the specified name has a corresponding physical address.
|
||||
*
|
||||
* @this {BusPDP11}
|
||||
* @param {string} sName
|
||||
* @return {number|null}
|
||||
*/
|
||||
BusPDP11.prototype.getAddrByName = function(sName)
|
||||
{
|
||||
sName = sName.toUpperCase();
|
||||
for (var i in this.aIOHandlers) {
|
||||
var off = +i;
|
||||
var afn = this.aIOHandlers[off];
|
||||
if (afn[BusPDP11.IOHANDLER.REG_NAME] == sName) {
|
||||
return off + this.addrIOPage;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* addResetHandler(fnReset)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1250,6 +1250,20 @@ if (DEBUGGER) {
|
|||
return value;
|
||||
};
|
||||
|
||||
/**
|
||||
* getSymbolValue(sSymbol)
|
||||
*
|
||||
* NOTE: At this time, the only symbols we support are those IOPAGE symbols that the Bus component knows about.
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
* @param {string} sSymbol
|
||||
* @return {number|undefined|null}
|
||||
*/
|
||||
DebuggerPDP11.prototype.getSymbolValue = function(sSymbol)
|
||||
{
|
||||
return this.bus.getAddrByName(sSymbol);
|
||||
};
|
||||
|
||||
/**
|
||||
* replaceRegs(s)
|
||||
*
|
||||
|
|
@ -2206,8 +2220,7 @@ if (DEBUGGER) {
|
|||
|
||||
/*
|
||||
* If getOperand() returns an Array rather than a string, then the first element is the original
|
||||
* operand, and the second element contains an alternate representation of the operand (eg, target
|
||||
* address, memory contents, etc).
|
||||
* operand, and the second element contains additional information (eg, the target) of the operand.
|
||||
*/
|
||||
if (typeof sOperand != "string") {
|
||||
sTarget = sOperand[1];
|
||||
|
|
@ -2239,7 +2252,10 @@ if (DEBUGGER) {
|
|||
var nCycles = this.cpu.getCycles();
|
||||
sLine += "cycles=" + nCycles.toString() + " cs=" + str.toHex(this.cpu.nChecksum);
|
||||
}
|
||||
if (sTarget) sLine += " @" + sTarget;
|
||||
if (sTarget) {
|
||||
if (sLine.slice(-1) != ';') sLine += ' ';
|
||||
sLine += sTarget;
|
||||
}
|
||||
}
|
||||
return sLine;
|
||||
};
|
||||
|
|
@ -2248,11 +2264,8 @@ if (DEBUGGER) {
|
|||
* getOperand(opCode, opType, dbgAddr)
|
||||
*
|
||||
* If getOperand() returns an Array rather than a string, then the first element is the original
|
||||
* operand, and the second element is a comment containing an alternate representation of the operand.
|
||||
*
|
||||
* TODO: For PC-relative addresses, we now return the effective address directly, rather than as the
|
||||
* second element of an Array; however, I still envision using Array return values to include current
|
||||
* memory operands, so support for such values is being left in place.
|
||||
* operand, and the second element is a comment containing additional information (eg, the target)
|
||||
* of the operand.
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
* @param {number} opCode
|
||||
|
|
@ -2295,6 +2308,7 @@ if (DEBUGGER) {
|
|||
* Isolate all OP_SRC or OP_DST bits from opcode in the opMode variable.
|
||||
*/
|
||||
var opMode = opCode & opType;
|
||||
|
||||
/*
|
||||
* Convert OP_SRC bits into OP_DST bits, since they use the same format.
|
||||
*/
|
||||
|
|
@ -2304,18 +2318,23 @@ if (DEBUGGER) {
|
|||
}
|
||||
if (opType & DebuggerPDP11.OP_DST) {
|
||||
var wIndex;
|
||||
var sTarget = null;
|
||||
var reg = opMode & DebuggerPDP11.OP_DSTREG;
|
||||
/*
|
||||
* Note that opcodes that specify only REG bits in the opType mask (ie, no MOD bits)
|
||||
* will automatically default to OPMODE_REG below.
|
||||
*/
|
||||
switch((opMode & DebuggerPDP11.OP_DSTMODE)) {
|
||||
|
||||
case PDP11.OPMODE.REG: // 0x0: REGISTER
|
||||
sOperand = this.getRegName(reg);
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.REGD: // 0x1: REGISTER DEFERRED
|
||||
sOperand = '@' + this.getRegName(reg);
|
||||
sTarget = this.getTarget(this.cpu.regsGen[reg]);
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.POSTINC: // 0x2: POST-INCREMENT
|
||||
if (reg < 7) {
|
||||
sOperand = '(' + this.getRegName(reg) + ")+";
|
||||
|
|
@ -2327,6 +2346,7 @@ if (DEBUGGER) {
|
|||
sOperand = '#' + this.toStrBase(wIndex, 0, true);
|
||||
}
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.POSTINCD: // 0x3: POST-INCREMENT DEFERRED
|
||||
if (reg < 7) {
|
||||
sOperand = "@(" + this.getRegName(reg) + ")+";
|
||||
|
|
@ -2336,14 +2356,18 @@ if (DEBUGGER) {
|
|||
*/
|
||||
wIndex = this.getWord(dbgAddr, 2);
|
||||
sOperand = "@#" + this.toStrBase(wIndex, 0, true);
|
||||
sTarget = this.getTarget(wIndex);
|
||||
}
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.PREDEC: // 0x4: PRE-DECREMENT
|
||||
sOperand = "-(" + this.getRegName(reg) + ")";
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.PREDECD: // 0x5: PRE-DECREMENT DEFERRED
|
||||
sOperand = "@-(" + this.getRegName(reg) + ")";
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.INDEX: // 0x6: INDEX
|
||||
wIndex = this.getWord(dbgAddr, 2);
|
||||
sOperand = this.toStrBase(wIndex, 0, true) + '(' + this.getRegName(reg) + ')';
|
||||
|
|
@ -2362,9 +2386,11 @@ if (DEBUGGER) {
|
|||
*
|
||||
* sOperand = [sOperand, this.toStrBase((wIndex + dbgAddr.addr) & 0xffff)];
|
||||
*/
|
||||
sOperand = this.toStrBase((wIndex + dbgAddr.addr) & 0xffff);
|
||||
sOperand = this.toStrBase(wIndex = (wIndex + dbgAddr.addr) & 0xffff);
|
||||
sTarget = this.getTarget(wIndex);
|
||||
}
|
||||
break;
|
||||
|
||||
case PDP11.OPMODE.INDEXD: // 0x7: INDEX DEFERRED
|
||||
wIndex = this.getWord(dbgAddr, 2);
|
||||
sOperand = '@' + this.toStrBase(wIndex) + '(' + this.getRegName(reg) + ')';
|
||||
|
|
@ -2375,13 +2401,17 @@ if (DEBUGGER) {
|
|||
*
|
||||
* sOperand = [sOperand, this.toStrBase((wIndex + dbgAddr.addr) & 0xffff)];
|
||||
*/
|
||||
sOperand = '@' + this.toStrBase((wIndex + dbgAddr.addr) & 0xffff);
|
||||
sOperand = '@' + this.toStrBase(wIndex = (wIndex + dbgAddr.addr) & 0xffff);
|
||||
sTarget = this.getTarget(this.cpu.getWordSafe(wIndex));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
this.assert(false);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sTarget) sOperand = [sOperand, sTarget];
|
||||
}
|
||||
else {
|
||||
this.assert(false);
|
||||
|
|
@ -2390,6 +2420,24 @@ if (DEBUGGER) {
|
|||
return sOperand;
|
||||
};
|
||||
|
||||
/**
|
||||
* getTarget(addr)
|
||||
*
|
||||
* @this {DebuggerPDP11}
|
||||
* @param {number} addr
|
||||
* @return {string|null}
|
||||
*/
|
||||
DebuggerPDP11.prototype.getTarget = function(addr)
|
||||
{
|
||||
var sTarget = null;
|
||||
var a = this.cpu.getAddrInfo(addr);
|
||||
var addrPhysical = a[0];
|
||||
if (addrPhysical >= this.cpu.addrIOPage && addrPhysical < this.bus.addrIOPage) {
|
||||
addrPhysical = (addrPhysical - this.cpu.addrIOPage) + this.bus.addrIOPage;
|
||||
}
|
||||
return this.bus.getAddrInfo(addrPhysical);
|
||||
};
|
||||
|
||||
/**
|
||||
* parseInstruction(sOp, sOperand, addr)
|
||||
*
|
||||
|
|
|
|||
|
|
@ -179,6 +179,20 @@ if (DEBUGGER) {
|
|||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* getSymbolValue(sSymbol)
|
||||
*
|
||||
* NOTE: This must be implemented by the individual debuggers.
|
||||
*
|
||||
* @this {Debugger}
|
||||
* @param {string} sSymbol
|
||||
* @return {number|undefined|null}
|
||||
*/
|
||||
Debugger.prototype.getSymbolValue = function(sSymbol)
|
||||
{
|
||||
return undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* parseAddrReference(s, sAddr)
|
||||
*
|
||||
|
|
@ -577,7 +591,12 @@ if (DEBUGGER) {
|
|||
value = this.getRegValue(iReg);
|
||||
} else {
|
||||
value = this.getVariable(sValue);
|
||||
if (value == null) value = str.parseInt(sValue, this.nBase);
|
||||
if (value == null) {
|
||||
value = this.getSymbolValue(sValue);
|
||||
if (value == null) {
|
||||
value = str.parseInt(sValue, this.nBase);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value == null && !fQuiet) this.println("invalid " + (sName? sName : "value") + ": " + sValue);
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Reference in a new issue