;
; DOUBLE PRECISION SIGNED MULTIPLY AND DIVIDE
;********************************************
; DIGITAL COMPUTER CONTROLS,INC.
; 116-0018A,116-0019A
;
; SIGNED DOUBLE MULTIPLY
; MULTIPLIES TWO SIGNED, DOUBLE PRECISION NUMBERS
; INPUT:        D1 IN AC0 (HIGH ORDER), AC1 (LOW ORDER)
;               D2 POINTED TO BY WORD AFTER JSR .DMPY
; OUTPUT:       D1*D2 IN STORAGE POINTED TO BY AC2
;               AC2 POINTS TO HIGHEST ORDER
; CALLING SEQUENCE:
;       JSR     .DMPY
;       ADDRESS OF D2
;       RETURN
; DESTROYED:    ALL ACS AND CARRY
; REQUIRES:     .MPYU & .MPYA (UNSIGNED MULTIPLY)
	.REL	0
	.TITL	.DMPY
	.ENT	.DDIV
	.EXTN	.MPYU
	.EXTN	.MPYA
.DMPY:  STA 3,.BC03     ; SAVE RETURN
        SUB 2,2         ; CLEAR RESULT FLAG WORD
        JSR .BB50       ; FORM ABSOLUTE VALUE OF D1
        STA 0,.BC10     ; SAVE ABS(D1)
        STA 1,.BC10+1
        LDA 3,.BC03     ; RESTORE AC3
        ISZ .BC03       ; BUMP PAST ADDRESS CONSTANT
        LDA 3,0,3       ; GET ADDRESS OF D2
        LDA 0,0,3       ; GET D1
        LDA 1,1,3
        JSR .BB50       ; FORM ABSOLUTE VALUE OF D2
        MOVR 2,2
        SUBL 2,2
        STA 2,.BC13     ; 0 FOR RESULT MINUS, 1 FOR
                        ; PLUS
        STA 0,.BC10+2   ; SAVE ABS(D2)
        STA 1,.BC10+3
        LDA 2,.BC10+1   ; D1(LOW) * D2(LOW)
        JSR @.BC30      ; UNSIGNED MULTIPLY
        STA 1,.BC10+1   ; STORE LOWEST ORDER OF RESULT
        LDA 1,.BC10+2   ; D1(LOW) * D2(HIGH)
        JSR @.BC31      ; ADD HIGH ORDER TO FIRST CROSS
                        ; PRODUCT
        LDA 2,.BC10     ; D1(HIGH)
        STA 0,.BC10     ; SAVE HIGH ORDER OF 1ST CROSS
        MOV 1,0         ; LOW ORDER TO BE ADDED TO
                        ; SECOND CROSS
        LDA 1,.BC10+3   ; D2(LOW) * D1(HIGH)
        JSR @.BC31      ; SECOND CROSS PRODUCT
        STA 1,.BC10+3   ; 2ND LOWEST ORDER OF RESULT
        LDA 1,.BC10+2   ; D1(HIGH) * D2(HIGH)
        JSR @.BC31      ; ADD HIGH ORDER OF CROSS TO
                        ; HIGH ORDER MULTIPLY
        LDA 2,.BC10     ; ADD HIGH ORDER OF 1ST CROSS
        ADDZ 2,1,SZC
        INCZ 0,0
        LDA 2,.BC10+3
        LDA 3,.BC10+1   ; GET LOW ORDER RESULTS
        DSZ .BC13       ; TEST SIGN OF RESULT
        JMP .BB53       ; NEGATIVE - NEGATE RESULT
        JMP .BB54       ; POSITIVE - STORE RESULTS
	.FORM
; ENTRY AT .BB50 FORMS ABSOLUTE VALUE OF NUMBER
;       IN AC0, AC1 AND INCREMENTS AC2
; ENTRY AT .BB56 NEGATES AC0, AC1 AND INCREMENTS AC2
; ENTRY AT .BB51 NEGATES AC0, AC1
.BB50:  MOVL# 0,0,SNC
        JMP 0,3
.BB56:  INC 2,2
.BB51:  NEG 1,1,SZR
        COM 0,0,SKP
        NEG 0,0
        JMP 0,3
; ENTRY AT .BB52 FORMS ABSOLUTE VALUE OF NUMBER
;       IN AC0, AC1, AC2, AC3
; ENTRY AT .BB53 FORMS QUADRUPLE NEGATE
; ENTRY AT .BB54 STORES THE ACS IN A BLOCK STARTING
;       AT .BC10
; IF .DMPY CALLED THE ROUTINE, CARRY WILL BE ZERO
; IF .DDIV CALLED THE ROUTINE, CARRY WILL BE NON-ZERO
.BB52:  MOVL# 0,0,SNC
        JMP .BB54
.BB53:  NEG 3,3,SZR
        COM 2,2,SKP
        NEGC 2,2,SZR
        COM 1,1,SKP
        NEGC 1,1,SZR
        COMC 0,0,SKP
        NEGC 0,0,SNR
        MOVC 0,0
.BB54:  STA 0,.BC10
        STA 1,.BC10+1
        STA 2,.BC10+2
        STA 3,.BC10+3
        MOV 0,0,SZC
        JMP .BC98       ; RETURN TO DIVIDE ROUTINE
.BB55:  LDA 2,.BC32     ; POINTER TO MULTIPLY RESULTS
                        ; OR DIVIDE REMAINDER
        JMP @.BC03      ; RETURN
	.FORM
.BC03:  0               ; SAVE RETURN
.BC10:  .BLK 4          ; SAVE ABS(U),
                        ; RESULTS OF MULTIPLY,
                        ; OR REMAINDER OF DIVIDE
.BC11:  .BLK 2          ; SAVE ABS(V)
.BC12:  .BLK 3          ; TEMPORARY STORAGE
.BC13:  0               ; SIGNS OF QUO./REMAINDER
                        ; FLAGS,
                        ; OR SIGN OF MULTIPLY RESULT
.BC14:  0               ; ITERATION COUNT WORD
.BC20:  41              ; ITERATION FOR DIVIDE (33)
.BC30:  .MPYU           ; UNSIGNED MULTIPLY
.BC31:  .MPYA           ; UNSIGNED MULTIPLY AND ADD
.BC32:  .BC10           ; POINTER TO  RESULTS
	.FORM
; SIGNED DOUBLE DIVIDE
; DIVIDES TWO SIGNED, MULTIPLE PRECISION NUMBERS
; INPUT:        DIVIDEND (U), A QUADRUPLE PRECISION
;       TWO'S COMPLEMENT INTEGER,
;       POINTED TO (HIGH ORDER WORD) BY AC2
;       AND OCCUPYING FOUR CONTIGUOUS MEMORY LOCATIONS
;       DIVISOR (V), A DOUBLE PRECISION TWO'S
;       COMPLEMENT NUMBER IN AC0, AC1 (HIGH, LOW)
; OUTPUT:       U0,U1,U2,U3/V0,V1
;       DOUBLE PRECISION, SIGNED QUOTIENT IN AC0, AC1
;       (HIGH, LOW)
;       DOUBLE PRECISION SIGNED (SAME AS DIVIDEND)
;       REMAINDER POINTED TO BY AC2 (HIGH, LOW)
; CALLING SEQUENCE:
;       JSR     .DDIV
;       RETURN
; ERROR CONDITIONS:     IF ABS(U0,U1) >= ABS(V0,V1),
;                       CARRY WILL BE
;                       SET AND RESULTS UNPREDICTABLE
;                       IF THE QUOTIENT HAS AN ABSOLUTE
;                       VALUE >= 2**31,
;                       CARRY WILL BE SET AND
;                       RESULTS UNPREDICTABLE
; DESTROYED:    ALL ACS AND CARRY
.DDIV:  STA 3,.BC03     ; SAVE RETURN
        STA 2,.BC10     ; SAVE AC2 TEMPORARILY
        SUBZR 2,2       ; CLEAR FOR RESULT SIGN FLAGS
        JSR .BB50       ; FORM ABSOLUTE VALUE OF
                        ; DIVISOR
.BC99:  STA 0,.BC11     ; SAVE ABS(V)
        STA 1,.BC11+1
        MOVZL 2,3       ; POSITION DIVISOR SIGN TO BIT
                        ; 14, SET CARRY
        LDA 2,.BC10     ; RESTORE AC2
        LDA 0,0,2       ; GET DIVIDEND
        MOVL# 0,0,SZC
        INC 3,3
        STA 3,.BC13     ; SIGN FLAGS ARE SET
        LDA 1,1,2
        LDA 3,3,2
        LDA 2,2,2
        JMP .BB52       ; FORM ABSOLUTE VALUE OF
                        ; DIVIDEND (NOTE CARRY SET)
	.FORM
.BC98:  LDA 2,.BC11     ; GET DIVISOR FOR ERROR TEST
        LDA 3,.BC11+1
        SUBZ# 2,0,SNC   ; ERROR IF U0,U1 >= V0,V1
        JMP .+4
        ADCZ# 2,0,SNC
        SUBZ# 3,1,SZC
        JMP @.BC03      ; ERROR, CARRY IS SET
        LDA 3,.BC20     ; +33
        STA 3,.BC14     ; STORE LOOP COUNT
        MOVZ 0,0        ; CLEAR CARRY
        JMP .BC90
.BC89:  SUBZ 3,1,SNC    ; SUBTRACT DIVISOR FROM HIGH
                        ; DIVIDEND
        ADCZ 2,0,SKP
        SUBZ 2,0
        JMP .BC90
.BC88:  MOVL 1,1
        MOVL 0,0
        LDA 2,.BC11     ; GET DIVISOR
        LDA 3,.BC11+1
        SUB# 2,0,SNC    ; WILL DIVISOR GO INTO
                        ; DIVIDEND
        JMP .BC90       ; NO
        SUB# 2,0,SNR
        SUB# 3,1,SZC
        JMP .BC89       ; YES
.BC90:  LDA 3,.BC10+3
        LDA 2,.BC10+2
        MOVL 3,3        ; SHIFT DIVIDEND AND QUOTIENT
        MOVL 2,2
        STA 2,.BC10+2
        STA 3,.BC10+3
        DSZ .BC14
        JMP .BC88       ; NOT DONE YET
        LDA 2,.BC13     ; GET FLAGS
        MOVR 2,2,SZC
        JSR .BB56       ; NEGATE REMAINDER, INC AC2
        STA 0,.BC10     ; AND STORE IT
        STA 1,.BC10+1
        LDA 0,.BC10+2   ; GET QUOTIENT
        LDA 1,.BC10+3
        MOVL 0,3,SZC    ; TEST FOR >2**31
        JMP @.BC03      ; YES, CARRY SET FOR ERROR
        MOVR 2,2,SZC
        JSR .BB51       ; NEGATE QUOTIENT
        MOVZ 0,0        ; CLEAR CARRY
        JMP .BB55       ; RETURN
	.END		;DBL.MULT/DIV
