Well, apparently the PDP-10 MUL instruction really DOES store the high-order word first, and it only stores the low-order word if the destination is an accumulator (weird)

This commit is contained in:
Jeff 2017-03-07 14:09:24 -08:00 committed by Jeff Parsons
commit 65eb821710
6 changed files with 118 additions and 46 deletions

View file

@ -47,5 +47,7 @@
0o265040000123, // 000122: JSP 1,.+1
0o270000000000, // 000123: ADD 0,0
0o265040000125, // 000124: JSP 1,.+1
0o255740000126, // 000125: JFCL 17,126
0o224100000002, // 000126: MUL 2,2
]
}

View file

@ -1,24 +1,26 @@
dep 100 505040111111
dep 101 541040444444
dep 102 544100000001
dep 103 504100000001
dep 104 570140000001
dep 105 530200000002
dep 106 544240000003
dep 107 504300000004
dep 110 573000000005
dep 111 533000000006
dep 112 541000000010
dep 113 251000000017
dep 114 577040000002
dep 115 261240000011
dep 116 262240000005
dep 117 515040170600
dep 120 135100000001
dep 121 270000000000
dep 122 265040000123
dep 123 270000000000
dep 124 265040000125
dep 100 HRLI 1,111111
dep 101 HRRI 1,444444
dep 102 HLR 2,1
dep 103 HRL 2,1
dep 104 HRRE 3,1
dep 105 HLLE 4,2
dep 106 HLR 5,3
dep 107 HRL 6,4
dep 110 HRRES 0,5
dep 111 HLLES 0,6
dep 112 HRRI 0,10
dep 113 BLT 0,17
dep 114 HLRES 1,2
dep 115 PUSH 5,11
dep 116 POP 5,5
dep 117 HRLZI 1,170600
dep 120 LDB 2,1
dep 121 ADD 0,0
dep 122 JSP 1,123
dep 123 ADD 0,0
dep 124 JSP 1,125
dep 125 JFCL 17,126
dep 126 MUL 2,2
ex -m 100-116
dep pc 100
step 11

View file

@ -33,6 +33,92 @@ if (NODE) {
var PDP10 = require("./defines");
}
/*
From the "PDP-10 System Reference Manual", May 1968, p. 1-4:
1.1 NUMBER SYSTEM
The program can interpret a data word as a 36-digit, unsigned binary number, or the left and right
halves of a word can be taken as separate 18-bit numbers. The PDP-10 repertoire includes instructions
that effectively add or subtract one from both halves of a word, so the right half can be used for
address modification when the word is addressed as an index register, while the left half is used to
keep a control count.
The standard arithmetic instructions in the PDP-10 use twos complement, fixed point conventions to do
binary arithmetic. In a word used as a number, bit 0 (the leftmost bit) represents the sign, 0 for positive,
1 for negative. In a positive number the remaining 35 bits are the magnitude in ordinary binary notation.
The negative of a number is obtained by taking its twos complement. If x is an n-digit binary number, its
twos complement is 2^n - x, and its ones complement is (2^n - 1) - x, or equivalently (2^n - x) - 1.
Subtracting a number from 2^n - 1 (ie, from all 1s) is equivalent to performing the logical complement,
ie changing all 0s to 1s and all 1s to 0s. Therefore, to form the twos complement one takes the logical
complement (usually referred to merely as the complement) of the entire word including the sign, and adds
1 to the result. In a negative number the sign bit is 1, and the remaining bits are the twos complement
of the magnitude.
Zero is represented by a word containing all 0s. Complementing this number produces all 1s, and adding
1 to that produces all 0s again. Hence there is only one zero representation and its sign is positive.
Since the numbers are symmetrical in magnitude about a single zero representation, all even numbers both
positive and negative end in 0, all odd numbers in 1 (a number all 1s represents -1). But since there are
the same number of positive and negative numbers and zero is positive, there is one more negative number
than there are nonzero positive numbers. This is the most negative number and it cannot be produced by
negating any positive number (its octal representation is 400000 000000 and its magnitude is one greater
than the largest positive number).
If ones complements were used for negatives one could read a negative number by attaching significance
to the as instead of the 1s. In twos complement notation each negative number is one greater than the
complement of the positive number of the same magnitude, so one can read a negative number by attaching
significance to the rightmost 1 and attaching significance to the 0s at the left of it (the negative number
of largest magnitude has a 1 in only the sign position). In a negative integer, 1s may be discarded at the
left, just as leading 0s may be dropped in a positive integer. In a negative fraction, 0s may be discarded
at the right. So long as only 0s are discarded, the number remains in twos complement form because it
still has a 1 that possesses significance; but if a portion including the rightmost 1 is discarded, the
remaining part of the fraction is now a ones complement.
The computer does not keep track of a binary point - the programmer must adopt a point convention and shift
the magnitude of the result to conform to the convention used. Two common conventions are to regard a number
as an integer (binary point at the right) or as a proper fraction (binary point at the left); in these two
cases the range of numbers represented by a single word is -2^35 to 2^35 - 1, or -1 to 1 - 2^35. Since
multiplication and division make use of double length numbers, there are special instructions for performing
these operations with integral operands.
SIDEBAR: Multiplication produces a double length product, and the programmer must remember that discarding
the low order part of a double length negative leaves the high order part in correct twos complement form
only if the low order part is null.
...
2.5 FIXED POINT ARITHMETIC
For fixed point arithmetic the PDP-10 has instructions for arithmetic shifting (which is essentially
multiplication by a power of 2) as well as for performing addition, subtraction, multiplication and division
of numbers in fixed point format [§ 1.1]. In such numbers the position of the binary point is arbitrary
(the programmer may adopt any point convention). The add and subtract instructions involve only single length
numbers, whereas multiply supplies a double length product, and divide uses a double length dividend. The high
and low order words respectively of a double length fixed point number are in accumulators A and A+1 (mod 20),
where the magnitude is the 70-bit string in bits 1-35 of the two words and the signs of the two are identical.
There are also integer multiply and divide instructions that involve only single length numbers and are
especially suited for handling smaller integers, particularly those of eighteen bits or less such as addresses
(of course they can be used for small fractions as well provided the programmer keeps track of the binary point).
For convenience in the following, all operands are assumed to be integers (binary point at the right).
The processor has four flags, Overflow, Carry 0, Carry 1 and No Divide, that indicate when the magnitude of a
number is or would be larger than can be accommodated. Carry 0 and Carry 1 actually detect carries out of bits
0 and 1 in certain instructions that employ fixed point arithmetic operations: the add and subtract instructions
treated here, the move instructions that produce the negative or magnitude of the word moved [§ 2.2], and the
arithmetic test instructions that increment or decrement the test word [§ 2.7]. In these instructions an
incorrect result is indicated - and the Overflow flag set - if the carries are different, ie if there is a carry
into the sign but not out of it, or vice versa. The Overflow flag is also set by No Divide being set, which
means the processor has failed to perform a division because the magnitude of the dividend is greater than or
equal to that of the divisor, or in integer divide, simply that the divisor is zero. In other overflow cases
only Overflow itself is set: these include too large a product in multiplication, and loss of significant bits
in left arithmetic shifting.
SIDEBAR: Overflow is determined directly from the carries, not from the carry flags, as their states may reflect
events in previous instructions.
*/
/**
* opKA10(op)
*
@ -5315,6 +5401,7 @@ PDP10.doADD = function(dst, src)
* only possible out-of-bounds value is a result >= WORD_LIMIT, which the mod cures.
*/
var res = (dst + src) % PDP10.WORD_LIMIT;
//noinspection JSUnresolvedFunction
PDP10.setAddFlags.call(this, dst, src, res);
return res;
};
@ -5423,7 +5510,7 @@ PDP10.doIOR = function(dst, src)
* @this {CPUStatePDP10}
* @param {number} dst (36-bit value)
* @param {number} src (36-bit value)
* @return {number} (dst * src) (the low 36 bits of the result; the high 36 bits are stored in regExt)
* @return {number} (dst * src) (the high 36 bits of the result; the low 36 bits are stored in regExt)
*/
PDP10.doMUL = function(dst, src)
{
@ -5491,8 +5578,8 @@ PDP10.doMUL = function(dst, src)
this.regPS |= PDP10.PSFLAG.OVFL;
}
this.regExt = ext;
return res;
this.regExt = res;
return ext;
};
/**
@ -5545,6 +5632,7 @@ PDP10.doSUB = function(dst, src)
* We can leverage setAddFlags() by treating the subtraction as addition;
* since res = dst - src, it is also true that dst = res + src.
*/
//noinspection JSUnresolvedFunction
PDP10.setAddFlags.call(this, res, src, dst);
return res;
};

View file

@ -60,7 +60,6 @@
negating any positive number (its octal representation is 400000 000000 and its magnitude is one greater
than the largest positive number).
If ones complements were used for negatives one could read a negative number by attaching significance
to the as instead of the 1s. In twos complement notation each negative number is one greater than the
complement of the positive number of the same magnitude, so one can read a negative number by attaching
@ -138,10 +137,6 @@
* be set to null by any other operation.
*
* The 'error' property records any error(s) from the last operation.
*
* NOTE: What we call extended Int36 values DEC refers to as "double length numbers", and they refer
* to the 'extended' portion as the "low order part" and the 'value' portion as the "high order part",
* presumably because they number the left-most significant bit 0.
*/
class Int36 {
/**
@ -1072,21 +1067,6 @@ class Int36 {
*
* Unsets extended if it's superfluous; opposite of extend().
*
* It's worth noting DEC's SIDEBAR comment (from above):
*
* Multiplication produces a double length product, and the programmer must remember that discarding
* the low order part ['extended'] of a double length negative leaves the high order part ['value'] in
* correct twos complement form only if the low order part ['extended'] is null [zero].
*
* is not applicable when we're using 71-bit magnitude values; for example, when value is MIN_NEG36 and
* extended is ZERO, we interpret that extended value as 34,359,738,368; we cannot simply eliminate the
* extended portion, otherwise value would be interpreted as -34,359,738,368.
*
* DEC can say that because each of the words in a PDP-10 double-length product contains its own sign bit,
* resulting in only 70 bits of magnitude. However, we don't store our extended (double-length) results that
* way, unless setMagnitude(70) has been called, so be aware of these mismatches in both terminology and
* format when converting an Int36 to/from PDP-10 registers/memory.
*
* @this {Int36}
*/
reduce()

View file

@ -104,7 +104,7 @@ function de(a,b){var c=this.g(this.f),d=this.g(b);this.i(b,ee(a,d,c)+(c-(c&A)))}
function je(a,b){var c=this.f*E,d=this.g(b);this.i(b,ee(a,d,c)+c)}function ke(a,b){b=(this.g(b)&A)*E;var c=this.g(this.f);this.i(this.f,ee(a,c,b)+b)}function le(a,b){var c=this.g(this.f),d=(c&A)*E,c=ee(a,c,d)+d;this.i(this.f,c);b&&this.i(b,c)}function me(a,b){var c=this.g(this.f)&A,d=this.g(b);this.i(b,ne(a,d,c)+c)}function oe(a,b){var c=this.g(b);this.i(b,ne(a,c,this.f)+this.f)}function pe(a,b){b=this.g(b)&A;var c=this.g(this.f);this.i(this.f,ne(a,c,b)+b)}
function qe(a,b){var c=this.g(this.f),d=c;if(a&=384)switch(d&=A,a){case 256:d+=A*E;break;case 384:d+=c>Vb?A*E:0}c=d;this.i(this.f,c);b&&this.i(b,c)}function re(a,b){var c=this.g(this.f)/E|0,d=this.g(b);this.i(b,ne(a,d,c)+c)}function se(a,b){var c=this.g(b);this.i(b,ne(a,c,0))}function te(a,b){b=this.g(b)/E|0;var c=this.g(this.f);this.i(this.f,ne(a,c,b)+b)}function ue(a,b){var c=this.g(this.f),d=c/E|0,c=ne(a,c,d)+d;this.i(this.f,c);b&&this.i(b,c)}function S(a){ve[a&7].call(this,a,a>>3&127)}
function we(){}function Q(a){this.j("undefined opcode: "+wa(a));wd(this,-1);this.V()}function xe(a){a>I&&(a!=Wb?a=Xb-a:this.u|=163840);return a}function ye(a,b){var c=(a+b)%H;ze.call(this,a,b,c);return c}function U(a,b){return((a/J|0)&(b/J|0))*J+((a&b)>>>0)}function Ae(a,b){return((a/J|0)^(b/J|0))*J+((a^b)>>>0)}function Be(a,b){return(~((a/J|0)^(b/J|0))&15)*J+(~(a^b)>>>0)}function V(a,b){return(a/J|0|b/J|0)*J+((a|b)>>>0)}
function Ce(a,b){var c=b;b=!1;var d;a>I&&(a=H-a,b=!b);c>I&&(c=H-c,b=!b);if(a<E&&c<E)d=a*c,a=0;else{d=a%E;var e=Math.trunc(a/E);a=c%E;var c=Math.trunc(c/E),f=d*a,g=e*a+Math.trunc(f/E);a=Math.trunc(g/E);g=g%E+d*c;d=g*E+f%E;a+=Math.trunc(g/E)+e*c}b&&(d?(a=G-a,d=H-d):a&&(a=H-a));b=a-a%F;a=2*a%H+Math.trunc(d/F);d=b+d%F;e=a-a%F;b!=e&&(a=b+(a-e),this.u|=131072);this.Ma=a;return d}function De(a){a?a==Wb?this.u|=163840:a=Xb-a:this.u|=98304;return a}
function Ce(a,b){var c=b;b=!1;var d;a>I&&(a=H-a,b=!b);c>I&&(c=H-c,b=!b);if(a<E&&c<E)d=a*c,a=0;else{d=a%E;var e=Math.trunc(a/E);a=c%E;var c=Math.trunc(c/E),f=d*a,g=e*a+Math.trunc(f/E);a=Math.trunc(g/E);g=g%E+d*c;d=g*E+f%E;a+=Math.trunc(g/E)+e*c}b&&(d?(a=G-a,d=H-d):a&&(a=H-a));b=a-a%F;a=2*a%H+Math.trunc(d/F);d=b+d%F;e=a-a%F;b!=e&&(a=b+(a-e),this.u|=131072);this.Ma=d;return a}function De(a){a?a==Wb?this.u|=163840:a=Xb-a:this.u|=98304;return a}
function Ee(a,b){var c=a-b;0>c&&(c+=H);ze.call(this,c,b,a);return c}function ze(a,b,c){a=Math.trunc(a/Yb);b=Math.trunc(b/Yb);c=Math.trunc(c/Yb);var d=a^(a^b)&(b^c);this.u=this.u|(d&2?65536:0)|(d&1?32768:0)|((a^c)&(b^c)&2?131072:0)}function ne(a,b,c){switch(a&384){case 0:b-=b&A;break;case 128:b=0;break;case 256:b=A*E;break;case 384:b=c>Vb?A*E:0}return b}function ee(a,b,c){switch(a&384){case 0:b&=A;break;case 128:b=0;break;case 256:b=A;break;case 384:b=c>I?A:0}return b}
var zd=[R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,Q,function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},Ad,function(a,b){0>this.F&&Ad.call(this);Bd.call(this,0,b)},Bd,function(a,b){0>this.F&&Ad.call(this);Xd.call(this,0,b)},Xd,function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},
function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},function(a){this.b(a)},

