Trailing-Edge
-
PDP-10 Archives
-
klu2_442
-
arith.mic
There are 5 other files named arith.mic in the archive. Click here to see a list.
.TOC "ADD, SUB"
.DCODE
270: R-PF, AC, J/ADD ;ADD
I-PF, AC, J/ADD ;ADDI
RPW, M, J/ADD ;ADDM
RPW, B, J/ADD ;ADDB
.UCODE
=0****00****
ADD: AR_AR*AC0,AD/A+B,AD FLAGS,EXIT
=
.DCODE
274: R-PF, AC, J/SUB ;SUB
I-PF, AC, J/SUB ;SUBI
RPW, M, J/SUB ;SUBM
RPW, B, J/SUB ;SUBB
.UCODE
=0****00****
SUB: AR_AC0,BR/AR
= AR_AR-BR,AD FLAGS,EXIT
.TOC "MUL, IMUL"
.DCODE
220: R, AC, J/IMUL ;IMUL
I, AC, J/IMUL ;IMULI [416]
RW, M, J/IMULM ;IMULM [424]
RW, B, J/IMULM ;IMULB [424]
.UCODE
;
; In days of old when knights were bold and PDP-10s were alive and
; kicking, someone decided to try to optimize IMULtIplication of a
; positive number by a positive number. That attempt failed because
; the code necessary to test for overflow in the general case becomes
; complex enough to cost much of the time saved by shortening the
; multiplication loop. We are now improving on the original idea a
; bit by optimizing all IMUL(I)s of a positive by a positive, as long
; as we can quickly guarantee that no overflow will occur. This
; requires that the high order 19 bits of the multiplier and the
; high order 18 bits of the multiplicand be zero. [416][424]
;
=0****00**00
IMUL: MQ_AR,ARX_AC0,SC_#,#/18., ;MQ_multiplier, ARX_multiplicand
FE/SCAD,SKP AR18 ; Too much multiplier?
=10 ARL_ARL,ARR_SHIFT,SC_FE-1,J/IMFAST;Maybe not. Test further, set SC
IMULM: MQ_AR,AR_AC0,CLR ARX,FE_-1,J/IMLONG;[424] Yes, or IMULM/B. No opt
=
;
IMFAST: AR_ARX,ARL/SH,ARX_0.M,FE_-1, ;Finish setup (FE to force MUL DISP
SKP AR NZ ; to work.) Can we optimize?
=010 BR_AR LONG,AR_0S,FE_#,#/-8, ;Yes. Set for truncated loop and
MUL DISP,CALL [MULP] ; start (note that SC has 17.)
IMLONG: BR_AR LONG,AR_0S,FE_#,#/-17., ;No. Do the full loop, starting
MUL DISP,CALL [MULP] ; here
AR_SHIFT,I FETCH,J/STORAC ;[424] Short IMUL(I). Load AC
SC_#,#/35.,SKP AR SIG ;Long IMULx. Did we overflow?
=0
IMDONE: AR_SHIFT,B WRITE,J/ST6 ;[424] No. Just store product
SET AROV,AR_SIGN,J/IMDONE ;Yes. Set overflow, force good sign
.DCODE
224: R, DBL AC, J/MUL ;MUL
I, DBL AC, J/MUL ;MULI
RW, M, J/MUL ;MULM
RW, DBL B, J/MUL ;MULB
.UCODE
=0****00*000
MUL: MQ_AR,CLR ARX,AR_AC0, ;MULTIPLIER TO MQ. Set multiplicand
FE_#,#/-18.,CALL,J/MULSUB ; and step count. Call subroutine
=100 SC_#,#/35.,GEN AR*BR,AD/AND, ;[421] M'IER NEG, CHECK M'CAND
SKP AD0 ; and product
=110 SC_#,#/35.,EXIT ;STORE DOUBLE RESULT
SET AROV,EXIT ;[421] MUST HAVE SQUARED 400000,,0
=
.TOC "MULTIPLY SUBROUTINE"
; ENTER WITH MULTIPLIER IN MQ,
; MULTIPLICAND IN AR!ARX, MINUS STEP COUNT IN FE
; RETURNS PRODUCT IN AR!ARX!MQ.
; RETURN 4, 6 TELLS SIGN OF MULTIPLIER
; 4 AND 6 ARE USED SO CALLER CAN IGNORE
; DIFFERENCE BY ALIGNMENT OF CALL LOC'N
;[TIME=4+2(-FE)+(# OF ARITH STEPS)] ... IF FE=-18, 40-58.
;
;Recall:
; MUL "FE_FE+1,DISP/MUL,MQ/MQ*.25"
;
MULSUB: BR_AR LONG,AR_0S,ARX_0S, ;M'CAND TO BR LONG, CLEAR PROD
MUL,J/MULP ;START THE MULTIPLICATION
=000 ;GRAB AN 8-WORD BLOCK
MULP: (AR+ARX+MQ)*2,FE_SC,RETURN6 ;XADDR MACHINE HAS
(AR+ARX+MQ)*2,FE_SC,RETURN6 ; NO "CRA MUL DONE"
(AR+ARX+MQ)*2,FE_SC,RETURN6
(AR+ARX+MQ)*2,FE_SC,RETURN6 ;DISCARD REDUNDANT SIGN BIT
AR_AR*.25 LONG,MUL,J/MULP ;M'IER BITS 00 AFTER POS STEP
AR_(AR+BR)*.25,ARX/ADX*.25, ;01 AFTER +
MUL,J/MULP
AR_(AR-2BR)*.25,ARX/ADX*.25, ;10 AFTER +
MUL,J/MULM
AR_(AR-BR)*.25,ARX/ADX*.25,
MUL,J/MULM ;11 AFTER +
=000 ;ANOTHER 8-WORD BLOCK FOR
MULM: (AR+ARX+MQ)*2,FE_SC,RETURN4 ; AFTER SUBTRACTION STEPS
(AR+ARX+MQ)*2,FE_SC,RETURN4
(AR+ARX+MQ)*2,FE_SC,RETURN4
(AR+ARX+MQ)*2,FE_SC,RETURN4 ;M'IER WAS NEGATIVE
AR_(AR+BR)*.25,ARX/ADX*.25, ;M'IER BITS 00 AFTER NEG STEP
MUL,J/MULP
AR_(AR+2BR)*.25,ARX/ADX*.25, ;01 AFTER -
MUL,J/MULP
AR_(AR-BR)*.25,ARX/ADX*.25, ;10 AFTER -
MUL,J/MULM
AR_AR*.25 LONG,MUL,J/MULM ;11 AFTER -
;HERE TO CONTINUE A LONG MULTIPLICATION
; WITH PARTIAL PRODUCT IN AR LONG
MULREE: AD/0S,MUL,J/MULP ;DIVE IN WITHOUT CLOBBERING AR
.TOC "DIV, IDIV"
.DCODE
230: R, DBL AC, J/IDIV ;IDIV
I, DBL AC, J/IDIV ;IDIVI
RW, M, J/IDIV ;IDIVM
RW, DBL B, J/IDIV ;IDIVB
234: R, DBL AC, J/DIV ;DIV
I, DBL AC, J/DIV ;DIVI
RW, M, J/DIV ;DIVM
RW, DBL B, J/DIV ;DIVB
.UCODE
=0****00*000
DIV: BR/AR,AR_AC1*2,ARL/AD*2, ;DIVISOR TO BR, LOW DIVIDEND TO AR
ARX+MQ_0.M,CALL.M,J/DIV1 ;[422] GET HIGH DIVIDEND
=010 ;[422]
IDIV: BR/AR,ARR+MQ_0.S,ARX_AC0,ARL/AD,;[421] BR_divisor; fetch dividend
SC_1,SKP AD0,CALL [IDIVGO] ; Isolate top half. Is it < 0?
=110 ARX_AR,AR_-BRX,SC_#,#/36.,EXIT ;Remainder to ARX, negate quotient
ARX_AR,AR_BRX,SC_#,#/36.,EXIT ;HERE FOR POS QUOTIENT
=
;HERE ON DIVIDE TO SET UP DIVIDEND
DIV1: BRX/ARX,ARX_AR,AR_AC0, ;CLR BRX, DIVIDEND IN AR LONG
FE_#,#/33.,TIME/3T, ;SETUP ITERATION COUNT
SIGNS DISP,J/DIVS1 ;ENTER SUBR
;
; Start of divide subroutine for IDIVx. We will optimize the
; division by taking only 19 (instead of 36) divide steps if the
; top half of the absolute value of the dividend is zero. Enter
; skipping if the dividend is positive. This routine will set
; up for the division and go to DIVS1 (or DIVS2) to begin the
; actual division. The latter take care of the subroutine return.
;
=0
IDIVGO: AR_ARX,ARX/MQ,FE_#,#/33., ;Recover positive dividend, set
SKP AR NZ,J/IDVOPT ; long step count. Can we optimize?
ARX_-AC0,ARR_0.M,ARL/AD, ;Negative dividend. Start building
FE_#,#/12,SKP AD0 ; step count. Is it max neg?
=0 AR_ARX,ARX/MQ,FE_#,#/33., ;No. Set long step count and
SKP AR NZ,J/IDVOPT ; test for optimization
MQ_1,TIME/2T,ARX/MQ,FE_FE+#,#/27,;Yes. Set up for positive version
AR CTL/0,EXP TST/0,J/IDVLNG ;and long count (avoid conflict)
;
=0
IDVOPT: BRX/ARX,AR_0S,ARX_AR SWAP,FE_#, ;Can optimize. Left adjust dividend
#/16.,SIGNS DISP,J/DIVS1 ; Set short divide count and go
IDVLNG: BRX/ARX,AR_MQ,ARL/AD,ARX_SHIFT, ;Dividend too big. Kill sign bit,
MQ_0.M,SIGNS DISP,J/DIVS1 ; clear MQ, set AR (FE already 33.)
.TOC "INTEGER DIVIDE SUBROUTINE"
; ENTER WITH SIGNS DISPATCH OF DIVISOR AND DIVIDEND,
; DIVISOR IN BR, BRX CLR; DIVIDEND IN AR!ARX
; STEP COUNT IN FE (# OF QUOTIENT BITS -2)
; If no divide, check for the maximum negative number as a
; quotient, and force it if it is there; otherwise, just set
; no divide. Exit the instruction in either case. [420]
; OTHERWISE, RETURN WITH SIGNED REMAINDER IN AR,
; POSITIVE QUOTIENT IN BRX AND MQ.
; RETURN 6 IF QUOTIENT SHOULD BE NEGATIVE,
; RETURN 7 IF QUOTIENT SHOULD BE POSITIVE.
;[TIME=14+3(FE)+3(D'END NEG)+3(RESTORE REQ'D)+1(REMAINDER NEG)]
; ... IF FE=33, 113-120
;
;Recall:
; DIVIDE "FE_FE-1,DISP/DIV,MQ/MQ*2"
;
=1100
DIVS1: DIVIDE,AR_2(AR-BR),
ARX/ADX*2,J/DIVS3 ;BOTH D'END AND D'SOR POS
AR_-AR LONG,J/DIVS1 ;MAKE POS DIVIDEND, THEN CHK
DIVS2: DIVIDE,AR_2(AR+BR),
ARX/ADX*2,J/DIVS4 ;D'END POS, D'SOR NEG
AR_-AR LONG,J/DIVS2
=0010
DIVS3: DIVIDE,AR_2(AR+BR),ARX/ADX*2,
ARL/AD*2,CALL.M,J/DIVLP ;START DIVIDING
AR_AR*.25 LONG,FE_#,#/40, ;[420] Possible overflow, but
CALL [MAXDIV] ; might be -2**-35 quotient
AR_-BR,BRX/ARX,RETURN6 ;D'END NEG, SO NEGATE QUO & REM
BRX/ARX,RETURN7 ;EVERYTHING POSITIVE
=1111 MQ_ARX-BR ;Possible legal quotient. Check rem
=1110 SC_#,#/36.,GEN MQ*AC0,AD/ORC, ;and make sure dividend was negative
SKP AD0,CALL [MAXCHK] ;with remainder < divisor
ARX_-BRX,EXIT ;Looks OK. Negate remainder
;
=0010
DIVS4: DIVIDE,AR_2(AR-BR),ARX/ADX*2,
ARL/AD*2,CALL.M,J/DIVLP ;BEGIN DIVISION FOR REAL BITS
AR_AR*.25 LONG,FE_#,#/40, ;[420] Usually overflow, but might
CALL [MAXDIV] ; be in range
BRX/ARX,RETURN6 ;NEGATE QUO
AR_-BR,BRX/ARX,RETURN7 ;NEGATE REM
=1111 MQ_ARX+BR ;Look at bottom of dividend (must
=1110 SC_#,#/36.,GEN MQ*AC0,AD/ORCA, ; < |divisor|); also original dividend
SKP AD0,CALL [MAXCHK] ; must > 0
EXIT ;All conditions met. Force quotient
;
; MAXDIV, MAXCHK--Helper subroutines to check for a quotient of
; -2**35. This copies the low dividend half to BRX, sets up the
; quotient (in case we have to generate it) and tests the high
; dividend half to see if the first DIVIDE step generated a zero
; result. If it did not, we have a true overflow and we exit
; sideways; otherwise we return 17. The latter portion is reused
; for a subsequent test of the remainder.
;
MAXDIV: BRX/ARX,P_FE,GEN AR*2 LONG, ;Set up quotient, save remainder
SKP AD NZ ; Did first step generate a zero?
=0
MAXCHK: RETURN17 ;Yes. Look more closely
SET NO DIVIDE,I FETCH,J/NOP ;No. Must be a real overflow
.TOC "BASIC DIVIDE LOOP"
; THE LOOP ITSELF IS AN INNER SUBROUTINE, TO MAKE IT SUITABLE
; FOR USE IN DOUBLE-LENGTH DIVISION.
; THE DOUBLE LENGTH REMAINDER IS RETURNED IN BR!BRX (RESTORED)
; THE SINGLE LENGTH QUOTIENT (LOW PART IF DBL-LEN DIVISION) IN ARX
; RETURN 6 IF QUOTIENT (REALLY AC0.XOR.BR) NEGATIVE, OR 7 IF POSITIVE
;[TIME=12+3(FE)+3(RESTORE REQ'D)] ... IF FE=33, 111-114.
=000
DIVLP: DIVIDE,AR_2(AR+BR),ARX/ADX*2,J/DIVLP
DIVIDE,AR_2(AR-BR),ARX/ADX*2,J/DIVLP
DIV-: DIVIDE,AR_2(AR-BR),ARX/ADX*2,J/DIVLP
DIV+: DIVIDE,AR_2(AR+BR),ARX/ADX*2,J/DIVLP
DIVIDE,AR_AR+BR,ARX/ADX,J/DIVX
DIVIDE,AR_AR-BR,ARX/ADX,J/DIVX
DIVIDE,AR_AR-BR,ARX/ADX,J/DIVX ;NO SHIFT ON FINAL STEP
DIVIDE,AR_AR+BR,ARX/ADX,J/DIVX
;HERE AFTER FINAL DIVIDE STEP
; MQ HAS POSITIVE FORM QUOTIENT
; AR!ARX HAS REMAINDER, EXCEPT THAT IT MUST BE RESTORED IF IT IS
; NEGATIVE (IT'S NEGATIVE IF THERE WAS NO CARRY ON FINAL STEP)
; THE ORIGINAL DIVIDEND IS STILL IN AC0, SO WE CHECK ITS SIGN
; TO DETERMINE WHETHER TO NEGATE THE (RESTORED) REMAINDER.
=100
DIVX: AR_AR+BR LONG ;RESTORE REMAIN WITH POS D'SOR
BR_AR LONG,ARX/MQ,FE_SC, ;LONG REMAIN TO BR, QUO TO ARX
SKP AC0+,RETURN6 ;RETURN TESTING D'END SIGN
AR_AR-BR LONG ;RESTORE REMAIN WITH NEG D'SOR
BR_AR LONG,ARX/MQ,FE_SC,
SKP AC0-,RETURN6
;SUBROUTINE FOR FIRST PART OF LONG DIVISIONS
; ENTER AT DDVSUB WITH SKP BR0
; RETURN3 IF SHOULD RESUME WITH ADD STEP
; RETURN5 IF SHOULD RESUME WITH SUBTRACT
=000
DDVLP: AR_2(AR+BR),ARX/ADX*2,DIVIDE,J/DDVLP
AR_2(AR-BR),ARX/ADX*2,DIVIDE,J/DDVLP
DDVSUB: AR_2(AR-BR),ARX/ADX*2,DIVIDE,J/DDVLP
AR_2(AR+BR),ARX/ADX*2,DIVIDE,J/DDVLP
AR_MQ,MQ_AR,FE_#,#/32.,RETURN3
AR_MQ,MQ_AR,FE_#,#/32.,RETURN5
AR_MQ,MQ_AR,FE_#,#/32.,RETURN5
AR_MQ,MQ_AR,FE_#,#/32.,RETURN3
.TOC "DOUBLE INTEGER ARITHMETIC -- DADD, DSUB, DMUL, DDIV"
.DCODE
114: R, B/0, J/DASMD ;DADD
R, B/2, J/DASMD ;DSUB
R, B/4, J/DASMD ;DMUL
R, J/DDIV ;DDIV
.UCODE
;HERE FOR DOUBLE WORD ADD, SUBTRACT, MULTIPLY, OR DIVIDE
;ENTER WITH (E) IN AR, E IN VMA
=0****00**00
DDIV: ARX_AC3,CLR MQ,J/DDIV0 ;GET LOWEST PART OF D'END
DASMD: BR/AR,AR_AC1*2,ARL/AD*2, ;HIGH MEM WORD TO BR
VMA_VMA+1,LOAD ARX, ;ASK FOR LOW WORD
MQ_0.S,CALL.S,J/XFERW ;AND WAIT FOR IT
=11 ARX_ARX*2 ;SHIFT LOW MEM WORD LEFT
= BRX/ARX,ARX_AR,AR_AC0, ;ALL DATA IN PLACE
SC_#,#/35.,B DISP ;DO THE OPERATION
;HERE WITH (E) IN BR, (E+1)*2 IN BRX
; (AC) IN AR, (AC+1)*2 IN ARX
=00* AR_AR+BR LONG,AD FLAGS,J/ST2AC ;[430] DADD
AR_AR-BR LONG,AD FLAGS,J/ST2AC ;[430] DSUB
MQ_SHIFT,AR_0S,ARX_0S, ;DMUL, USE AC1 AS INITIAL M'IER
FE_#,#/-18.,J/DMULT ;SETUP STEP COUNT
=
;HERE FOR DOUBLE WORD MULTIPLY
=00*
DMULT: AD/0S,MUL,CALL.M,J/MULP ;BEGIN MULTIPLY
=10* AR_AR+BR LONG ;CANCEL EFFECTS OF LOW BIT 0
MQ_AR,AR_MQ ;EXCH HI AND LOW PRODUCT WORDS
;HERE AFTER 1ST CALL ON MPY SUBR. SAVE LOW WORD OF PROD, GET HIGH M'IER
AC3_AR ;LOW WORD OF PRODUCT
AR_AC0 ;GET HIGH M'IER WORD
=000 MQ_AR,AR_MQ,CALL, ;DIVE IN AGAIN
FE_#,#/-18.,J/MULREE ;CONTINUE THE MULTIPLY
=100 GEN AR*BR,AD/AND,SKP AD0 ;SKP IF M'IER, M'CAND, & PROD NEG
=110
DMUL1: AC0_AR,AR_SIGN,
SC_#,#/35.,J/DMUL2 ;STORE HIGH WORD OF PRODUCT
SET AROV,J/DMUL1
;MULTIPLY NOW COMPLETE, STORE RESULTS WITH PROPER SIGN IN BIT 0
DMUL2: BR/AR,AR_SHIFT ;GET 2ND WITH SIGN, SAVE SIGN
AC1_AR,AR_ARX,ARX/MQ ;READY TO BUILD 3RD WORD
ARX_SHIFT,AR_BR,MQ_MQ*2 ;SIGNIFICANT BITS TO ARX, SIGN TO AR
AR_SHIFT,ARX_AC3, ;3RD WORD IN AR, GET LOW
MQ_MQ*.25 ;EXTRA PROD BIT TO MQ 35
AC2_AR,AR_MQ ;,I FETCH WHEN TIMING FIXED
=0* ARX_SHIFT,AR_BR,I FETCH, ;LOW WORD AND SIGN READY
CALL,J/SHIFT ; GET LOW WORD TO AR
STRAC3: AC3_AR,FINISH ;GANZ GETAN
;HERE FOR DOUBLE INTEGER DIVISION
;AR HAS (E), ARX HAS (AC3), AND MQ IS CLEAR
DDIV0: T0_AR,AR_ARX,ARX_ARX*8,SC_1 ;SAVE (E) IN T0
BRX/ARX,ARX_SHIFT, ;AC3 3-35 TO BRX, 1-2 TO ARX
AR_AC2,SC_#,#/2 ;GET AC2 READY
AR_SHIFT,BR/AR, ;AC2 BITS 2-35 WITH AC3 1-2
ARX_AC1,VMA_VMA+1 ;READY TO GET (E+1)
BR/AR,AR_ARX,ARX_BR*2, ;LOW DOUBLE WORD NOW IN BR LONG
SC_1,FE_1
ARX_SHIFT,AR_AC0,SKP AD0 ;HIGH DOUBLEWORD IN AR LONG
=0
DDIV1: BR_AR LONG,AR_BRX,ARX_BR, ;HI POS D'END TO BR
LOAD AR,J/DDIV2 ;GET LOW D'SOR READY
BR_AR LONG,AR_-BR LONG, ;NEGATE LOW D'END
FE_-1,SKP CRY0 ;TEST FOR CARRY PROPAGATION
=0 BR_AR LONG,AR_BR COMP LONG,J/DDIV1
BR_AR LONG,AR_-BR LONG,J/DDIV1 ;FINISH NEGATION OF D'END
=0*
DDIV2: T1_AR,MQ_ARX,ARX_0S, ;LOWEST D'END TO T1, NEXT TO MQ
CALL,J/XFERW ; WAIT FOR (E+1)
ARX_SHIFT,AR_T0,SKP FE0 ;DIVISOR NOW IN AR LONG
=0 AR_BR LONG,BR_AR LONG, ;PUT OPERANDS IN PLACE FOR DIV
SIGNS DISP,J/DDIV3 ;TEST D'SOR SIGN
AR_BR LONG,BR_AR LONG,SET SR2, ;NOTE D'END NEGATIVE
SIGNS DISP,J/DDIV3
;HERE WITH THE DIVISOR IN BR LONG,
; THE HIGH PART OF THE MAGNITUDE OF THE DIVIDEND IN AR LONG,
; AND THE LOW PART OF THE MAGNITUDE OF THE DIVIDEND IN MQ AND T1
; SKIP IF DIVISOR NEGATIVE, & CHECK FOR NO-DIVIDE.
=1011
DDIV3: AR_2(AR-BR),ARX/ADX*2,MQ_MQ*2, ;SEE IF FIRST DIVIDE STEP
SKP CRY0,J/DDIV4 ; GENERATES A 1
AR_2(AR+BR),ARX/ADX*2,MQ_MQ*2,SKP CRY0
=000
DDIV4: FE_#,#/33.,SKP BR0,CALL,J/DDVLP ;GO DO FIRST HALF OF DIVIDE
SET NO DIVIDE,I FETCH,J/NOP ;[422] TOO MANY QUOTIENT BITS
=011 AC1_AR,CLR SC,J/DDIV6 ;SAVE HI QUOTIENT IN AC1
=101 AC1_AR,SC_1S ;SET FLAG FOR RESUMPTION
=
DDIV6: AR_T1 ;GET LOWEST DIVIDEND BITS
=100 MQ_AR,AR_MQ,CALL, ;FINISH DIVISION, GENERATING
SKP SC0,J/DIVLP ; 35 MORE QUOTIENT BITS
=110 AR_AC1,SR DISP,SET SR3,J/DDVX1 ;QUOTIENT NEGATIVE. NOTE
AR_AC1,SR DISP ;HERE'S HIGH PART OF QUOTIENT
=1101
DDVX1: BR_AR LONG,AR_BR LONG,J/DDVX2 ;POS REMAINDER. GO STORE
BR_AR LONG,AR_-BR LONG,J/DDVX2 ;NEGATE REMAINDER
DDVX2: AC2_AR,AR_SIGN,SC_#,#/35.
AR_SHIFT,SR DISP ;GET LOW WORD OF REM. TEST QUO SIGN
=1110 AC3_AR,AR_BR,ARX/ADX*2,J/ST2AC ;[430] GET QUO, SQUEEZE OUT HOLE
AC3_AR,AR_-BR,ARX/ADX*2,AD LONG,;GET NEGATIVE QUOTIENT
J/ST2AC ;[430]