Added a few PDP-10 byte pointer fixes, along with the ability to pass MACRO-10 text directly into the MACRO-10 assembler (use the Debugger's "as" command)
This commit is contained in:
parent
38f709bb7a
commit
d28d1ee940
10 changed files with 481 additions and 375 deletions
|
|
@ -7,7 +7,7 @@ machines:
|
|||
type: pdp10
|
||||
config: /devices/pdp10/machine/ka10/test/debugger/machine.xml
|
||||
debugger: true
|
||||
commands: a dakam.mac
|
||||
commands: a dakam.mac;g 033352
|
||||
---
|
||||
|
||||
PDP-10 KA10 Basic Instruction Diagnostic #13
|
||||
|
|
|
|||
|
|
@ -257,7 +257,16 @@ PDP10.opFSC = function(op, ac)
|
|||
*
|
||||
* From the DEC PDP-10 System Reference Manual (May 1968), p. 2-16:
|
||||
*
|
||||
* Increment the byte pointer in location E as explained [below].
|
||||
* Increment the byte pointer in location E as explained [below]. The pointer has the format:
|
||||
*
|
||||
* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3
|
||||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||
* P P P P P P S S S S S S - I X X X X Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y
|
||||
*
|
||||
* where S is the size of the byte as a number of bits, and P is its position as the number of bits
|
||||
* remaining at the right of the byte in the word (eg if P is 3 the rightmost bit of the byte is bit 32
|
||||
* of the word). The rest of the pointer is interpreted in the same way as in an instruction: I, X and Y
|
||||
* are used to calculate the address of the location that is the source or destination of the byte.
|
||||
*
|
||||
* To facilitate processing a series of bytes, several of the byte instructions increment the
|
||||
* pointer, ie, modify it so that it points to the next byte position in a set of memory locations.
|
||||
|
|
@ -277,9 +286,6 @@ PDP10.opFSC = function(op, ac)
|
|||
* a byte of size 36 - P is loaded from position P, or the right 36 - P bits of the byte are deposited
|
||||
* in position P.
|
||||
*
|
||||
* NOTE: Until I can conduct real-world testing, I'm assuming when they say "100 - S", DEC really meant "64 - S",
|
||||
* which is 100 [base 8], which makes much more sense, since P is limited to a range of 00-77 [base 8].
|
||||
*
|
||||
* @this {CPUStatePDP10}
|
||||
* @param {number} op
|
||||
* @param {number} ac
|
||||
|
|
@ -294,7 +300,7 @@ PDP10.opIBP = function(op, ac)
|
|||
if (p < 0) {
|
||||
inc++;
|
||||
p = 36 - s;
|
||||
if (p < 0) p = 64 - s; // see SPECIAL CONSIDERATIONS and NOTE above
|
||||
if (p < 0) p = 100 - s; // see SPECIAL CONSIDERATIONS and NOTE above
|
||||
}
|
||||
/*
|
||||
* Since the documentation above makes clear that the effect of the increment (of w) extends past the Y
|
||||
|
|
@ -378,7 +384,7 @@ PDP10.opLDB = function(op, ac)
|
|||
}
|
||||
var p = (this.regBP / PDP10.OPCODE.P_SCALE) & PDP10.OPCODE.P_MASK;
|
||||
var s = (this.regBP >> PDP10.OPCODE.S_SHIFT) & PDP10.OPCODE.S_MASK;
|
||||
if (p + s <= 32) {
|
||||
if (p + s < 32) {
|
||||
/*
|
||||
* WARNING: When using JavaScript's 32-bit operators with values that could set bit 31 and produce a
|
||||
* negative value, it's critical to perform a final right-shift of 0, ensuring that the final result is
|
||||
|
|
@ -389,7 +395,7 @@ PDP10.opLDB = function(op, ac)
|
|||
/*
|
||||
* Regarding the SPECIAL CONSIDERATIONS above, even if the P ("shift") and/or S ("mask") values are
|
||||
* over-large, that should be fine, because nothing but additional zero bits will be included (provided
|
||||
* our memory is working properly and didn't give us more than 36 bits).
|
||||
* our memory is working properly and didn't give us more than 36 bits of unsigned data).
|
||||
*/
|
||||
w = Math.trunc(w / Math.pow(2, p)) % Math.pow(2, s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -910,7 +910,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
* non-DEBUGGER builds.
|
||||
*/
|
||||
if (DEBUGGER && (this.opFlags & PDP10.OPFLAG.DEBUGGER)) {
|
||||
if (this.dbg.checkInstruction(this.getPC(), nDebugState)) {
|
||||
if (this.dbg.checkInstruction(this.getXC(), nDebugState)) {
|
||||
this.stopCPU();
|
||||
break;
|
||||
}
|
||||
|
|
@ -927,7 +927,7 @@ class CPUStatePDP10 extends CPUPDP10 {
|
|||
*/
|
||||
if ((this.opFlags & (PDP10.OPFLAG.IRQ_MASK | PDP10.OPFLAG.WAIT)) /* && nDebugState >= 0 */) {
|
||||
if (this.checkInterrupts()) {
|
||||
if ((this.opFlags & PDP10.OPFLAG.DEBUGGER) && this.dbg.checkInstruction(this.getPC(), nDebugState)) {
|
||||
if ((this.opFlags & PDP10.OPFLAG.DEBUGGER) && this.dbg.checkInstruction(this.getXC(), nDebugState)) {
|
||||
this.stopCPU();
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2669,8 +2669,8 @@ class DebuggerPDP10 extends Debugger {
|
|||
return true;
|
||||
}
|
||||
|
||||
var match = sOpcode.match(/^(['"]?)(.*\.klm|.*\.mac|.*\.html|.*\.txt)\1$/i);
|
||||
if (match) {
|
||||
var match = sOpcode.match(/^(['"]?)(.*?)(\.klm|\.mac|\.html|\.txt|)\1$/i);
|
||||
if (match && (match[1] || match[3])) {
|
||||
var dbg = this;
|
||||
var cpu = this.cpu;
|
||||
dbgAddr = this.parseAddr(sAddr);
|
||||
|
|
@ -2678,9 +2678,11 @@ class DebuggerPDP10 extends Debugger {
|
|||
dbg.println("assembly already in progress");
|
||||
}
|
||||
else {
|
||||
var sFile = match[2];
|
||||
var sFile = match[2] + match[3];
|
||||
if (!match[3]) sOptions += 's';
|
||||
var addrLoad = dbgAddr.addr;
|
||||
var macro10 = this.macro10 = new Macro10(sFile, addrLoad, sOptions, dbg, function doneMacro10(nErrorCode, sURL) {
|
||||
var macro10 = this.macro10 = new Macro10(dbg);
|
||||
macro10.assembleFiles(sFile, addrLoad, sOptions, function doneMacro10(nErrorCode, sURL) {
|
||||
if (!nErrorCode) {
|
||||
/*
|
||||
* NOTE: Most Debugger operations run in the context of doCommand(), which catches any exceptions;
|
||||
|
|
@ -3706,21 +3708,48 @@ class DebuggerPDP10 extends Debugger {
|
|||
}
|
||||
|
||||
/**
|
||||
* splitArgs(sCmd)
|
||||
* splitArgs(sCmd, sDelim)
|
||||
*
|
||||
* @this {DebuggerPDP10}
|
||||
* @param {string} sCmd
|
||||
* @param {string} [sDelim]
|
||||
* @return {Array.<string>}
|
||||
*/
|
||||
splitArgs(sCmd)
|
||||
splitArgs(sCmd, sDelim = " ")
|
||||
{
|
||||
var asArgs = sCmd.replace(/ +/g, ' ').split(' ');
|
||||
var asArgs = [];
|
||||
var chQuote = "";
|
||||
var i = 0, iLast = 0;
|
||||
|
||||
while (i < sCmd.length) {
|
||||
var ch = sCmd[i++];
|
||||
if (chQuote) {
|
||||
if (ch == chQuote) {
|
||||
chQuote = "";
|
||||
asArgs.push(sCmd.substr(iLast, i - iLast));
|
||||
iLast = i;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (ch == '"' || ch == "'") {
|
||||
chQuote = ch;
|
||||
continue;
|
||||
}
|
||||
if (sDelim.indexOf(ch) >= 0) {
|
||||
asArgs.push(sCmd.substr(iLast, i - iLast - 1));
|
||||
iLast = i;
|
||||
}
|
||||
}
|
||||
if (iLast < i) {
|
||||
asArgs.push(sCmd.substr(iLast, i - iLast));
|
||||
}
|
||||
|
||||
asArgs[0] = asArgs[0].toLowerCase();
|
||||
if (asArgs && asArgs.length) {
|
||||
var s0 = asArgs[0];
|
||||
var ch0 = s0.charAt(0);
|
||||
for (var i = 1; i < s0.length; i++) {
|
||||
var ch = s0.charAt(i);
|
||||
for (i = 1; i < s0.length; i++) {
|
||||
ch = s0.charAt(i);
|
||||
if (ch0 == '?' || ch0 == 'r' || ch < 'a' || ch > 'z') {
|
||||
asArgs[0] = s0.substr(i);
|
||||
asArgs.unshift(s0.substr(0, i));
|
||||
|
|
|
|||
|
|
@ -91,66 +91,87 @@ var Scope;
|
|||
/**
|
||||
* @class Macro10
|
||||
* @property {string} sURL
|
||||
* @property {number} addrLoad
|
||||
* @property {number|null} addrLoad
|
||||
* @property {string} sOptions
|
||||
* @property {DebuggerPDP10} dbg
|
||||
* @property {function(...)} done
|
||||
* @property {function(...)|undefined} done
|
||||
* @property {number} iURL
|
||||
* @property {Array.<string>} asURLs
|
||||
* @property {Array.<string>} aURLs
|
||||
* @property {Array.<number>} anLines
|
||||
* @property {Array.<string>} asLines
|
||||
* @property {number|null|undefined} addrStart
|
||||
* @unrestricted
|
||||
*/
|
||||
class Macro10 {
|
||||
/**
|
||||
* Macro10(sURL, addrLoad, sOptions, dbg, done)
|
||||
* Macro10(dbg)
|
||||
*
|
||||
* A "mini" version of DEC's MACRO-10 assembler, with just enough features to support the handful
|
||||
* of DEC diagnostic source code files that we choose to throw at it.
|
||||
*
|
||||
* Requests the resource(s) specified by sURL; multiple resources can be requested by separating
|
||||
* them with semicolons.
|
||||
*
|
||||
* The done() callback is called after the resource(s) have been loaded and parsed. The caller
|
||||
* must use other methods to obtain further results (eg, getImage(), getStart()).
|
||||
*
|
||||
* The callback includes a non-zero error code if there was an error (and the URL):
|
||||
*
|
||||
* done(nErrorCode, sURL)
|
||||
*
|
||||
* We rely on the calling component (dbg) to provide a variety of helper services (eg, println(),
|
||||
* parseExpression(), etc). This is NOT a subclass of Component, so Component services are not part
|
||||
* of this class.
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {DebuggerPDP10} dbg (used to provide helper services to the Macro10 class)
|
||||
*/
|
||||
constructor(dbg)
|
||||
{
|
||||
this.dbg = dbg;
|
||||
}
|
||||
|
||||
/**
|
||||
* init(addrLoad, sOptions, done)
|
||||
*
|
||||
* Initializes all instance properties. Called by assembleFiles() and assembleString().
|
||||
*
|
||||
* Supported options include:
|
||||
*
|
||||
* 'd': leave all symbols in the debugger's variable table
|
||||
* 'p': print the preprocessed resource(s) without assembling them
|
||||
* 'l': print lines as they are parsed
|
||||
* 's': treat the URL as a string and assemble it (assembleFiles() only)
|
||||
*
|
||||
* The done() callback is called after the resource(s) have been loaded (if necessary), parsed, and
|
||||
* assembled. The caller must use other methods to obtain further results (eg, getImage(), getStart()).
|
||||
*
|
||||
* The callback includes a non-zero error code if there was an error (and the URL):
|
||||
*
|
||||
* done(nErrorCode, sURL)
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sURL (the URL(s) of the resource to be assembled)
|
||||
* @param {number|null} addrLoad (the absolute address to assemble the code at, if any)
|
||||
* @param {string|null} sOptions (zero or more letter codes to control the assembly process)
|
||||
* @param {DebuggerPDP10} dbg (used to provide helper services to the Macro10 class)
|
||||
* @param {function(...)} done
|
||||
* @param {number|null} [addrLoad] (the absolute address to assemble the code at, if any)
|
||||
* @param {string|undefined} [sOptions] (zero or more letter codes to control the assembly process)
|
||||
* @param {function(...)|undefined} [done]
|
||||
*/
|
||||
constructor(sURL, addrLoad, sOptions, dbg, done)
|
||||
init(addrLoad, sOptions, done)
|
||||
{
|
||||
this.sURL = sURL;
|
||||
this.addrLoad = addrLoad;
|
||||
this.sOptions = sOptions || "";
|
||||
this.dbg = dbg;
|
||||
this.sOptions = (sOptions || "").toLowerCase();
|
||||
this.done = done;
|
||||
|
||||
/*
|
||||
* The next set of properties may be updated by the assembly process and queried by the caller.
|
||||
this.iURL = 0;
|
||||
this.aURLs = [];
|
||||
|
||||
/**
|
||||
* Number of lines per file.
|
||||
*
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.addrStart = null;
|
||||
this.anLines = [];
|
||||
|
||||
/**
|
||||
* Lines from all the resources.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.asLines = [];
|
||||
|
||||
if (MAXDEBUG) this.println("starting PCjs MACRO-10 Mini-Assembler...");
|
||||
|
||||
/*
|
||||
* Initialize all the tables that MACRO-10 uses.
|
||||
* Initialize all the tables and other data structures that MACRO-10 uses.
|
||||
*
|
||||
* The Macros (tblMacros) and Symbols (tblSymbols) tables are fairly straightforward: they are
|
||||
* indexed by a macro or symbol name, and each element is a Mac or Sym object, respectively.
|
||||
|
|
@ -266,18 +287,65 @@ class Macro10 {
|
|||
*/
|
||||
this.sASCII = "";
|
||||
|
||||
/**
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
this.asLines = [];
|
||||
this.addrStart = null;
|
||||
}
|
||||
|
||||
this.iURL = 0;
|
||||
this.asURLs = sURL.split(';');
|
||||
this.anLines = []; // keeps track of the number of lines per file
|
||||
/**
|
||||
* assembleFiles(sURL, addrLoad, sOptions, done)
|
||||
*
|
||||
* Requests the resource(s) specified by sURL; multiple resources can be requested by separating
|
||||
* them with semicolons. The resources are requested and combined in the same order they are listed,
|
||||
* and after the last resource has been received, they are assembled as a single unit.
|
||||
*
|
||||
* As a courtesy to the Debugger's doAssemble() function, we allow it to select between assembleFiles()
|
||||
* and assembleString() by specifying an 's' option here, rather than having two separate code paths.
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sURL (the URL(s) of the resource to be assembled)
|
||||
* @param {number|null} [addrLoad] (the absolute address to assemble the code at, if any)
|
||||
* @param {string|undefined} [sOptions] (zero or more letter codes to control the assembly process)
|
||||
* @param {function(...)|undefined} [done]
|
||||
*/
|
||||
assembleFiles(sURL, addrLoad, sOptions, done)
|
||||
{
|
||||
if (sOptions && sOptions.indexOf('s') >= 0) {
|
||||
this.assembleString(sURL, addrLoad, sOptions, done);
|
||||
return;
|
||||
}
|
||||
|
||||
this.init(addrLoad, sOptions, done);
|
||||
|
||||
this.aURLs = sURL.split(';');
|
||||
|
||||
this.loadNextResource();
|
||||
}
|
||||
|
||||
/**
|
||||
* assembleString(sText, addrLoad, sOptions, done)
|
||||
*
|
||||
* Assembles the given text.
|
||||
*
|
||||
* @this {Macro10}
|
||||
* @param {string} sText
|
||||
* @param {number|null} [addrLoad] (the absolute address to assemble the code at, if any)
|
||||
* @param {string|undefined} [sOptions] (zero or more letter codes to control the assembly process)
|
||||
* @param {function(...)|undefined} [done]
|
||||
* @return {number}
|
||||
*/
|
||||
assembleString(sText, addrLoad, sOptions, done)
|
||||
{
|
||||
this.init(addrLoad, sOptions, done);
|
||||
|
||||
this.asLines = sText.split(/(\r?\n)/);
|
||||
this.anLines.push(this.asLines.length);
|
||||
|
||||
this.parseResources();
|
||||
|
||||
if (this.done) this.done(this.nError);
|
||||
|
||||
return this.nError;
|
||||
}
|
||||
|
||||
/**
|
||||
* loadNextResource()
|
||||
*
|
||||
|
|
@ -285,13 +353,14 @@ class Macro10 {
|
|||
*/
|
||||
loadNextResource()
|
||||
{
|
||||
if (this.iURL == this.asURLs.length) {
|
||||
this.done(this.parseResources());
|
||||
if (this.iURL == this.aURLs.length) {
|
||||
this.parseResources();
|
||||
if (this.done) this.done(this.nError);
|
||||
return;
|
||||
}
|
||||
|
||||
var macro10 = this;
|
||||
var sURL = this.asURLs[this.iURL];
|
||||
var sURL = this.aURLs[this.iURL];
|
||||
|
||||
this.println("loading " + Str.getBaseName(sURL));
|
||||
|
||||
|
|
@ -305,7 +374,7 @@ class Macro10 {
|
|||
|
||||
Web.getResource(sURL, null, true, function processMacro10(sFile, sResource, nErrorCode) {
|
||||
if (nErrorCode) {
|
||||
macro10.done(nErrorCode, sFile);
|
||||
if (macro10.done) macro10.done(nErrorCode, sFile);
|
||||
return;
|
||||
}
|
||||
var sText = sResource;
|
||||
|
|
@ -1100,13 +1169,13 @@ class Macro10 {
|
|||
var iURL = 0;
|
||||
while (nLine > this.anLines[iURL]) {
|
||||
nLine -= this.anLines[iURL];
|
||||
if (iURL < this.asURLs.length - 1) {
|
||||
if (iURL < this.aURLs.length - 1) {
|
||||
iURL++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Str.getBaseName(this.asURLs[iURL] + " line " + nLine);
|
||||
return Str.getBaseName(this.aURLs[iURL] + " line " + nLine);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue