Assemble commands can now be batched up; even if they refer to external files that must be loaded asynchronously, command processing will be suspended until assembly is complete

This commit is contained in:
Jeff 2017-03-29 08:14:07 -07:00 committed by Jeff Parsons
commit 642e43937e
5 changed files with 118 additions and 111 deletions

View file

@ -1343,7 +1343,7 @@ PDP10.opIMULB = function(op, ac)
PDP10.opMUL = function(op, ac)
{
this.writeWord(ac, PDP10.doMUL.call(this, this.readWord(ac), this.readWord(this.regEA)));
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1364,7 +1364,7 @@ PDP10.opMUL = function(op, ac)
PDP10.opMULI = function(op, ac)
{
this.writeWord(ac, PDP10.doMUL.call(this, this.readWord(ac), this.regEA));
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1405,7 +1405,7 @@ PDP10.opMULM = function(op, ac)
PDP10.opMULB = function(op, ac)
{
this.writeWord(this.regEA, this.writeWord(ac, PDP10.doMUL.call(this, this.readWord(ac), this.readWord(this.regEA))));
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1430,7 +1430,7 @@ PDP10.opIDIV = function(op, ac)
var dst = PDP10.doDIV.call(this, this.readWord(ac), 0, this.readWord(this.regEA));
if (dst < 0) return;
this.writeWord(ac, dst);
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1455,7 +1455,7 @@ PDP10.opIDIVI = function(op, ac)
var dst = PDP10.doDIV.call(this, this.readWord(ac), 0, this.regEA);
if (dst < 0) return;
this.writeWord(ac, dst);
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1531,7 +1531,7 @@ PDP10.opDIV = function(op, ac)
dst = PDP10.doDIV.call(this, dst, ext, this.readWord(this.regEA));
if (dst < 0) return;
this.writeWord(ac, dst);
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1559,7 +1559,7 @@ PDP10.opDIVI = function(op, ac)
dst = PDP10.doDIV.call(this, dst, ext, this.regEA);
if (dst < 0) return;
this.writeWord(ac, dst);
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -1614,7 +1614,7 @@ PDP10.opDIVB = function(op, ac)
dst = PDP10.doDIV.call(this, dst, ext, this.readWord(this.regEA));
if (dst < 0) return;
this.writeWord(ac, this.writeWord(this.regEA, dst));
this.writeWord((ac + 1) & 0o17, this.regExt);
this.writeWord((ac + 1) & 0o17, this.regEX);
};
/**
@ -2242,7 +2242,7 @@ PDP10.opJRST = function(op, ac)
/*
* Restore the flags.
*/
this.setPS(this.regLA);
this.setPS((this.regLA / PDP10.HALF_SHIFT)|0);
}
if (ac & 0b0100) {
/*
@ -2447,7 +2447,7 @@ PDP10.opPOPJ = function(op, ac)
*/
PDP10.opJSR = function(op, ac)
{
this.writeWord(this.regEA, this.getPS() + this.getPC());
this.writeWord(this.regEA, this.getPS() * PDP10.HALF_SHIFT + this.getPC());
this.regPS &= ~PDP10.PSFLAG.BIS; // TODO: Verify that BIS is cleared AFTER writing
this.setPC(this.regEA + 1);
};
@ -2471,7 +2471,7 @@ PDP10.opJSR = function(op, ac)
*/
PDP10.opJSP = function(op, ac)
{
this.writeWord(ac, this.getPS() + this.getPC());
this.writeWord(ac, this.getPS() * PDP10.HALF_SHIFT + this.getPC());
this.regPS &= ~PDP10.PSFLAG.BIS; // TODO: Verify that BIS is cleared AFTER writing
this.setPC(this.regEA);
};
@ -6157,14 +6157,14 @@ PDP10.doADD = function(dst, src)
* @param {number} dst (36-bit value)
* @param {number} ext (36-bit value extension)
* @param {number} src (36-bit divisor)
* @return {number} (dst / src) (the remainder is stored in regExt); -1 if error (no division performed)
* @return {number} (dst / src) (the remainder is stored in regEX); -1 if error (no division performed)
*/
PDP10.doDIV = function(dst, ext, src)
{
var fNegQ = false, fNegR = false;
dst = PDP10.merge72.call(this, dst, ext);
ext = this.regExt;
ext = this.regEX;
if (src > PDP10.INT_MASK) {
src = PDP10.WORD_LIMIT - src;
@ -6223,14 +6223,14 @@ PDP10.doDIV = function(dst, ext, src)
this.assert(!this.regRem[1], "extended remainder");
dst = this.regRes[0];
this.regExt = this.regRem[0];
this.regEX = this.regRem[0];
if (fNegQ && dst) {
dst = PDP10.WORD_LIMIT - dst;
}
if (fNegR && this.regExt) {
this.regExt = PDP10.WORD_LIMIT - this.regExt;
if (fNegR && this.regEX) {
this.regEX = PDP10.WORD_LIMIT - this.regEX;
}
return dst;
@ -6250,7 +6250,7 @@ PDP10.doDIV = function(dst, ext, src)
* @param {number} dst (36-bit value)
* @param {number} src (36-bit value)
* @param {boolean} [fTruncate] (true to truncate the result to 36 bits)
* @return {number} (dst * src) (the high 36 bits of the result; the low 36 bits are stored in regExt)
* @return {number} (dst * src) (the high 36 bits of the result; the low 36 bits are stored in regEX)
*/
PDP10.doMUL = function(dst, src, fTruncate)
{
@ -6380,7 +6380,7 @@ PDP10.doSUB = function(dst, src)
* @this {CPUStatePDP10}
* @param {number} dst (36-bit value)
* @param {number} ext (36-bit value)
* @return {number} (returns the lower 36 bits; the upper 36 bits are stored in regExt)
* @return {number} (returns the lower 36 bits; the upper 36 bits are stored in regEX)
*/
PDP10.merge72 = function(dst, ext)
{
@ -6395,7 +6395,7 @@ PDP10.merge72 = function(dst, ext)
* Compute value without the sign bit and add the low bit of extended in its place.
*/
dst = (dst % PDP10.INT_LIMIT) + ((ext * PDP10.INT_LIMIT) % PDP10.WORD_LIMIT);
this.regExt = sign + Math.trunc(ext / 2);
this.regEX = sign + Math.trunc(ext / 2);
return dst;
};
@ -6407,7 +6407,7 @@ PDP10.merge72 = function(dst, ext)
* @this {CPUStatePDP10}
* @param {number} res (36-bit value)
* @param {number} ext (36-bit value)
* @return {number} (returns the upper 36 bits; the lower 36 bits are stored in regExt)
* @return {number} (returns the upper 36 bits; the lower 36 bits are stored in regEX)
*/
PDP10.split72 = function(res, ext)
{
@ -6427,7 +6427,7 @@ PDP10.split72 = function(res, ext)
ext = sign + (ext - signNew);
this.regPS |= PDP10.PSFLAG.AROV;
}
this.regExt = res;
this.regEX = res;
return ext;
};

View file

@ -184,7 +184,7 @@ class CPUStatePDP10 extends CPUPDP10 {
this.regXC = -1; // if >= 0 this supersedes regPC (refers to an opcode from XCT)
this.regBP = -1; // active byte pointer (-1 if none)
this.regPS = 0; // assorted processor flags (see PSFLAG bit definitions)
this.regExt = 0; // internal "extension" register used for 72-bit MUL and DIV calculations
this.regEX = 0; // internal "extension" register used for 72-bit MUL and DIV calculations
this.regRes = [0, 0]; // four internal "double-length" registers used for 72-bit DIV calculations
this.regPow = [0, 0];
@ -351,28 +351,26 @@ class CPUStatePDP10 extends CPUPDP10 {
/**
* getPS()
*
* Gets the processor state flags in the format required by various program control operations (eg, JSP),
* pre-masked and pre-shifted for convenient loading into the left half of an accumulator.
* Gets the processor state flags in the format required by various program control operations (eg, JSP).
*
* @this {CPUStatePDP10}
* @return {number}
*/
getPS()
{
return (this.regPS & PDP10.HALF_MASK) * PDP10.HALF_SHIFT;
return (this.regPS & PDP10.HALF_MASK);
}
/**
* setPS(w)
*
* Sets the processor state flags in the format used by various program control operations (eg, JRST).
* Sets the processor state flags in the format required by various program control operations (eg, JRST).
*
* @this {CPUStatePDP10}
* @param {number} w
*/
setPS(w)
{
w = (w / PDP10.HALF_SHIFT)|0;
this.regPS = (this.regPS & ~PDP10.PSFLAG.SET_MASK) | (w & PDP10.PSFLAG.SET_MASK);
this.regPS |= (w & PDP10.PSFLAG.USERF);
if (!(w & PDP10.PSFLAG.EXIOT)) {

View file

@ -164,6 +164,7 @@ class DebuggerPDP10 extends Debugger {
this.aMessageBuffer = [];
this.messageInit(parmsDbg['messages']);
this.sInitCommands = parmsDbg['commands'];
this.aCommands = [];
/*
* Define remaining miscellaneous DebuggerPDP10 properties.
@ -920,7 +921,7 @@ class DebuggerPDP10 extends Debugger {
value = cpu.regEA;
break;
case DebuggerPDP10.REGS.PS:
value = (cpu.getPS() / PDP10.HALF_SHIFT)|0;
value = cpu.getPS();
break;
case DebuggerPDP10.REGS.OV:
value = (cpu.regPS & PDP10.PSFLAG.AROV)? 1 : 0;
@ -959,7 +960,7 @@ class DebuggerPDP10 extends Debugger {
this.setAddr(this.dbgAddrCode, cpu.getPC());
break;
case DebuggerPDP10.REGS.PS:
cpu.setPS(value * PDP10.HALF_SHIFT);
cpu.setPS(value);
break;
case DebuggerPDP10.REGS.OV:
flag = PDP10.PSFLAG.AROV;
@ -2591,8 +2592,8 @@ class DebuggerPDP10 extends Debugger {
*
* [0]: the assemble command (assumed to be "a")
* [1]: the target address (eg, "200")
* [2]: the operation code, aka instruction name (eg, "adc")
* [3]: the operation mode operand, if any (eg, "14", "[1234]", etc)
* [2]: the opcode mnemonic (eg, "hrli")
* [3]: the operands, if any
*
* The Debugger enters "assemble mode" whenever only the first (or first and second) arguments are present.
* As long as "assemble mode is active, the user can omit the first two arguments on all later assemble commands
@ -2601,16 +2602,13 @@ class DebuggerPDP10 extends Debugger {
*
* Entering "assemble mode" is optional; one could enter a series of fully-qualified assemble commands; eg:
*
* a ff00 cld
* a ff01 ldx 28
* a 100 hrli 1,111111
* a 101 hrri 1,444444
* ...
*
* without ever entering "assemble mode", but of course, that requires more typing and doesn't take advantage
* of automatic target address advancement (see dbgAddrAssemble).
*
* NOTE: As the previous example implies, you can even assemble new instructions into ROM address space;
* as our setByte() function explains, the ROM write-notification handlers only refuse writes from the CPU.
*
* When filename(s) or URL(s) are provided in lieu of an opcode, we pass those on to the Macro10 component
* for assembling, along with any option letters that were included with the "a" command; for example, if "ap"
* was specified, then "p" will be passed to Macro10 as an option.
@ -2618,15 +2616,16 @@ class DebuggerPDP10 extends Debugger {
* Macro10 options include:
*
* p: preprocess the specified resource(s) without assembling them
* l: generate listing information
* l: generate listing information (TODO)
*
* @this {DebuggerPDP10}
* @param {Array.<string>} asArgs is the complete argument array, beginning with the "a" command in asArgs[0]
* @return {boolean}
*/
doAssemble(asArgs)
{
var dbgAddr = this.parseAddr(asArgs[1], this.dbgAddrAssemble);
if (!dbgAddr) return;
if (!dbgAddr) return false;
var sOpcode = asArgs[2];
@ -2634,7 +2633,7 @@ class DebuggerPDP10 extends Debugger {
this.println("begin assemble at " + this.toStrAddr(dbgAddr));
this.fAssemble = true;
this.cmp.updateDisplays();
return;
return true;
}
var sOptions = asArgs[0].substr(1);
@ -2658,14 +2657,16 @@ class DebuggerPDP10 extends Debugger {
dbg.loadBin(dbg.macro10.getBin(), addrLoad);
} catch(e) {
dbg.println(e.message);
nErrorCode = -1; // fake error so that command processing stops
}
} else {
dbg.println("error (" + nErrorCode + ") processing " + (sURL || sFile));
}
dbg.macro10 = null;
if (!nErrorCode) dbg.doCommands();
});
}
return;
return false;
}
asArgs.shift();
@ -2678,6 +2679,7 @@ class DebuggerPDP10 extends Debugger {
this.setWord(dbgAddr, opCode);
this.println(this.getInstruction(dbgAddr));
}
return true;
}
/**
@ -3749,7 +3751,7 @@ class DebuggerPDP10 extends Debugger {
switch (asArgs[0].charAt(0)) {
case 'a':
this.doAssemble(asArgs);
result = this.doAssemble(asArgs);
break;
case 'b':
this.doBreak(asArgs[0], asArgs[1], sCmd);
@ -3868,16 +3870,23 @@ class DebuggerPDP10 extends Debugger {
/**
* doCommands(sCmds, fSave)
*
* This function is now written so that if any async command, such as assemble ('a'), stopped the
* flow of commands by returning false, it can call us from its callback handler with no arguments,
* and command processing should continue where it left off.
*
* @this {DebuggerPDP10}
* @param {string} sCmds
* @param {string} [sCmds]
* @param {boolean} [fSave]
* @return {boolean} true if all commands processed, false if not
*/
doCommands(sCmds, fSave)
{
var a = this.parseCommand(sCmds, fSave);
for (var s in a) {
if (!this.doCommand(a[+s])) return false;
if (sCmds) {
this.aCommands = this.parseCommand(sCmds, fSave);
}
var sCmd;
while (sCmd = this.aCommands.shift()) {
if (!this.doCommand(sCmd)) return false;
}
return true;
}