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:
parent
5a8a76249a
commit
642e43937e
5 changed files with 118 additions and 111 deletions
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue