1
0
mirror of https://github.com/pkimpel/retro-b5500.git synced 2026-04-14 08:59:13 +00:00

Continue Character Mode tests; debug Field Add/Subtract; implement and debug word-mode PRL, IOR.

This commit is contained in:
paul
2013-02-17 01:21:44 +00:00
parent 4f366efe13
commit 239eb2f624
4 changed files with 198 additions and 77 deletions

View File

@@ -195,7 +195,7 @@ B5500Processor.prototype.access = function(eValue) {
this.cycleCount += B5500Processor.memCycles;
if (acc.MAED) {
this.I |= 0x02; // set I02F - memory address/inhibit error
this.I |= 0x02; // set I02F: memory address/inhibit error
if (this.NCSF || this !== this.cc.P1) {
this.cc.signalInterrupt();
} else {
@@ -203,7 +203,7 @@ B5500Processor.prototype.access = function(eValue) {
this.cycleLimit = 0; // exit this.run()
}
} else if (acc.MPED) {
this.I |= 0x01; // set I01F - memory parity error
this.I |= 0x01; // set I01F: memory parity error
if (this.NCSF || this !== this.cc.P1) {
this.cc.signalInterrupt();
} else {
@@ -218,7 +218,7 @@ B5500Processor.prototype.accessError = function() {
/* Common error handling routine for all memory acccesses */
if (this.accessor.MAED) {
this.I |= 0x02; // set I02F - memory address/inhibit error
this.I |= 0x02; // set I02F: memory address/inhibit error
if (this.NCSF || this !== this.cc.P1) {
this.cc.signalInterrupt();
} else {
@@ -226,7 +226,7 @@ B5500Processor.prototype.accessError = function() {
this.cycleLimit = 0; // exit this.run()
}
} else if (this.accessor.MPED) {
this.I |= 0x01; // set I01F - memory parity error
this.I |= 0x01; // set I01F: memory parity error
if (this.NCSF || this !== this.cc.P1) {
this.cc.signalInterrupt();
} else {
@@ -671,6 +671,8 @@ B5500Processor.prototype.compareSourceWithDest = function(count) {
have been left in an updated state by a prior syllable */
var aBit; // A register bit nr
var bBit; // B register bit nr
var yc = 0; // local Y register
var zc = 0; // local Z register
this.MSFF = 0;
this.streamAdjustSourceChar();
@@ -731,9 +733,9 @@ B5500Processor.prototype.compareSourceWithDest = function(count) {
}
}
} else { // strings still equal -- check this character
if ((this.Y = this.cc.fieldIsolate(this.A, aBit, 6)) != (this.Z = this.cc.fieldIsolate(this.B, bBit, 6))) {
if ((yc = this.cc.fieldIsolate(this.A, aBit, 6)) != (zc = this.cc.fieldIsolate(this.B, bBit, 6))) {
this.Q |= 0x04; // set Q03F to stop further comparison
this.MSFF = (B5500Processor.collation[this.Y] > B5500Processor.collation[this.Z] ? 1 : 0);
this.MSFF = (B5500Processor.collation[yc] > B5500Processor.collation[zc] ? 1 : 0);
} else { // strings still equal -- advance to next character
count--;
if (bBit < 42) {
@@ -761,6 +763,9 @@ B5500Processor.prototype.compareSourceWithDest = function(count) {
}
}
} while (count);
this.Y = yc; // for display only
this.Z = zc; // for display only
}
};
@@ -773,8 +778,8 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) {
var bBit; // B register bit nr
var carry = 0; // carry/borrow bit
var compl = false; // complement addition (i.e., subtract the digits)
var MSFF = (this.MSFF != 0); // get TFFF as a Boolean
var Q03F = ((this.Q & 0x04) != 0); // get Q03F as a Boolean
var TFFF; // local copy of MSFF/TFFF
var Q03F; // local copy of Q03F
var resultNegative; // sign of result is negative
var sd; // digit sum
var ycompl = false; // complement source digits
@@ -786,6 +791,8 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) {
this.cycleCount += 2; // approximate the timing thus far
if (this.Q & 0x20) { // Q06F => count > 0, so there's characters to add
this.Q &= ~(0x28); // reset Q06F and Q04F
TFFF = (this.MSFF != 0); // get TFFF as a Boolean
Q03F = ((this.Q & 0x04) != 0); // get Q03F as a Boolean
// Back down the pointers to the last characters of their respective fields
if (this.K > 0) {
@@ -813,18 +820,18 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) {
this.Q |= 0x80; // set Q08F (for display only)
aBit = this.G*6; // A-bit number
bBit = this.K*6; // B-bit number
yd = this.cc.fieldIsolate(this.A, aBit, 2); // get the source sign
zd = this.cc.fieldIsolate(this.B, bBit, 2); // get the dest sign
yd = (this.cc.fieldIsolate(this.A, aBit, 2) == 2 ? 2 : 0); // source sign
zd = (this.cc.fieldIsolate(this.B, bBit, 2) == 2 ? 2 : 0); // dest sign
compl = (yd == zd ? !adding : adding ); // determine if complement needed
resultNegative = !( // determine sign of result
(zd == 0 && !compl) ||
(zd == 0 && Q03F && !MSFF) ||
(zd != 0 && compl && Q03F && MSFF ) ||
(zd == 0 && Q03F && !TFFF) ||
(zd != 0 && compl && Q03F && TFFF ) ||
(compl && !Q03F));
if (compl) {
this.Q |= 0x42; // set Q07F and Q02F (for display only)
carry = 1; // preset the carry/borrow bit (Q07F)
if (MSFF) {
if (TFFF) {
this.Q |= 0x08; // set Q04F (for display only)
zcompl = true;
} else {
@@ -832,18 +839,17 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) {
}
}
this.MSFF = 0; // reset TFFF so it can ultimately indicate overflow
this.cycleCount += 4;
do {
count--;
this.cycleCount += 2;
yd = this.cc.fieldIsolate(this.A, aBit+2, 4); // get the source sign
zd = this.cc.fieldIsolate(this.B, bBit+2, 4); // get the dest sign
yd = this.cc.fieldIsolate(this.A, aBit+2, 4); // get the source digit
zd = this.cc.fieldIsolate(this.B, bBit+2, 4); // get the dest digit
sd = (ycompl ? 9-yd : yd) + (zcompl ? 9-zd : zd) + carry; // develop binary digit sum
if (sd <= 9) {
carry = this.MSFF = 0;
carry = 0;
} else {
carry = this.MSFF = 1;
carry = 1;
sd -= 10;
}
if (resultNegative) {
@@ -851,7 +857,7 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) {
resultNegative = false;
}
this.cc.fieldInsert(this.B, bBit, 6, sd);
this.B = this.cc.fieldInsert(this.B, bBit, 6, sd);
if (count == 0) {
this.storeBviaS(); // [S] = B, store final dest word
@@ -904,6 +910,7 @@ B5500Processor.prototype.fieldArithmetic = function(count, adding) {
}
this.AROF = this.BROF = 0;
this.H = this.V = this.N = 0;
this.MSFF = (compl ? 1-carry : carry); // MSFF/TFFF = overflow indicator
}
};
@@ -1285,7 +1292,7 @@ B5500Processor.prototype.storeForInterrupt = function(forTest) {
this.MWOF = 0;
}
this.M = (this.R*64) + 0x08; // store initiate word at R+@10
this.M = this.R*64 + 8; // store initiate word at R+@10
this.storeBviaM(); // [M] = B
this.M = 0;
@@ -2321,17 +2328,18 @@ B5500Processor.prototype.computeRelativeAddr = function(offset, cEnabled) {
This offset must be in (0..1023) */
if (this.SALF) {
this.cycleCount += 2; // approximate the timing
switch (offset >>> 7) {
case 0:
case 1:
case 2:
case 3:
this.M = (this.R*64) + (offset & 0x1FF);
this.M = this.R*64 + (offset & 0x1FF);
break;
case 4:
case 5:
if (this.MSFF) {
this.M = (this.R*64) + 7;
this.M = this.R*64 + 7;
this.loadMviaM(); // M = [M].[18:15]
this.M += (offset & 0xFF);
} else {
@@ -2342,12 +2350,12 @@ B5500Processor.prototype.computeRelativeAddr = function(offset, cEnabled) {
if (cEnabled) {
this.M = this.C + (offset & 0x7F);
} else {
this.M = (this.R*64) + (offset & 0x7F);
this.M = this.R*64 + (offset & 0x7F);
}
break;
case 7:
if (this.MSFF) {
this.M = (this.R*64) + 7;
this.M = this.R*64 + 7;
this.loadMviaM(); // M = [M].[18:15]
this.M -= (offset & 0x7F);
} else {
@@ -2356,7 +2364,7 @@ B5500Processor.prototype.computeRelativeAddr = function(offset, cEnabled) {
break;
} // switch
} else {
this.M = (this.R*64) + (offset & 0x3FF);
this.M = this.R*64 + (offset & 0x3FF);
}
// Reset variant-mode R-relative addressing, if enabled
@@ -2732,7 +2740,7 @@ B5500Processor.prototype.exitSubroutine = function(inline) {
this.S = (this.B % 0x40000000) >>> 15;
this.loadBviaS(); // B = [S], fetch prior MSCW
} while (((this.B - this.B % 0x40000000)/0x40000000) % 4 == 3); // MSFF & SALF
this.S = (this.R*64) + 7;
this.S = this.R*64 + 7;
this.storeBviaS(); // [S] = B, store last MSCW at [R]+7
}
this.S = ((this.X % 0x40000000) >>> 15) - 1;
@@ -2780,7 +2788,7 @@ B5500Processor.prototype.operandCall = function() {
case 5:
// Absent data or program descriptor
if (this.NCSF) {
this.I = (this.I & 0x0F) | 0x70; // set I05/6/7: P-bit
this.I = (this.I & 0x0F) | 0x70; // set I05/6/7: p-bit
this.cc.signalInterrupt();
// else if control state, we're done
}
@@ -3157,11 +3165,11 @@ B5500Processor.prototype.run = function() {
this.M = t1 >>> 3;
break;
case 0x1A: // XX32: ---=Field subtract (aux) !! ??
case 0x1A: // XX32: xxx=Field subtract (aux)
this.fieldArithmetic(variant, false);
break;
case 0x1B: // XX33: ---=Field add (aux) !! ??
case 0x1B: // XX33: xxx=Field add (aux)
this.fieldArithmetic(variant, true);
break;
@@ -3390,13 +3398,11 @@ B5500Processor.prototype.run = function() {
this.AROF = this.BROF;
t2 = this.S; // save S (not the way the hardware did it)
this.S = this.F - variant; // compute store address
this.B = this.cc.fieldInsert( // construct control address: reset flag bit
this.cc.fieldInsert( // insert F (as saved in t2)
this.B = this.cc.fieldInsert( // insert F (as saved in t2)
this.cc.fieldInsert( // insert L
this.cc.fieldInsert(this.B, 33, 15, this.C), // insert C
10, 2, this.L),
18, 15, t2),
0, 1, 0);
18, 15, t2) % 0x800000000000; // reset flag bit
this.storeBviaS(); // [S] = B
this.S = t2; // restore S
this.B = this.A; // restore B from A
@@ -3670,6 +3676,35 @@ B5500Processor.prototype.run = function() {
case 0x09: // XX11: control state and communication ops
switch (variant) {
case 0x01: // 0111: PRL=Program Release
this.adjustAFull();
t1 = this.A;
if (t1 < 0x800000000000) { // it's an operand
this.computeRelativeAddr(t1, 0);
t2 = 1;
} else if (this.presenceTest(t1)) {
this.M = t1 % 0x8000; // present descriptor
t2 = 1;
} else { // absent descriptor
t2 = 0;
}
if (t2) {
this.loadAviaM();
if (this.NCSF) {
if (this.A % 0x200000 < 0x100000) {
this.I = (this.I & 0x0F) | 0x50; // set I07/I05: program release
} else {
this.I = (this.I & 0x0F) | 0x60; // set I07/I06: continuity bit
}
this.cc.signalInterrupt();
this.A = this.M;
this.M = this.R*64 + 9; // store IOD address in PRT[9]
this.storeAviaM();
} else {
this.A = this.cc.bitReset(this.A, 2);
this.storeAviaM();
}
this.AROF = 0;
}
break;
case 0x02: // 0211: ITI=Interrogate Interrupt
@@ -3692,7 +3727,7 @@ B5500Processor.prototype.run = function() {
case 0x08: // 1011: COM=Communicate
if (this.NCSF) { // no-op in control state
this.M = (this.R*64) + 0x09; // address = R+@11
this.M = this.R*64 + 9; // address = R+@11
if (this.AROF) {
this.storeAviaM(); // [M] = A
this.AROF = 0;
@@ -3701,12 +3736,32 @@ B5500Processor.prototype.run = function() {
this.storeBviaM(); // [M] = B
this.BROF = 0;
}
this.I = (this.I & 0x0F) | 0x40; // set I07
this.I = (this.I & 0x0F) | 0x40; // set I07: communicate
this.cc.signalInterrupt();
}
break;
case 0x11: // 2111: IOR=I/O Release
if (!this.NCSF) { // no-op in normal state
this.adjustAFull();
t1 = this.A;
if (t1 < 0x800000000000) { // it's an operand
this.computeRelativeAddr(t1, 0);
t2 = 1;
} else if (t1 % 0x400000000000 >= 0x200000000000) {
this.M = t1 % 0x8000; // present descriptor
t2 = 1;
} else {
// for an absent descriptor, just leave it on the stack
t2 = 0;
}
if (t2) {
this.loadAviaM();
this.A = this.cc.bitSet(this.A, 2);
this.storeAviaM();
this.AROF = 0;
}
}
break;
case 0x12: // 2211: HP2=Halt Processor 2
@@ -4258,7 +4313,7 @@ B5500Processor.prototype.run = function() {
this.F = this.S;
if (!this.MSFF) {
if (this.SALF) { // store the MSCW at R+7
this.M = (this.R*64) + 7;
this.M = this.R*64 + 7;
this.storeBviaM(); // [M] = B
}
this.MSFF = 1;

View File

@@ -69,14 +69,6 @@ CAPTION {
padding-right: 4px;
font-weight: bold}
TH {
vertical-align: bottom;
text-align: center;
padding-left: 2px;
padding-right: 2px;
font-family: "Arial", "Helvetica", sans-serif;
font-weight: bold}
TABLE.normal>TBODY>TR>TD, TABLE.standard>TBODY>TR>TD {
padding-top: 1px;
padding-bottom: 1px;
@@ -105,6 +97,17 @@ TABLE#RegisterBank2 {
TR {
vertical-align: middle}
TH {
vertical-align: bottom;
text-align: center;
padding-left: 2px;
padding-right: 2px;
font-family: "Arial", "Helvetica", sans-serif;
font-weight: bold}
INPUT.warn {
background-color: yellow}
.bold {
font-weight: bold}

View File

@@ -203,6 +203,36 @@ function $$(id) {
return document.getElementById(id);
}
function hasClass(id, name) {
/* returns true if element "e" has class "name" in its class list */
var e = $$(id);
var classes = e.className;
if (!e) {
return false;
} else if (classes == name) {
return true;
} else {
return (classes.search("\\b" + name + "\\b") >= 0);
}
}
function addClass(id, name) {
/* Adds a class "name" to the element "e"s class list */
var e = $$(id);
if (!hasClass(id, name)) {
e.className += (" " + name);
}
}
function removeClass(id, name) {
/* Removes the class "name" from the element "e"s class list */
var e = $$(id);
e.className = e.className.replace(new RegExp("\\b" + name + "\\b\\s*", "g"), "");
}
function setText(id, text) {
/* Replaces the children of the node having id="id" with a text node containing "text" */
var e = $$(id);
@@ -530,6 +560,7 @@ function displayRegisters() {
displayOctal("XReg", cc.P1.X, 13);
displayOctal("CReg", cc.P1.C, 5);
displayOctal("LReg", cc.P1.L, 1);
setText("SylAddr", (cc.P1.C*4 + cc.P1.L).toString(8));
displayOctal("PReg", cc.P1.P, 16);
$$("PROF").checked = (cc.P1.PROF != 0);
displayOctal("TReg", cc.P1.T, 4);
@@ -537,6 +568,11 @@ function displayRegisters() {
displaySyllable();
displayOctal("EReg", cc.P1.E, 2);
displayOctal("IReg", cc.P1.I, 3);
if (cc.P1.I) {
addClass("IReg", "warn");
} else {
removeClass("IReg", "warn");
}
displayOctal("QReg", cc.P1.Q, 4);
displayOctal("MReg", cc.P1.M, 5);
displayOctal("GReg", cc.P1.G, 1);
@@ -565,7 +601,24 @@ function displayProcessorState() {
window.focus();
}
function stepIt() {
function goIt(ev) {
/* Branches to the location specified by the C and L registers: loads
P and T to set up for the execution of the instruction at that syllable
address, and then advances C/L to the next syllable address */
cc.P1.loadPviaC();
cc.P1.T = cc.P1.cc.fieldIsolate(cc.P1.P, cc.P1.L*12, 12);
cc.P1.TROF = 1;
if (cc.P1.L < 3) {
cc.P1.L++;
} else {
cc.P1.L = 0;
cc.P1.C++;
}
displayProcessorState();
}
function stepIt(ev) {
/* Executes a single instruction. If that syllable was manually injected into
the T register, backs up C and L so that the originally-queued syllable can
be executed next */
@@ -584,7 +637,7 @@ function stepIt() {
displayProcessorState();
}
function execIt() {
function execIt(ev) {
/* Executes one instruction from the drop-down syllable options list, then
backs up C and L to prepare for the original instruction in the stream */
var opList = $$("OpList")
@@ -752,9 +805,11 @@ function initialize() {
};
$$("CReg").onchange = function(ev) {
cc.P1.C = reg_onChange(ev);
setText("SylAddr", (cc.P1.C*4 + cc.P1.L).toString(8));
};
$$("LReg").onchange = function(ev) {
cc.P1.L = reg_onChange(ev);
setText("SylAddr", (cc.P1.C*4 + cc.P1.L).toString(8));
};
$$("PReg").onchange = function(ev) {
cc.P1.P = reg_onChange(ev);
@@ -776,6 +831,11 @@ function initialize() {
};
$$("IReg").onchange = function(ev) {
cc.P1.I = reg_onChange(ev);
if (cc.P1.I) {
addClass("IReg", "warn");
} else {
removeClass("IReg", "warn");
}
};
$$("QReg").onchange = function(ev) {
cc.P1.Q = reg_onChange(ev);
@@ -855,6 +915,7 @@ function initialize() {
$$("MWordP4").onchange = word_onChange;
$$("FileSelector").addEventListener("change", fileSelector_onChange, false);
$$("GoBtn").addEventListener("click", goIt, false);
$$("Step").addEventListener("click", stepIt, false);
$$("Exec").addEventListener("click", execIt, false);
@@ -1102,8 +1163,12 @@ window.onload = function() {
<td>
<input id=CReg name=CReg type=text class=number size=5 maxlength=5>
<td class=center>L
<td colspan=3>
<td colspan=2>
<input id=LReg name=LReg type=text class=number size=1 maxlength=1>
&nbsp;
<span id=SylAddr></span>
<td class=center>
<input id=GoBtn name=GoBtn type=button value="Go To">
<tr>
<td class=center>P
<td colspan=5>
@@ -1173,34 +1238,30 @@ window.onload = function() {
<input id=SALF name=SALF type=checkbox value=1><label for=SALF>SALF</label>
&nbsp;&nbsp;
<input id=VARF name=VARF type=checkbox value=1><label for=VARF>VARF</label>
<tr>
<td colspan=6>
<input id=Step name=Step type=button value="Step" accesskey=P>
&nbsp;Syllable:
<select id=OpList name=OpList>
<option value="0055" selected>NOP : No Operation
<option value="0101">ADD : Add
<option value="0301">SUB : Subtract
<option value="0401">MUL : Multiply
<option value="1001">DIV : Divide
<option value="3001">IDV : Integer Divide
<option value="7001">RDV : Remainder Divide
<option value="0105">DLA : Add DP
<option value="0305">DLS : Subtract DP
<option value="0125">GEQ : B GEQ A
<option value="0225">GTR : B GTR A
<option value="0425">NEQ : B NEQ A
<option value="4125">LEQ : B LEQ A
<option value="4225">LSS : B LSS A
<option value="4425">EQL : B EQL A
</select>
&nbsp;
<input id=Exec name=Exec type=button value="Exec" accesskey=X>
</table>
<p>
<input id=Step name=Step type=button value="Step" accesskey=P>
&nbsp;
Syllable:
<select id=OpList name=OpList>
<option value="0055" selected>NOP : No Operation
<option value="0101">ADD : Add
<option value="0301">SUB : Subtract
<option value="0401">MUL : Multiply
<option value="1001">DIV : Divide
<option value="3001">IDV : Integer Divide
<option value="7001">RDV : Remainder Divide
<option value="0105">DLA : Add Double Precision
<option value="0305">DLS : Subtract Double Precision
<option value="0125">GEQ : B Greater or Equal A
<option value="0225">GTR : B Greater Than A
<option value="0425">NEQ : B Not Equal A
<option value="4125">LEQ : B Less or Equal A
<option value="4225">LSS : B Less Than A
<option value="4425">EQL : B Equal A
</select>
&nbsp;
<input id=Exec name=Exec type=button value="Exec" accesskey=X>
</p>
</body>
</html>

View File

@@ -24,7 +24,7 @@ START:*: 00500100
00500200
D[0]:= 76543210; 00500300
00520000
STREAM(R:=-D[0]: COUNT:=0, S:=S, D:=D); 00520100
STREAM(R:=-D[0] : COUNT:=0, S:=S, D:=D); 00520100
BEGIN 00520200
SI:= S; 00520300
SI:= SI+51; 00520400
@@ -147,10 +147,12 @@ STREAM(R:=-D[0]: COUNT:=0, S:=S, D:=D); 00520100
DS:= 9 SUB; 00532100
00532200
COUNT:= CI; 00532300
TALLY:= COUNT; 00532400
CI:= COUNT; 00532500
CI:= COUNT; % SINCE RCA INCREMENTS L, THIS SHOULD BE OK 00532400
TALLY:= COUNT; 00532500
00532600
END STREAM; 00549900
00550000
P(DEL); % EAT THE WORD LEFT BELOW MSCW BY THE STREAM 00550100
00999700
GO TO START; 00999800
END. 00999900