View file

@ -100,7 +100,7 @@ function uc(a,b){var c=this.c(this.b),d=c;if(a&=384)switch(d-=d&I,a){case 256:d+
function zc(a,b){var c=this.c(this.b)&I,d=this.c(b);this.f(b,Ac(a,d,c)+c)}function Bc(a,b){var c=this.c(b);this.f(b,Ac(a,c,this.b)+this.b)}function Cc(a,b){b=this.c(b)&I;var c=this.c(this.b);this.f(this.b,Ac(a,c,b)+b)}function Dc(a,b){var c=this.c(this.b),d=c;if(a&=384)switch(d&=I,a){case 256:d+=I*J;break;case 384:d+=c>Za?I*J:0}c=d;this.f(this.b,c);b&&this.f(b,c)}function Ec(a,b){var c=this.c(this.b)/J|0,d=this.c(b);this.f(b,Ac(a,d,c)+c)}function Fc(a,b){var c=this.c(b);this.f(b,Ac(a,c,0))}
function Gc(a,b){b=this.c(b)/J|0;var c=this.c(this.b);this.f(this.b,Ac(a,c,b)+b)}function Hc(a,b){var c=this.c(this.b),d=c/J|0,c=Ac(a,c,d)+d;this.f(this.b,c);b&&this.f(b,c)}function X(a){Ic[a&7].call(this,a,a>>3&127)}function Jc(){}function U(a){this.M("undefined opcode: "+la(a));gc(this);R(this)}function Kc(a){a>O&&(a!=$a?a=ab-a:this.g|=163840);return a}function Lc(a,b){var c=(a+b)%N;Mc.call(this,a,b,c);return c}function Y(a,b){return((a/P|0)&(b/P|0))*P+((a&b)>>>0)}
function Nc(a,b){return((a/P|0)^(b/P|0))*P+((a^b)>>>0)}function Oc(a,b){return(~((a/P|0)^(b/P|0))&15)*P+(~(a^b)>>>0)}function Z(a,b){return(a/P|0|b/P|0)*P+((a|b)>>>0)}
function Pc(a,b){var c=b;b=!1;var d;a>O&&(a=N-a,b=!b);c>O&&(c=N-c,b=!b);if(a<J&&c<J)d=a*c,a=0;else{d=a%J;var e=Math.trunc(a/J);a=c%J;var c=Math.trunc(c/J),f=d*a,g=e*a+Math.trunc(f/J);a=Math.trunc(g/J);g=g%J+d*c;d=g*J+f%J;a+=Math.trunc(g/J)+e*c}b&&(d?(a=M-a,d=N-d):a&&(a=N-a));b=a-a%L;a=2*a%N+Math.trunc(d/L);d=b+d%L;e=a-a%L;b!=e&&(a=b+(a-e),this.g|=131072);this.ta=a;return d}function Qc(a){a?a==$a?this.g|=163840:a=ab-a:this.g|=98304;return a}
function Pc(a,b){var c=b;b=!1;var d;a>O&&(a=N-a,b=!b);c>O&&(c=N-c,b=!b);if(a<J&&c<J)d=a*c,a=0;else{d=a%J;var e=Math.trunc(a/J);a=c%J;var c=Math.trunc(c/J),f=d*a,g=e*a+Math.trunc(f/J);a=Math.trunc(g/J);g=g%J+d*c;d=g*J+f%J;a+=Math.trunc(g/J)+e*c}b&&(d?(a=M-a,d=N-d):a&&(a=N-a));b=a-a%L;a=2*a%N+Math.trunc(d/L);d=b+d%L;e=a-a%L;b!=e&&(a=b+(a-e),this.g|=131072);this.ta=d;return a}function Qc(a){a?a==$a?this.g|=163840:a=ab-a:this.g|=98304;return a}
function Rc(a,b){var c=a-b;0>c&&(c+=N);Mc.call(this,c,b,a);return c}function Mc(a,b,c){a=Math.trunc(a/bb);b=Math.trunc(b/bb);c=Math.trunc(c/bb);var d=a^(a^b)&(b^c);this.g=this.g|(d&2?65536:0)|(d&1?32768:0)|((a^c)&(b^c)&2?131072:0)}function Ac(a,b,c){switch(a&384){case 0:b-=b&I;break;case 128:b=0;break;case 256:b=I*J;break;case 384:b=c>Za?I*J:0}return b}function W(a,b,c){switch(a&384){case 0:b&=I;break;case 128:b=0;break;case 256:b=I;break;case 384:b=c>O?I:0}return b}
var hc=[V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,V,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,U,function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},ic,function(a,b){0>this.o&&ic.call(this);jc.call(this,0,b)},jc,function(a,b){0>this.o&&ic.call(this);kc.call(this,0,b)},kc,function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},
function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},function(a){this.a(a)},