|
|
DataMuseum.dkPresents historical artifacts from the history of: CP/M |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about CP/M Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 86912 (0x15380)
Types: TextFile
Names: »D160«
└─⟦ae2411776⟧ Bits:30008864 Diskette med tekster der formodes at være 31-D-152…161
└─⟦this⟧ »D160«
******************************************
DMATHO.S
created 770801; last modified 791023
******************************************
H ADD AND SUBTRACT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FLOATING POINT REVERSE SUBTRACT ROUTINE
; NEGATE X AND ADD
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RSUB LD A,(IX) ; GET MS BYTE OF X
XOR 80H ; NEGATE SIGN
LD D,A ; SAVE IT
LD E,(IY) ; GET MS BYTE OF Y
JP AD05
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FLOATING POINT SUBTRACT ROUTINE
; NEGATE Y AND ADD
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SUB LD A,(IY) ; GET MSBYTE OF Y
XOR 80H ; NEGATE SIGN
LD E,A ; SAVE IT
LD D,(IX) ; GET MSBYTE OF X
JP AD05
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FLOATING POINT ADD ROUTINE
;
; INPUT: IX PTS TO 1ST ARG
; IY PTS TO 2ND ARG
; OUTPUT: IX PTS TO SUM (X IS REPLACED BY SUM, Y IS UNCHANGED)
; ERRORS: EXPONENT OVERFLOW AND UNDERFLOW
; SPECIAL CASES: ZERO ARGUMENT(S)
;
; INPUT FOR AD05: D CONTAINS MS BYTE OF X
; E CONTAINS MS BYTE OF Y
; ALGORITHM: ABSOLUTE VALUE MAGNITUDES ARE COMPARED,
; THE LARGER IS LOADED TO AC1, THE SMALLER TO AC2.
; AC2 IS SHIFTET TO ALIGN DECIMAL POINTS.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ADD LD D,(IX) ; GET MS BYTES
LD E,(IY)
;
; CHECK FOR ZERO ARGUMENTS
;
AD05 XOR A ; CLEAR A
CP (IX+7)
JP NZ,AD07 ; X IS NONZERO
CP (IY+7)
RET Z ; Y IS ALSO ZERO
LD A,E ; GET Y MSBYTE
PUSH IY
POP HL
CALL LD ; COPY TO X
LD (IX),A ; STORE MSBYTE
RET
\f
AD07 LD (IX),D ; STRE NEW SIGN IN CASE Y IS 0
CP (IY+7)
RET Z ; Y IS ZERO, RETURN X
;
; LOAD ARGUMENTS, LARGER MAGNITUDE IN AC1
;
PUSH DE ; SAVE MS BYTES
RES 7,D ; CLEAR SIGN BITS
RES 7,E
CALL CP1 ; COMPARE X TO Y IGNORING SIGN
JR C,AD10 ; X < Y
CALL STA1 ; X TO AC1
CALL STYA2 ; Y TO AC2
POP BC ; GET SIGNS
LD A,B
XOR C
LD A,B ; USE SIGN OF X FOR RESULT
JP AD15
AD10 CALL STYA1 ; Y TO AC1
CALL STA2 ; X TO AC2
POP BC ; GET SIGNS
LD A,C
XOR B
LD A,C ; USE SIGN OF Y FOR RESULT
;
; PRENORMALIZE BY SHIFTING AC2 RIGHT
;
AD15 EX AF,AF' ; SAVE RESULT SIGN, XOR FLAGS
LD A,(AC1E) ; GET AC1 EXPONENT
LD HL,AC2E
SUB (HL) ; CALC SHIFT COUNT
JR Z,AD30 ; FRACTIONS ALREADY ALIGNED
CP 13
JP NC,FSTO ; AC2 IS INSIGNIFICANT
LD B,A ; SET COUNTER
AD20 XOR A ; CLEAR A
LD HL,AC2 ; PT TO ACCUM
CALL SRD1 ; SHIFT RT 1 DIGIT
DJNZ AD20 ; COUNTER NOT 0
;
; INITIALIZE FOR ADD OR SUB
;
AD30 LD B,7 ; COUNTER
LD HL,AC20 ; POINTERS
LD DE,AC10
AND A ; CLEAR CY
EX AF,AF' ; GET SIGN & FLAGS
JP M,SB10 ; SIGNS WERE DIFFERENT
;
; ADD
;
EX AF,AF' ; SAVE SIGN OF RESULT
AD40 LD A,(DE)
ADC A,(HL)
DAA
LD (DE),A
DEC DE
DEC HL
DJNZ AD40
\f
;
; POST NORMALIZE, AT MOST 1 SHFT RIGHT
;
LD A,(AC1) ; CHECK FOR OVERFLOW
AND 0F0H
JP Z,FSTO ; ALREADY NORMALIZED
LD HL,AC1E
INC (HL) ; INCREMENT EXPONENT
JP Z,OVERA ; OVERFLOW
LD HL,AC1 ; PT TO ACCUM
CALL SRD1 ; SHIFT RIGHT
JP FSTO
;
; SUB
;
SB10 EX AF,AF' ; SAVE SIGN OF RESULT
SB20 LD A,(DE)
SBC A,(HL)
DAA
LD (DE),A
DEC DE
DEC HL
DJNZ SB20
;
; POST-NORMALIZE BY SHIFTING LEFT
;
LD A,(AC1E) ; PUT EXP IN C
LD C,A
LD HL,AC1
CALL NORML2 ; NORMALIZE FRACTION
JP Z,ZERO ; ZERO FRACTION RESULT
JP C,UNDER ; EXPONENT UNDERFLOW
LD A,C ; STORE EXP
LD (AC1E),A
JP FSTO
;
; COPY AC1 TO (IX) AND SET SIGN OF RESULT
;
FSTO LD HL,AC1 ; PT TO AC1
CALL LD
JP RSTO ; SET SIGN FROM A'
*H MULTIPLY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FLOATING POINT MULTIPLY ROUTINE
;
; INPUT: IX PTS TO MULTIPLICAND
; IY PTS TO MULTIPLIER
; OUTPUT: IX PTS TO PRODUCT (PRODUCT REPLACES X, Y IS UNCHANGED)
; ERRORS: EXPONENT OVERFLOW OR UNDERFLOW
; SPECIAL CASES: ARGUMENT(S) ZERO
; ALGORITHM: X, 2X, 4X, and 8X ARE STORED IN TEMPORARY REGS.
; Y IS PLACED IN AC1.
; MULTIPLIER IS EXAMINED BIT AT A TIME WITHIN EACH DIGIT,
; CORRESPONDING TEMP REGS ARE ADDED TO (IX), AND (IX)
; IS SHIFTED RIGHT.
;
; TIMING: APPROX 19814 (16916 IN LOOP)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\f
;
; CHECK FOR ZERO OPERANDS
;
MULT XOR A
CP (IX+7)
JP Z,ZERO
CP (IY+7)
JP Z,ZERO
;
; CALCULATE AND SAVE SIGN OF RESULT
;
LD A,(IX) ; MS BYTE OF X
XOR (IY)
EX AF,AF' ; SAVE IN A>
;
; STORE X, 2X, 4X, AND 8X IN TEMP REGISTERS
;
PUSH IX
POP DE
LD HL,6
ADD HL,DE
LD (SAVE),HL ; SAVE PTR TO LS BYTE
EX DE,HL
CALL MDTL
;
; SAVE Y IN AC1 (IN CASE X AND Y ARE SAME)
; CLEAR (IX)
;
CALL STYA1 ; STORE Y IN AC1
LD IY,AC1 ; PT TO Y
CALL ZERO ; CLEAR X
LD B,7 ; LOOP COUNTER
JP ML20 ; SKIP SHIFT OF AC1
;
; SHIFT PRODUCT RIGHT ONE DIGIT
; GET NEXT MULTIPLIER DIGIT
;
ML10 XOR A ; CLEAR A
CALL SRD ; SHFT (IX) RIGHT
CALL MLDIG ; MULTIPLY BY 2ND DIGIT
XOR A
CALL SRD ; SHFT (IX) RIGHT
ML20 LD C,(IY+6) ; GET 2 DIGITS
DEC IY ; DECR PTR
CALL MLDIG ; MULTIPLY BY 1ST DIGIT
DJNZ ML10 ; COUNTER NOT 0
;
; CHECK NORMALIZATION
;
DEC B ; DEFAULT SHIFT COUNT IS -1
LD A,(IX) ; GET MS BYTE
AND 0F0H
JR Z,ML60 ; ALREADY NORMALIZED
INC B ; SET SHIFT COUNT TO 0
XOR A
CALL SRD ; SHIFT 0 INTO (IX)
\f
;
; CALCULATE EXPONENT OF RESULT
;
ML60 LD A,(TEMPOE) ; EXP OF ORIGINAL X
SUB 80H ; REMOVE BIAS
LD C,A
LD A,(IY+14) ; EXP OF ORIGINAL Y
SUB 80H ; REMOVE BIAS
ADD A,C ; ADD TWO EXPONENTS
;
; CHECK EXPONENT CALCULATION FOR ERRORS
;
MCHK JP PO,M10 ; NO OVERFLOW
ADD A,B ; ADD SHIFT COUNT
JP PO,MERR ; NO SECOND OVERFLOW
JP M20
M10 ADD A,B ; ADD SHIFT COUNT
JP PE,MERR ; OVERFLOW
M20 ADD A,80H ; RESTORE BIAS
JP Z,UNDER ; UNDERFLOW
LD (IX+7),A ; STORE EXP
JP RSTO
*H DIVIDE
;
; RECIPROCAL
;
REC CALL STO4 ; SAVE X
LD HL,C1
CALL LD ; GET A 1
LD IY,TEMP4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FLOATING POINT DIVISION ROUTINE
;
; INPUT: IX PTS TO DIVIDEND
; IY PTS TO DIVISOR
; OUTPUT: IX PTS TO QUOTIENT (QUOT. REPLACES X, Y UNCHANGED)
; ERRORS: DIVISOR ZERO
; EXPONENT OVERFLOW OR UNDERFLOW
; SPECIAL CASES: DIVIDEND ZERO
; ALGORITHM: Y, 2Y,4Y,8Y ARE STORED IN TEMP. REGS.
; X IS PLACED IN AC1. AC1 IS COMPARED TO THE TEMP
; REGS. A BIT AT A TIME WITHIN EACH DIGIT, SUBTRACTING
; WHEN TEMP <= AC1. RESULT BITS ARE ACCUMULATED IN C,
; AND STORED A BYTE AT A TIME INTO (IX)
; TIMING: APPROX. 22938 (20108 LOOP)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; CHECK FOR ZERO OPERANDS
;
DIVI XOR A
CP (IY+7)
JP Z,DIVO ; Y IS ZERO
CP (IX+7)
JP Z,ZERO ; X IS ZERO
;
; CALCULATE AND SAVE SIGN OF RESULT
;
LD A,(IX) ; MS BYTE OF X
XOR (IY)
EX AF,AF' ; SAVE IN A>
\f
;
; STORE Y, 2Y, 4Y, AND 8Y IN TEMP REGISTERS
;
PUSH IY
POP HL
CALL MDTL
;
; INITIALIZE AC1
;
PUSH IX ; SAVE IX
CALL STA1 ; STORE X IN AC1
LD BC,701H ; COUNTER IS 7, SHFT COUNT 1
PUSH BC ; SAVE COUNTERS
LD C,OFH ; INIT C
LD HL,TEMP0
CALL DVCP ; COMPARE X TO Y (FRACTIONS)
JR NC,DV30 ; X >= Y
POP BC
DEC C ; DECR SHIFT COUNT
PUSH BC
JP DV20 ; BEGIN WITH SHIFT DIGIT
;
; DIVIDE LOOP
;
DV10 PUSH BC ; SAVE COUNTERS
LD HL,AC1
XOR A
CALL SLD1 ; SHIFT AC1 LEFT 1 DIGIT
CALL DVDIG ; GET 1 DIGIT RESULT
DV20 LD HL,AC1
XOR A
CALL SLD1 ; SHIFT AC1 LEFT A DIGIT
DV30 CALL DVDIG ; GET 2ND DIGIT RESULT
LD A,C ; COMPL RESULT IN A
CPL ; TRUE RESULT
LD (IX),A ; STORE PAIR OF QUOTIENT DIGITS
INC IX
POP BC
DJNZ DV10 ; COUNTER NOT 0
;
; CALCULATE EXPONENT OF RESULT
;
LD B,C ; PUT SHIFT COUNT IN B
LD A,(TEMPOE) ; EXP OF ORIGINAL Y
SUB 80H
LD C,A ; SAVE UNBIASED EXP
LD A,(AC1E) ; EXP OF ORIGINAL X
SUB 80H ; REMOVE BIAS
SUB C ; SUB TWO EXPONENTS
POP IX ; RESTORE IX
JP MCHK ; CHECK FOR ERRORS
*H MULT, DIVI UTILITIES
;
; MLDIG MULTIPLY DIGIT
; INPUT: C CONTAINS DIGIT IN LOW 4 BITS
; (SAVE) IS PTR TO LS BYTE OF ACCUM
; OUTPUT: C IS ROTATED 4 BITS
; PRODUCT OF MPLICAND WITH DIGIT IS
; ADDED TO ACCUM
; TIMING 950
;
\f
MLDIG LD HL,TEMP00 ; PT TO MPLICAND
RR C
CALL C,MLADD ; ADD X
LD HL,TEMP10
RR C
CALL C,MLADD ; ADD 2X
LD HL,TEMP20
RR C
CALL C,MLADD ; ADD 4X
LD HL,TEMP30
RR C
CALL C,MLADD ; ADD 8X
RET
;
; MLADD ADD UTILITY FOR MULTIPLY
;
; INPUT: HL PTS TO NUMBER
; (SAVE) PTS TO LS BYTE OF ACCUM
; OUTPUT: 14 DIGIT NUMBER IS ADDED TO ACCUM
; TIMING 407
;
MLADD LD DE,(SAVE) ; PT TO LS BYTE
AND A ; CLEAR CY
PUSH BC ; SAVE BC
LD B,7 ; SET COUNTER
ML40 LD A,(DE)
ADC A,(HL)
DAA
LD (DE),A
DEC DE
DEC HL
DJNZ ML40
POP BC
RET
;
; RSTO PRODUCES SIGN OF RESULT
; INPUT: IX PTS TO RESULT
; A' BIT 7 IS SIGN BIT
; OUTPUT: IX PTS TO RESULT
; TIMING 74
;
RSTO LD A,(IX) ; GET MS BYTE
AND 0FH ; CLEAR UPPER DIGIT
LD B,A
EX AF,AF' ; GET NEW SIGN BIT
AND 80H
OR B
LD (IX),A ; REPLACE MS BYTE
RET
;
; DVDIG ROUTINE TO DIVIDE 1 DIGIT
; INPUT: AC1 IS CURRENT REMAINDER (DIVIDEND)
; TEMP REGS CONTAIN 1,2,4,8*DIVISOR
; OUTPUT: C CONTAINS QUOTIENT DIGIT IN LOW 4 BITS
; (C ROTATED LEFT)
; AC1 CONTAINS REMAINDER (< DIVISOR)
; TIMING 1162
;
\f
DVDIG LD HL,TEMP3 ; PT TO 8Y
CALL DVCP
JR C,DVD10 ; AC1 < 8Y
LD HL,TEMP30
CALL DVSUB ; 8Y <= AC1
DVD10 RL C ; COMPL RESULT BIT IN C
LD HL,TEMP2 ; PT TO 4Y
CALL DVCP
JR C,DVD20 ; AC1 < 4Y
LD HL,TEMP20
CALL DVSUB ; 4Y < AC1
DVD20 RL C ; COMPL RESULT BIT IN C
LD HL,TEMP1 ; PT TO 2Y
CALL DVCP
JR C,DVD30 ; AC1 < 2Y
LD HL,TEMP10
CALL DVSUB ; 2Y < AC1
DVD30 RL C ; COMPL RESULT BIT IN C
LD HL,TEMP0 ; PT TO Y
CALL DVCP ; COMPARE TO AC1
JR C,DVD40 ; AC1 < Y
LD HL,TEMP00
CALL DVSUB ; Y < AC1
DVD40 RL C ; COMPL RESULT BIT IN C
RET
;
; DVCP ROUTINE TO COMPARE (DE) TO AC1
; RETURNS CY SET IFF (DE) < AC1
; RETURNS Z SET IFF (DE) = AC1
; TIMING APPROX 42
;
DVCP LD DE,AC1 ; PT TO AC1
LD B,7 ; SET COUNTER
DVC10 LD A,(DE) ; GET BYTE
CP (HL)
RET NZ ; < OR >
INC HL ; INC PTRS
INC DE
DJNZ DVC10 ; COUNTER NOT 0
RET
;
; DVSUB ROUTINE TO SUBTRACT (DE) FROM AC1
; ASSUMES 14 DIGIT OPERANDS
; TIMING 376
;
DVSUB LD DE,AC10 ; PT TO ACCUM
AND A ; CLEAR CY
LD B,7
DV40 LD A,(DE)
SBC A,(HL)
DAA
LD (DE),A
DEC DE
DEC HL
DJNZ DV40
RET
;
; ROUTINE TO LOAD TEMP REGISTERS
; TIMING 2014
;
\f
MDTL LD DE,TEMP0 ; FIRST DEST
CALL MOV ; LOAD TEMP0
LD HL,TEMP0 ; PT TO SRC
RES 7,(HL) ; CLEAR SIGN BIT
LD B,3 ; SET COUNTER
;
; LOOP TO COPY TEMPN TO TEMPN+1 & SHFT LFT 1 BIT
;
MDTL1 LD A,B ; SAVE COUNTER
CALL MOV ; MOVE TO NEXT TEMP
LD B,A ; RESTORE COUNTER
AND A ; CLEAR CY
CALL SLB1 ; SHFT LEFT (HL ALREADY OK)
INC HL ; PT TO MSBYTE JUST SHIFTED
DJNZ MDTL1 ; COUNTER NOT 0
RET
;
; DETERMINE OVER OR UNDER
;
MERR JP P,UNDER ; UNDERFLOW
JP OVERA
;
; DIVISION BY ZERO ERROR
;
DIV0 LD HL,ERROR
SET 4,(HL)
JP INF
*H FIX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FIX CONVERTS FLOATING POINT NUMBER TO
; 16 BIT 2'S COMPLEMENT INTEGER
; (ROUNDING)
;
; INPUT: IX PTS TO FL PT NUMBER
; OUTPUT: IX PTS TO INTEGER
; ERRORS: OVERFLOW IF X > 32767 OR X < -32768
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FIX LD IY,C _5
CALL ADD ; ADD .5
CALL FIXA ; CONVERT NUMBER
JR NC,FX10 ; NO OVERFLOW
LD HL,ERROR
SET 6,(HL) ; FLAG OVERFLOW
LD HL,7FFFH ; 32767
BIT 7,(IX)
JR Z,FX10 ; POSITIVE SIGN
LD HL,8000H ; -32768
FX10 LD (IX),L ; STORE INTEGER
LD (IX+1),H
RET
;
; MAIN CONVERSION FOR FIX
;
; RETURNS CY SET IF OVERFLOW
; RETURNS Z SET IF EXACT INTEGER
; HL IS LOW 16 BITS OF INT(X) FOR ALL X < 10 13
;
\f
FIXA XOR A
LD H,A ; CLEAR ACCUM
LD L,A
LD (SAVE),A ; CLEAR FLAG
;
; CALCULATE DIGITS LEFT AND RIGHT OF DECML PT
;
LD A,(IX+7) ; GET EXP
SUB 80H ; SUBTRACT BIAS
JR C,FXA100 ; X < .1
JR Z,FXA100 ; X < 1
LD B,A ; SAVE # LEFT DIGITS
LD A,13
SUB B
JR C,FXA90 ; X >= 10 13
LD C,A ; SAVE RIGHT DIGITS
;
; CONVERT LEFT DIGITS TO BINARY
;
PUSH IX ; SET POINTER
POP IY
LD A,(IY) ; GET FIRST BYTE
INC IY
JP FXA20
FXA10 CALL NZ,FXA110 ; OVERFLOW
LD A,(IY) ; GET NEXT TWO DIGITS
INC IY
PUSH AF ; SAVE THIS BYTE
RRA ; GET LEFT DIGIT
RRA
RRA
RRA
CALL MAD ; CONVERT LEFT DIGIT
DJNZ FXA15 ; COUNTER NOT 0
POP AF ; GET RIGHT DIGIT
AND OFH
JR FXA30
FXA15 CALL NZ,FXA110 ; OVERFLOW
POP AF ; GET SAVED BYTE
FXA20 CALL MAD ; CONVERT RIGHT DIGIT
DJNZ FXA10 ; COUNTER NOT 0
;
; CALCULATE OR OF ALL DIGITS TO RIGHT OF DECML PT
;
XOR A ; INITIALIZE A
FXA30 LD B,C ; USE OTHER COUNTER
SRL B ; DIVIDE BY 2
JR Z,FXA50 ; COUNT IS 0
FXA40 OR (IY) ; OR 2 DIGITS
INC IY
DJNZ FXA40 ; COUNTER NOT 0
;
; CONVERT TO 2'S COMPLEMENT
;
FXA50 BIT 7,(IX)
JR Z,FXA80 ; POSITIVE SIGN
EX DE,HL
LD HL,0
AND A
JR Z,FXA60 ; EXACT INTEGER
INC DE ; CORRECT MAGNITUDE
\f
FXA60 SBC HL,DE ; SUBTRACT FROM 0
JP P,FXA90 ; OVERFLOW
FXA70 AND A ; SET Z OR NZ
LD A,(SAVE) ; GET FLAG
RLA ; PUT IN CY
RET
FXA80 BIT 7,H
JR Z,FXA70 ; NO OVERFLOW
FXA90 AND A ; SET Z OR NZ
SCF ; SET CY
RET
FXA100 LD A,(IX+7) ; A IS 0 IFF FRACTION 0
JP FXA50
FXA110 LD A,(SAVE) ; GET FLAG
OR 80H ; TURN IT ON
LD (SAVE),A
RET
;
; MAD ROUTINE TO MULTIPLY ACCUM BY 10 AND ADD NEW DIGIT
;
MAD LD D,H ; SAVE COPY OF HL
LD E,L
ADD HL,HL ; SHIFT LEFT 2
ADD HL,HL
ADD HL,DE ; ADD COPY
ADD HL,HL ; SHIFT LEFT 1
AND 0FH ; PUT NEW DIGIT IN DE
LD E,A
LD D,0
ADD HL,DE ; ADD NEW DIGIT
LD A,H ; TEST HIGH BITS
AND 0F0H
RET
*H FLOAT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FLOAT CONVERTS 16 BIT 2'S COMPLEMENT INTEGER TO
; FLOATING POINT FORMAT
; (FLOAT1 ASSUMES INPUT IS IN HL)
;
; INPUT: IX PTS TO 16 BIT INTEGER
; OUTPUT: IX PTS TO FLOATING PT NUMBER
; ERRORS: NONE
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; TEST INPUT
;
FLOAT LD L,(IX) ; LOAD 16 BIT INTEGER
LD H,(IX+1)
FLOAT1 PUSH HL ; SAVE INTEGER
CALL ZERO ; CLEAR OUTPUT AREA
POP HL
LD A,H ; TEST FOR ZERO
OR L
RET Z ; INPUT WAS ZERO
;
; CONVERT TO SIGN MAGNITUDE, SIGN IN A'
;
LD A,H ; GET SIGN BIT
AND 80H
JR Z,FL10 ; POSITIVE
\f
EX DE,HL
LD HL,0
SBC HL,DE ; NEGATE
;
; CONVERT BINARY TO DECIMAL
;
FL10 EX AF,AF' ; SAVE SIGN BIT
EX DE,HL ; SAVE ACCUM
PUSH IX
POP HL ; PT TO OUTPUT AREA
LD BC,10000
CALL FLDIV ; DIVIDE BY 10000
INC HL ; ADVANCE OUTPUT PTR
LD BC,1000
CALL FLDIV ; DIVIDE BY 1000
LD BC,100
CALL FLDIV ; DIVIDE BY 100
INC HL ; ADVANCE OUTPUT PTR
LD BC,10
CALL FLDIV ; DIVIDE BY 10
LD A,E ; GET REMAINDER
RLD ; ROT INTO OUTPUT
;
; NORMALIZE RESULT, STORE SIGN
;
LD C,85H ; EXPONENT
CALL NORML1
JP RSTO ; STORE SIGN
;
; ROUTINE TO DIVIDE DE BY BC
; 4 BIT QUOTIENT IS ROTATED INTO (HL)
;
FLDIV EX DE,HL ; PUT ACCUM IN HL
XOR A ; CLEAR A, CY
DEC A ; INITIALLY A IS -1
FLDIV1 SBC HL,BC ; SUBTRACT DIVISOR
INC A ; INCR QUOTIENT
JR NC,FLDIV1 ; RESULT NOT NEGATIVE
ADD HL,BC ; RESTORE REMAINDER
EX DE,HL ; SAVE ACCUM, GET PTR
RLD ; STORE QUOTIENT
RET
*H CP
;
; CP FLOATING POINT COMPARE ROUTINE
;
; RETURNS CY SET IF X < Y
; RETURNS Z SET IF X = Y
; CP1 ASSUMES MS BYTES FOR X,Y IN D,E
;
CP LD D,(IX) ; LOAD MS BYTES
LD E,(IY)
CP1 LD A,D ; GET SIGN OF X
AND 80H ; (CY IS OFF)
JR NZ,CP10 ; X IS NEGATIVE
BIT 7,E
RET NZ ; Y IS NEGATIVE
;
; X AND Y ARE BOTH POSITIVE, COMPARE EXPONENTS
;
\f
LD A,(IX+7)
CP (IY+7)
RET NZ ; EXP'S NOT =
;
; COMPARE X FRACTION TO Y FRACTION
;
LD A,D ; MS BYTE
CP E ; (SIGNS ARE EQUAL)
RET NZ
PUSH IX ; SET UP PTRS
PUSH IY
JR CP20
;
; X IS NEGATIVE, CHECK SIGN OF Y
;
CP10 XOR E ; TEST SIGN, SET NZ
RLA ; SIGN BIT IN CY
RET C ; Y WAS POSITIVE
;
; BOTH SIGNS NEGATIVE, TEST EXPONENTS
;
LD A,(IY+7)
CP (IX+7)
RET NZ
;
; COMPARE Y FRACTION TO X FRACTION
;
LD A,E
CP D
RET NZ
PUSH IY ; SET UP PTRS
PUSH IX
;
; LOOP TO COMPARE 6 FRACTION BYTES
;
CP20 POP HL ; GET PTRS
POP DE
INC HL
INC DE
LD B,6 ; COUNTER
CP30 LD A,(DE)
CP (HL)
RET NZ
INC HL
INC DE
DJNZ CP30
RET
*H NORMALIZE
;
; NORMLZ NORMALIZES AN ACCUM BY SHIFTING LEFT
;
; INPUT: IX PTS TO ACCUM (NORMLZ,NORML1)
; HL PTS TO ACCUM (NORML2)
; C CONTAINS BIASED EXP (NORML1,NORML2)
; OUTPUT: NORMAL RETURN - NZ & NC
; ZERO FRACTION - Z & NC
; EXP UNDERFLOW - NZ & C
; C CONTAINS UPDATED EXPONENT
; (IX+7) CONTAINS UPDATED EXPONENT C UNDER C
;
\f
NORMLZ LD C,(IX+7) ; GET EXPONENT
NORML1 PUSH IX ; PT TO ACCUM
POP HL
NORML2 LD A,(HL) ; GET MS BYTE
AND A
JR NZ,NOR15 ; ALREADY NORMALIZED
LD B,12 ; MAX COUNT
XOR A ; CLEAR A
NOR10 DEC C ; DECR EXPONENT
JR Z,NOR20 ; UNDERFLOW
CALL SLD1 ; SHIFT LEFT
INC HL ; PT TO 1ST BYTE
LD A,(HL) ; GET MS BYTE
AND A
JR NZ,NOR15 ; NORMALIZED
DJNZ NOR10 ; COUNTER NOT 0
NOR15 LD (IX+7),C ; STORE EXPONENT
RET
;
; UNDERFLOW. HL PTS TO MS BYTE, A CONTAINS MS BYTE
;
NOR20 INC B ; CALC BYTES LEFT
SRL B
NOR30 INC HL ; ADVANCE PTR
OR (HL) ; COLLECT REMAINING BITS
DJNZ NOR30 ; COUNT NOT 0
RET Z ; FRACTION WAS ZERO
SCF
RET ; (UNDERFLOW)
*H HALF
;
; HALF DIVIDES A FLOATING POINT NUMBER BY 2
; INPUT MUST BE POSITIVE (0 IN SIGN DIGIT)
;
; INPUT: IX PTS TO X (HALF)
; OUTPUT: INPUT REPLACED BY X/2
; FLAGS SET ACCORDING TO NORMLZ
;
HALF AND A ; CLEAR CY
CALL SRB ; DIVIDE FRACTION BY 2
CALL NORMLZ ; NORMALIZE RESULT
RET
*H SHIFT UTILITIES
;
; SLD SHIFT LEFT DIGIT
;
; INPUT: IX PTS TO ACCUM (SLD)
; HL PTS TO ACCUM (SLD1)
; A CONTAINS DIGIT TO SHIFT IN
; OUTPUT: A CONTAINS DIGIT SHIFTED OUT
; HL PTS TO 1 LESS THAN MS BYTE
;
SLD PUSH IX ; SET PTR TO ACCUM
POP HL
SLD1 PUSH BC ; SAVE BC
LD BC,6
ADD HL,BC ; PT TO RIGHT END
LD B,7 ; LOOP COUNTER
SLD10 RLD ; ROT LEFT
\f
DEC HL ; PT TO NEXT BYTE
DJNZ SLD10 ; COUNTER NOT 0
POP BC ; RESTORE BC
RET
;
; SRD SHIFT RIGHT DIGIT
;
; INPUT: IX PTS TO ACCUM (SRD)
; HL PTS TO ACCUM (SRD1)
; A CONTAINS DIGIT TO SHIFT IN
; OUTPUT: A CONTAINS DIGIT SHIFTED OUT
; HL PTS TO 1 MORE THAN LS BYTE
;
SRD PUSH IX ; SET PTR TO ACCUM
POP HL
SRD1 PUSH BC ; SAVE BC
LD B,7 ; COUNTER
SRD10 RRD ; ROT RIGHT
INC HL
DJNZ SRD10 ; COUNTER NOT 0
POP BC ; RESTORE RC
RET
;
; SLB SHIFT LEFT BIT
;
; INPUT: IX PTS TO ACCUM (SLB)
; HL PTS TO ACCUM (SLB1)
; CY CONTAINS BIT TO SHIFT IN
; OUTPUT: CY CONTAINS BIT SHIFTED OUT
; HL PTS TO 1 LESS THAN MS BYTE
;
SLB PUSH IX ; SET PTR TO ACCUM
POP HL
SLB1 PUSH BC ; SAVE BC
LD BC,6
ADD HL,BC ; PT TO RIGHT END
LD B,7 ; LOOP COUNTER
SLB10 LD A,(HL) ; GET BYTE
ADC A,A ; SHIFT LEFT
DAA
LD (HL),A ; REPLACE
DEC HL ; PT TO NEXT BYTE
DJNZ SLB10 ; COUNTER NOT 0
POP BC ; RESTORE BC
RET
;
; SRB SHIFT RIGHT BIT
;
; INPUT: IX PTS TO ACCUM (SRB)
; HL PTS TO ACCUM (SRB1)
; CY CONTAINS BIT TO SHIFT IN
; OUTPUT: CY CONTAINS BIT SHIFTED OUT
; HL PTS TO 1 MORE THAN LS BYTE
;
SRB PUSH IX ; SET PTR TO ACCUM
POP HL
SRB1 PUSH BC ; SAVE BC
LD B,7 ; COUNTER
SRB10 LD A,(HL) ; GET BYTE
RRA ; SHIFT
\f
RR C ; SAVE CY IN C
BIT 7,A
JR Z,SRB20 ; 0 SHIFTED INTO UPPER
SUB 30H ; CORRECTION
SRB20 BIT 3,A
JR Z,SRB30 ; 0 SHIFTED INTO LOWER
SUB 3 ; CORRECTION
SRB30 RL C ; GET CY
LD (HL),A ; STORE BYTE
INC HL
DJNZ SRB10 ; COUNTER NOT 0
POP BC ; RESTORE BC
RET
*H MOVE UTILITIES
;
; MOVE ROUTINES
;
STO4 LD DE,TEMP4
JP STO
STO5 LD DE,TEM5
JP STO
STO6 LD DE,TEM6
STO PUSH IX
POP HL ; SET SRC PTR
MOV LD BC,8
LDIR
RET
LD PUSH IX
POP DE ; SET DEST PTR
JP MOV
;
; SPECIALIZED LOAD ROUTINES, LOAD AC1 AND AC2 WITH ABS VALUE
;
STA1 PUSH IX ; SOURCE WILL BE (IX)
JR ST1
STA2 PUSH IX ; SOURCE WILL BE (IX)
JR ST2
STYA1 PUSH IY ; SOURCE WILL BE (IY)
ST1 POP HL
MV1 LD DE,AC1 ; DEST IS AC1
CALL MOV
LD HL,AC1
LD D,(HL) ; SAVE MS BYTE IN D
RES 7,(HL) ; CLEAR SIGN BIT
RET
STYA2 PUSH IY ; SOURCE WILL BE (IY)
ST2 POP HL
MV2 LD DE,AC2 ; DEST IS AC2
CALL MOV
LD HL,AC2
LD E,(HL) ; SAVE MS BYTE IN E
RES 7,(HL) ; CLEAR SIGN BIT
RET
*H BOOLEAN
;
; LOGICAL OPERATORS
;
IOR LD A,(IX)
OR (IX+1)
OR (IY)
OR (IY+1)
JP INE1
\f
IAND LD A,(IX)
OR (IX+1)
JP Z,IZERO ; X IS ZERO
LD A,(IY)
OR (IY+1)
JP INE1
INOT LD A,(IX)
OR (IX+1)
JR IEQ1
OR LD A,(IX+7)
OR (IY+7)
JP NE1
AND LD A,(IX+7)
AND A
JP Z,ZERO ; X IS ZERO
LD A,(IY+7)
AND A
JR NE1
NOT LD A,(IX+7)
AND A
JR EQ1
;
; RELATIONAL OPERATORS
;
SGT CALL SCP
JR IGT1
SLE CALL SCP
JR ILE1
SLT CALL SCP
JR ILT1
SGE CALL SCP
JR IGE1
SEQ CALL SCP
JR IEQ1
SNE CALL SCP
JR INE1
IGT CALL ICP
IGT1 JR Z,IZERO
JR C,IZERO
JR IONE
ILE CALL ICP
ILE1 JR Z,IONE
JR C,IONE
JR IZERO
ILT CALL ICP
ILT1 JR C,IONE
JR IZERO
IGE CALL ICP
IGE1 JR C,IZERO
JR IONE
IEQ CALL ICP
IEQ1 JR Z,IONE
JR IZERO
INE CALL ICP
INE1 JR Z,IZERO
JR IONE
GT CALL CP
GT1 JR Z,ZERO
JR C,ZERO
JR ONE
\f
LE CALL CP
LE1 JR Z,ONE
JR C,ONE
JR ZERO
LT CALL CP
LT1 JR C,ONE
JR ZERO
GE CALL CP
GE1 JR C,ZERO
JR ONE
EQ CALL CP
EQ1 JR Z,ONE
JR ZERO
NE CALL CP
NE1 JR Z,ZERO
JR ONE
*H CONSTANT FUNCTIONS
;
; PRODUCE UNITY RESULT
;
IONE LD (IX),1
DD (IX+1),0
RET
ONE LD B,7
CALL ZERO1
LD (HL),81H
LD (IX),1
RET
;
; PRODUCE ZERO RESULT
;
IZERO LD (IX),0
LD (IX+1),0
RET
ZERO LD B,8
ZERO1 PUSH IX ; PT TO RESULT
POP HL
ZER10 LD (HL),0
INC HL
DJNZ ZER10
RET
;
; PRODUCE INFINITE RESULT
;
INF PUSH IX ; SET PTR
POP HL
RL (HL) ; GET OLD SIGN
LD (HL),18
RR (HL) ; REPLACE SIGN
INC HL
LD A,99H
LD B,6
INF10 LD (HL),A
INC HL
DJNZ INF10
LD (HL),0FFH ; HIGHEST EXP
RET
;
; FLAG OVERFLOW ERROR, STORE INFINITY
;
\f
OVERA EX AF,AF' ; GET SIGN OF RESULT
LD (IX),A ; STORE IT
OVER LD HL,ERROR
SET 6,(HL) ; FLAG OVERFLOW
JP INF
;
; FLAG UNDERFLOW ERROR, STORE ZERO
;
UNDER LD HL,ERROR
SET 5,(HL) ; FLAG UNDERFLOW
JP ZERO
*H CONSTANTS AND WORK AREAS
C1 DEFW 1
DEFW 0
DEFW 0
DEFW 8100H
C0 DEFW 0
DEFW 0
DEFW 0
DEFW 0
C _5 DEFW 5 ; .5
DEFW 0
DEFW 0
DEFW 8000H
SEED DEFW 0 ; 0
DEFW 0
DEFW 0
DEFW 0
SEED10 EQU SEED+6
CRNDA DEFW 1403H ; 31415 92653 581
DEFW 9215H
DEFW 3565H
DEFW 8081H
CRNDC DEFW 7102H ; 27182 81828 459
DEFW 8182H
DEFW 8482H
DEFW 8059H
CRNDCO EQU CRNDC+6
SAVE DEFS 2
AC1 DEFS 8
AC10 EQU AC1+6
AC1E EQU AC1+7 ; EXPONENT BYTE
AC2 DEFS 8
AC20 EQU AC2+6
AC2E EQU AC2+7 ; EXPONENT BYTE
TEMP0 DEFS 8
TEMP00 EQU TEMP0+6
TEMP0E EQU TEMP0+7
TEMP1 DEFS 8
TEMP10 EQU TEMP1+6
TEMP2 DEFS 8
TEMP20 EQU TEMP2+6
TEMP3 DEFS 8
TEMP30 EQU TEMP3+6
TEMP4 DEFS 8
TEMP5 DEFS 8
TEMP6 DEFS 8
\f
;
; REFERENCES
;
EXTERNAL ERROR,ICP,SCP
GLOBAL ADD,SUB,RSUB,MULT,REC,DIVI
GLOBAL MLDIG,MDTL
GLOBAL FIX,FIXA,FLOAT,FLOAT1,CP,MAD
GLOBAL GT,LE,LT,GE,EQ,NE,OR,AND,NOT
GLOBAL IGT,ILE,ILT,IGE,IEQ,INE,IOR,IAND,INOT
GLOBAL SGT,SLE,SLT,SGE,SEQ,SNE
GLOBAL SEED,SEED10,CRNDA,CRNDC0,C _5,SAVE,C1,C0
GLOBAL OVER,UNDER,ZERO,ONE,INF
GLOBAL NORMLZ,NORML1,NORML2,SLD,SRB,HALF
GLOBAL STO4,STO5,STO6,STO,LD,SRD
GLOBAL TEMP4,TEMP5,TEMP6,AC1,AC10,AC2,AC20
\f
******************************************
DMATH2.S
created 770801; last modified 791023
******************************************
*H POWER
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; X TO THE Y POWER
;
; INPUT: IX PTS TO X
; IY PTS TO Y
; OUTPUT: IX PTS TO X Y
; ERRORS: NONE DIRECTLY
; SPECIAL CASES: IF Y IS 0, RETURN 1
; ALGORITHM: IF Y IS AN EXACT INTEGER -32768 <= Y < 32768
; THEN USE A SEQUENCE OF SQUARING AND
; MULTIPLYING BY X TO PRODUCE RESULT
; OTHERWISE, RESULT IS EXP(Y*LOG(X))
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; DETERMINE IF Y IS AN INTEGER
;
POW PUSH IY ; SAVE PTR TO Y
PUSH IX ; SAVE PTR TO X
PUSH IY ; PT TO Y
POP IX
CALL FIXA ; CONVERT TO INTEGER
POP IX ; RESTORE IX
JR Z,POW10 ; Y WAS AN INTEGER
;
; FOR NONINTEGER Y, TAKE EXP(Y*LOG(X))
;
CALL LOG ; LOG OF X
POP IY ; RESTORE IY
CALL MULT ; MPY BY Y
CALL EXP ; EXP OF PRODUCT
RET
;
; Y IS INTEGER, SET UP FOR LOOP, GET MAGNITUDE
;
POW10 XOR A ; CHECK FOR 0
POP IY ; RESTORE IY
CP (IY+7)
JP Z,ONE ; X TO 0 POWER
PUSH HL ; SAVE Y
BIT 7,H
JR Z,POW15 ; Y IS POSITIVE
EX DE,HL ; NEGATE Y
LD HL,0
AND A
SBC HL,DE
EX (SP),HL ; SAVE NEGATED Y INSTEAD
CALL REC ; CALC 1/X
POW15 CALL ST04 ; SAVE COPY OF X
POP HL ; GET Y
LD B,16 ; SET COUNTER
\f
;
; LOOK FOR FIRST BIT
;
POW20 PUSH BC ; SAVE COUNTER
ADD HL,HL ; SHIFT Y LEFT 1
JR C,POW40 ; 1 BIT FOUND
POP BC ; GET COUNTER
DJNZ POW20 ; COUNTER NOT 0
JP ONE ; THIS JUMP SHOULD NOT HAPPEN
;
; SQUARE FOR EACH ZERO BIT
; SQUARE AND MULTIPLY FOR EACH 1 BIT
;
POW30 PUSH BC ; SAVE COUNTER
ADD HL,HL ; SHIFT Y LEFT 1
PUSH HL ; SAVE Y
PUSH AF ; SAVE CY
CALL STO5 ; SAVE COPY OF ACCUM
LD IY,TEM5
CALL MULT ; SQUARE X
POP AF ; GET CY
JR NC,POW35 ; WAS A 0 BIT
CALL MULT4 ; MPY BY X
POW35 POP HL ; GET Y
POW40 POP BC ; GET COUNTER
DJNZ POW30 ; COUNTER NOT 0
RET
;
; IPOW POWERS FOR INTEGER ARGUMENTS
; USES REAL POW ROUTINE BY FLOATING ARGS
; IN TEMP5, TEMP6, (UNUSED BY POW WHEN Y
; IS INTEGER), CALLING POW, AND FIXING RESULT
;
IPOW PUSH IX ; SAVE ORIGINAL PTR
LD L,(IY) ; GET Y
LD H,(IY+1)
LD IX,TEMP6
CALL FLOAT1 ; FLOAT Y IN TEMP6
POP IX ; GET ORIGINAL PTR
PUSH IX
LD L,(IX) ; GET X
LD H,(IX+1)
LD IX,TEMP5
CALL FLOAT1 ; FLOAT X IN TEMP5
LD IY,TEMP6 ; PT TO Y
CALL POW ; CALL REAL ROUTINE
CALL FIX ; FIX RESULT
POP IX ; GET ORIGINAL PTR
LD (IX),L ; STORE RESULT
LD (IX+1),H
RET
*H SQUARE ROOT
\f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SQUARE ROOT FUNCTION
;
; INPUT: IX PTS TO X
; OUTPUT: IX PTS TO SQR(X)
; ERRORS: X IS NEGATIVE, RETURNS SQR(ABS(X))
; SPECIAL CASES: X IS 0
; ALGORITHM: INPUT IS SCALED TO .1 <= X < 1
; BY REMOVING THE EXPONENT. HALF THE
; EXPONENT IS ADDED TO THE RESULT EXPONENT
; AND THE RESULT IS MULTIPLIED BY SQR(10)
; IF THE ORIGINAL EXP WAS ODD.
; AN INITIAL APPROXIMATION IS GIVEN BY
; A 1ST ORDER POLYNOMIAL, AND IMPROVED TO
; REQUIRED ACCURACY IN 4 ITERATIONS OF
; MEWTON'S METHOD
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; CHECK VALID ARGUMENTS
;
SQR LD A,(IX+7)
OR A
JP Z,ZERO ; ZERO INPUT
BIT 7,(IX)
CALL NZ,SQERR ; NEGATIVE INPUT
;
; SCALE BY STRIPPING EXPONENT
;
PUSH AF ; SAVE ORIGINAL EXP
LD (IX+7),80H ; SET ZERO EXP
;
; CALC INITIAL APPROX
;
CALL STO4 ; SAVE X
PUSH IX
LD IX,TEMP4
CALL HALF ; CALC X/2 IN TEMP4
POP IX
LD IY,PSQ00
CALL ADD; INIT APPROX.
;
; PERFORM 4 ITERATIONS
;
LD B,4
SQ10 PUSH BC ; SAVE COUNTER
CALL STO5 ; SAVE LAST APPROX IN TEMP5
LD HL,TEMP4
CALL LD ; GET X/2
LD IY,TEMP5
CALL DIVI ; DIVIDE BY LAST APPROX
PUSH IX
LD IX,TEMP5
CALL HALF ; DIVIDE LAST APPROX BY 2
POP IX
CALL ADD ; CALC NEW APPROX
POP BC
DJNZ SQ10 ; COUNTER NOT 0
\f
;
; CALC EXPONENT, SCALE RESULT
;
POP AF ; GET ORIGINAL EXP
AND A
RRA ; DIVIDE BY TWO
RR B ; SAVE CY
ADD A,40H ; CORRECT THE BIAS
LD (IX+7),A ; STORE IT
BIT 7,B ; TEST ODD OR EVEN
RET Z ; ORIGINAL EXP EVEN
LD IY,SQR10
CALL MULT ; MPY BY SQR(10)
RET
;
; SQUARE ROOT OF NEGATIVE NUMBER
;
SQERR LD HL,ERROR
SET 3,(HL) ; FLAG ERROR
RES 7,(IX) ; MAKE POSITIVE
RET
*H EXP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; EXPONENTIATION ROUTINE
;
; INPUT: IX PTS TO X
; OUTPUT: IX PTS TO E X
; ERRORS: OVER/UNDERFLOW IN HANDLING EXPONENT PART
; ALGORITHM: X:=X*2*LOG BASE 10 OF E
; SAVE:=INT(X)
; X:=FRACTION PART(X) / 2
; X:=10 X, WHERE 0 <= X < .5
; IF SAVE IS ODD THEN X:=X*SQR(10)
; X:=X*10 INT(SAVE/2)
;
; THE APPROXIMATION TO 10 X IS GIVEN BY :
; (Q(X 2) + X*P(X 2)) / (Q(X 2) - X*P(X 2))
; WHERE Q IS 3RD ORDER POLYNOMIAL, P IS 2ND ORDER.
; REFERENCE IS "COMPUTER APPROXIMATIONS", HART, JOHN F.
; ET AL, FUNCTION NUMBER 1444
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; CONVERT E X TO 10 X
;
EXP LD IY,LOGE2 ; MULT BY 2*LOG10(E)
CALL MULT
;
; GET 8 BIT 2'S COMPL INTEGER PART IN A
;
CALL BRK ; BREAK INTEGER AND FRACTION PARTS
JP C,EXERR1 ; INTEGER PART > 16 bits
LD A,H
RLC L ; SIGN BIT IN CY
ADC A,0
JP NZ,EXERR2 ; INTEGER > 8 BITS
LD A,L
RRCA ; RESTORE 8 BIT INTEGER
PUSH AF ; SAVE IT
\f
;
; SCALE FRACTION PART TO 0 <= X < .5
;
XOR A
CP (IX+7)
JR Z,EX10 ; FRACTION IS ZERO
CALL HALF
JP C,UNDER ; UNDERFLOW
;
; EVALUATE RATIONAL APPROX. TO 10 X
;
EX10 CALL XX2 ; STORE X, X 2 IN TEMP4, 5
LD IY,PEX02
LD B,2 ; 2ND ORDER POLY
CALL POLY ; EVALUATE P(X 2)
CALL MULT4 ; CALC. X*P(X 2)
CALL STO4 ; SAVE X*P IN TEMP4
LD HL,TEMP5
CALL LD ; GET X 2
LD IY,QEX02
LD B,2 ; 3RD ORDER POLY(1)
CALL POLY1 ; EVALUATE Q(X 2)
CALL STO5 ; SAVE Q IN TEMP5
LD IY,TEMP4
CALL SUB
CALL STO6 ; SAVE Q-XP IN TEMP6
LD HL,TEMP5
CALL LD ; GET Q
LD IY,TEMP4
CALL ADD ; CALC. Q+XP
LD IY,TEMP6
CALL DIVI ; FINAL RESULT
;
; POSSIBLE SCALE BY SQR(10)
;
POP AF ; GET 8 BIT INTEGER
SRA A ; DIVIDE BY 2
PUSH AF ; SAVE INTEGER
LD IY,SQR10
CALL C,MULT ; INTEGER WAS ODD
;
; ADD INTEGER PART TO RESULT EXPONENT
;
POP BC ; PUT INTEGER IN B
LD A,(IX+7) ; GET EXP
SUB 80H ; REMOVE BIAS
ADD A,B ; ADD INTEGER PART
JP PE,EXERR3 ; OVER/UNDERFLOW
ADD A,80H ; ADD BIAS
JP Z,UNDER ; UNDERFLOW
LD (IX+7),A ; STORE EXP
RET
;
; EXP ERRORS
;
EXERR1 EX AF,AF' ; GET ORIGINAL SIGN
LD H,A
EXERR2 BIT 7,H
JP NZ,UNDER ; - SIGN
JP OVER
EXERR3 JP P,UNDER ; + SIGN AFTER OVERFLOW
JP OVER
\f
*H LOG
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; LOG ROUTINE
;
; INPUT: IX PTS TO X
; OUTPUT: IX PTS TO NATURAL LOG OF X
; ERRORS: X IS NEGATIVE, RETURN LOG(ABS(X))
; X IS ZERO, RETURN NEGATIVE OVERFLOW
; SPECIAL CASES: X IS 1, RETURN ZERO
; ALGORITHM: SAVE:=INT(X)
; X:=SQR(10)*FRACTION-PART(X)
; X:=LOG BASE E (X), WHERE 1/SQR(10) < X < SQR(10)
; X:=X - LOG BASE E(SQR(10)) + SAVE*LOG BASE E(10)
;
; LOG IS APPROXIMATED BY :
; Z*P(Z 2) / Q(Z 2) WHERE Z = (X-1) / (X+1)
; AND P IS A 3RD ORDER POLYNOMIAL, AND Q IS 4TH ORDER.
; REFERENCE FUNCTION IS 2686.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; CHECK FOR VALID ARGUMENTS
;
LOG BIT 7,(IX)
CALL NZ,LGERR1 ; NEGATIVE ARG
LD IY,C1
CALL CP
JP Z,ZERO ; LOG(1)
LD A,(IX+7) ; GET EXPONENT
OR A
JP Z,LGERR2 ; ZERO ARG
;
; TAKE LOG OF EXPONENT PART
;
SUB 80H ; REMOVE BIAS
LD L,A ; PUT IN HL
LD H,0 ; SIGN EXTEND
JR NC,LO10 ; + SIGN
LD H,0FFH
LO10 PUSH HL ; SAVE INTEGER
;
; SCALE TO 1/SQR(10) < X < SQR(10)
;
LD (IX+7),80H ; SCALE TO 0 < X < 1
LD IY,SQR10
CALL MULT
;
; APPROXIMATION FOR LOGARITHM
CALL STO4 ; SAVE X IN TEMP4
PUSH IX ; SAVE PTR
LD IX,TEMP4
LD IY,C1
CALL ADD ; X+1 IN TEMP4
POP IX
LD IY,C1
CALL SUB ; x-1 IN (IX)
LD IY,TEMP4
CALL DIVI
\f
CALL XX2 ; STORE Z,Z 2 IN TEMP4,5
LD IY,QL003
LD B,3
CALL POLY1 ; EVALUATE Q(Z 2)
CALL STO6 ; Q IN TEMP6
LD HL,TEMP5
CALL LD ; LOAD Z 2
LD IY,PL003
LD B,3
CALL POLY ; EVALUATE P(Z 2)
CALL MULT4 ; CALC. Z*P(Z 2)
LD IY,TEMP6
CALL DIVI ; CALC ZP/Q
LD IY,LNSQ10
CALL SUB ; SUB LOGE(SQR(10))
CALL STO4 ; SAVE IN TEMP4
;
; CONVERT 16 BIT EXPONENT PART TO FLOATING PT
;
POP HL ; GET INTEGER
CALL FLOAT1 ; FLOAT IT
LD IY,LN10
CALL MULT ; MPY BY LOG BASE E(10)
LD IY,TEMP4
CALL ADD ; FINAL RESULT
RET
;
; ERRORS
;
LGERR1 LD HL,ERROR
SET 2,(HL) ; FLAG LOG OF NEG
RES 7,(HL) ; TAKE ABS VALUE
RET
LGERR2 SET 7,(IX) ; SET NEGATIVE SIGN
JP OVER ; LOG OF ZERO
*H TANGENT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; TANGENT ROUTINE
;
; INPUT: IX PTS TO X (IN RADIANS)
; OUTPUT: IX PTS TO TAN(X)
; ERRORS: NONE DIRECTLY
; ALGORITHM: X := X*4/PI
; SAVE := INT(X) LAND 3 (SAVE LOW 2 BITS ONLY)
; X := FRACTION-PART(X)
; IF SAVE IS 0,2 THEN X := 1-X
; X := TAN(X*PI/4), WHERE 0 <= X <= PI/4
; IF SAVE IS 0,3 THEN X := 1/X
; IF SAVE IS 0,1 THEN X := -X
;
; THE APPROXIMATION TO TAN(X*PI/4) IS GIVEN BY:
; X*P(X 2) / Q(X 2)
; WHERE P IS ORDER 3 POLYNOMIAL, Q IS ORDER 4
; REFERENCE FUNCTION IS 4286
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
\f
;
; SCALE BY 4/PI
;
TAN LD IY,FOVRPI
CALL MULT
CALL BRK ; GET INTEGER,FRACTION
LD A,L
PUSH AF ; SAVE FLAG BITS
AND 1 ; TEST FLAG
JR Z,TA10 ; FLAG WAS 0 OR 2
LD IY,C1
CALL RSUB ; CALC. 1-FRACTION PART
;
; TAN APPROX
;
TA10 CALL XX2 ; SAVE X,X 2 IN TEMP4,5
LD IY,QTA03
LD B,3
CALL POLY1 ; EVALUATE Q(X 2)
CALL STO6 ; SAVE Q
LD HL,TEMP5
CALL LD ; GET X 2
LD IY,PTA03
LD B,3
CALL POLY ; EVALUATE P(X 2)
CALL MULT4 ; CALC. X*P(X 2)
POP AF ; GET 2 BIT FLAG
PUSH AF
AND 3
JP PE,TA20 ; FLAG WAS 0 OR 3
CALL STO4 ; SAVE X*P
LD HL,TEMP6
CALL LD ; GET Q
LD IY,TEMP4 ; SET FOR Q/XP
JP TA30
TA20 LD IY,TEMP6 ; SET FOR XP/Q
TA30 CALL DIVI
;
; CALC. SIGN OF RESULT
;
POP AF ; GET FLAG
AND 2
RET Z ; ON 0 OR 1
SET 7,(IX)
RET
*H COSINE,SINE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; COSINE ROUTINE
; EFFECTIVELY ADDS PI/2 AND CALLS SINE
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
COS LD IY,FOVRPI
CALL MULT ; SCALE BY 4/PI
CALL BRK ; GET INTEGER, FRACTION
LD A,L
ADD A,2 ; ADD EFFECTIVE PI/2
JP SI10
\f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SINE ROUTINE
;
; INPUT: IX PTS TO X (IN RADIANS)
; OUTPUT: IX PTS TO SIN(X)
; ERRORS: NONE
; ALGORITHM: X := X*4/PI
; SAVE := INT(X) LAND 7
; X := FRACTION-PART(X)
;IF SAVE IS 1,3,5,7 THEN X := 1-X
; IF SAVE IS 0,3,4,7 THEN X := SIN(X*PI/4)
; IF SAVE IS 1,2,5,6 THEN X := COS(X*PI/4)
; IF SAVE IS 4,5,6,7 THEN X := -X
;
; THE SINE APPROX FOR 0 <= X <= PI/4 IS:
; X*P(X 2) / Q(X 2)
; WHERE P IS A 3RD ORDER POLYNOMIAL, Q IS 3RD ORDER.
; REFERENCE FUNCTION IS 3063.
;
; THE COSINE APPROX IS:
; P(X 2) / Q(X 2)
; WHERE P IS A 3RD ORDER POLY, Q IS 3RD ORDER.
; REFERENCE FUNCTION IS 3843.
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SIN LD IY,FOVRPI
CALL MULT ; SCALE BY 4/PI
CALL BRK ; GET INTEGER AND FRACTION
LD A,L
SI10 PUSH AF ; SAVE 3 BIT FLAG
AND 1
JR Z,SI20 ; FLAG IS 0,2,4,6
LD IY,C1
CALL RSUB ; CALC. 1-X
SI20 POP AF ; GET FLAG
PUSH AF
AND 3
JP PO,SI30 ; 1,2,5,6
;
; SIN APPROX
;
CALL XX2 ; STORE X,X 2 IN TEMP4,5
LD IY,QSI02
LD B,2
CALL POLY1 ; EVALUATE Q(X 2)
CALL STO6 ; SAVE Q
LD HL,TEMP5
CALL LD ; GET X 2
LD IY,PSI03
LD B,3
CALL POLY ; EVALUATE P(X 2)
CALL MULT4 ; CALC. X*P(X 2)
LD IY,TEMP6
CALL DIVI ; CALC. XP/Q
JP SI40
;
; COS APPROX
;
\f
SI30 CALL XX2 ; STORE X,X 2 IN TEMP4,5
LD IY,QC002
LD B,2
CALL POLY1 ; EVALUATE Q(X 2)
CALL STO6
LD HL,TEMP5
CALL LD ; GET X 2
LD IY,PC003
LD B,3
CALL POLY ; EVALUATE P(X 2)
LD IY,TEMP6
CALL DIVI ; CALC. P/Q
;
; CALC SIGN OF RESULT
;
SI40 POP AF ; GET FLAG
AND 4
RET Z ; 0,1,2,3
SET 7,(IX)
RET
*H ARCTANGENT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; ARCTANGENT ROUTINE
;
; INPUT: IX PTS TO X
; OUTPUT: IX PTS TO ATN(X) (IN RADIANS)
; ERRORS: NONE
; ALGORITHM: SAVE := SGN(X)
; FLAG := 0
; IF TAN(3*PI/8) <= X THEN X:=1/X, FLAG:=1
; IF TAN(PI/8) <= X THEN X:=(X-1)/(X+1), FLAG:=2
; X := ATN(X) , WHERE 0 <= X <= TAN(PI/8)
; IF FLAG = 1 THEN X := X + PI/4
; IF FLAG = 2 THEN X := PI/2 - X
; X := X*SAVE
;
; APPROXIMATION FOR ATN(X) IS:
; X*P(X 2) / Q(X 2)
; WHERE P IS 3RD ORDER POLYNOMIAL, Q IS 4TH ORDER.
; REFERENCE FUNCTION IS 5075
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; TAKE ABS VALUE, DETERMINE RANGE
;
ATN LD A,(IX) ; GET SIGN
AND 80H
PUSH AF ; SAVE SIGN
RES 7,(IX) ; MAKE POSITIVE
LD IY,TAPI8
CALL CP ; COMPARE TO 1ST LIMIT
LD B,0
JR C,AT20 ; < TAN(PI/8)
LD IY,TA3PI8
CALL CP ; COMPARE TO 2ND LIMIT
JR C,AT10 ; < TAN(3*PI/8)
;
; TAN(3*PI/8) <= X
; TAKE 1/X NOW, SUB FROM PI/2 AT END
;
\f
CALL REC ; RECIPROCAL
LD B,2 ; SET FLAG TO 2
JP AT20
;
; TAN (PI/8) < = X < TAN(3*PI/8)
; CALC (X-1)/(X+1) NOW, ADD PI/4 AT END
;
AT10 CALL STO4 ; SAVE X IN TEMP4
PUSH IX
LD IX,TEMP4
LD IY,C1
CALL ADD ; X+1 IN TEMP4
POP IX
LD IY,C1
CALL SUB ; X-1 IN ACCUM
LD IY,TEMP4
CALL DIVI
LD B,1 ; SET FLAG TO 1
;
; APPROX FOR ARCTAN
;
AT20 PUSH BC ; SAVE FLAG
CALL XX2 ; SAVE X,X 2
LD IY,QAT03
LD B,3
CALL POLY1 ; CALC. Q(X 2)
CALL STO6 ; SAVE Q
LD HL,TEMP5
CALL LD ; GET X 2
LD IY,PAT03
LD B,3
CALL POLY ; CALC P(X 2)
CALL MULT4 ; X*P
LD IY,TEMP6
CALL DIVI ; X*P/Q
POP BC ; GET FLAG
BIT 0,B
JR Z,AT30 ; FLAG IS 0 OR 2
; SECOND INTERVAL (FLAG IS 1)
LD IY,PI4
CALL ADD ; ADD PI/4
JP AT40
AT30 BIT 1,B
JR Z,AT40 ; FLAG IS 0
; THIRD INTERVAL (FLAG IS 2)
LD IY,PI2
CALL RSUB ; SUB FROM PI/2
;
; GIVE RESULT SIGN OF ARGUMENT
;
AT40 POP AF ; GET SIGN
RET Z ; SIGN WAS POSITIVE
SET 7,(IX) ; MAKE NEGATIVE
RET
*H POLY
\f
;
; POLYNOMIAL EVALUATOR
;
; INPUT: IX PTS TO ACCUM
; IY PTS TO HIGHEST COEFFICIENT
; TEMP5 CONTAINS X
; B CONTAINS ORDER (ORDER-1 FOR POLY1)
; OUTPUT: IX PTS TO RESULT
; (POLY1 ASSUMES FIRST COEFF. IS 1)
;
POLY PUSH BC ; SAVE COUNTER
PUSH IY ; SAVE COEFF. PTR
JP POLY10
POLY1 PUSH BC ; SAVE COUNTER
PUSH IY ; SAVE PTR
CALL ADD
LD IY,TEMP5 ; PT TO X
POLY10 CALL MULT
POP IY
POP BC
LD DE,-8 ; ADJUST PTR
ADD IY,DE
DJNZ POLY1 ; COUNTER NOT 0
CALL ADD ; FINAL ADD
RET
;
; POLYNOMIAL UTILITIES
;
XX2 CALL STO4 ; STORE X IN TEMP4
CALL MULT4 ; CALC. X 2
CALL STO5
RET
MULT4 LD IY,TEMP4
CALL MULT
RET
*H CONSTANTS
SQR10 DEFW 1603H ; 3.1622 77660 168
DEFW 7722H
DEFW 0166H
DEFW 8168H
LNSQ10 DEFW 1501H ; 1.1512 92546 497
DEFW 9212H
DEFW 6454H
DEFW 8197H
LN10 DEFW 3002H ; 2.3025 85092 994
DEFW 8525H
DEFW 2909H
DEFW 8194H
LOGE2 DEFW 6808H ; .86858 89638 065
DEFW 8958H
DEFW 8063H
DEFW 8065H
FOVRPI DEFW 2701H ; 1.2732 39544 735
DEFW 3932H
DEFW 4754H
DEFW 8135H
TAPI8 DEFW 1404H ; .41421 35623 731
DEFW 3521H
DEFW 3762H
\f
DEFW 8031H
TA3PI8 DEFW 4102H ; 2.4142 13562 373
DEFW 1342H
DEFW 2356H
DEFW 8173H
PI4 DEFW 8507H ; .78539 81633 974
DEFW 8139H
DEFW 3963H
DEFW 8074H
PI2 DEFW 5701H ; 1.5707 96326 795
DEFW 9607H
DEFW 6732H
DEFW 8195H
PSQ00 DEFW 7101H ; .17157 28752 538
DEFW 2857H
DEFW 2575H
DEFW 8038H
PEX00 DEFW 1705H ; 5178.0 91991 516
DEFW 9180H
DEFW 1599H
DEFW 8416H
PEX01 DEFW 3108H ; 831.40 67212 937
DEFW 6740H
DEFW 2921H
DEFW 8337H
PEX02 DEFW 8301H ; 18.312 36015 928
DEFW 3612H
DEFW 5901H
DEFW 8228H
QEX00 DEFW 4904H ; 4497.6 33557 406
DEFW 3376H
DEFW 7455H
DEFW 8406H
QEX01 DEFW 7002H ; 2709.3 16940 852
DEFW 1693H
DEFW 0894H
DEFW 8452H
QEX02 DEFW 5901H ; 159.37 41523 603
DEFW 4137H
DEFW 3652H
DEFW 8303H
; QEX03 IS 1
PL000 DEFW 6502H ; 265.52 24908 516
DEFW 2452H
DEFW 8590H
DEFW 8316H
PL001 DEFW 2984H ; -429.48 34828 658
DEFW 3448H
DEFW 8682H
DEFW 8358H
PL002 DEFW 9701H ; 197.64 46297 035
DEFW 4664H
DEFW 7029H
DEFW 8335H
PL003 DEFW 2782H ; -22.764 76157 115
DEFW 7664H
DEFW 7115H
DEFW 8215H
QL000 DEFW 3201H ; 132.76 12454 159
\f
DEFW 1276H
DEFW 4245H
DEFW 8359H
QL001 DEFW 5882H ; -258.99 54899 200
DEFW 5499H
DEFW 9289H
DEFW 8300H
QL002 DEFW 5801H ; 158.60 18962 727
DEFW 1860H
DEFW 2796H
DEFW 8327H
QL003 DEFW 1483H ; -31.416 48448 282
DEFW 4816H
DEFW 8244H
DEFW 8282H
; QL004 IS 1
PTA00 DEFW 0801H ; 10888 600.43 728
DEFW 6088H
DEFW 3704H
DEFW 8828H
PTA01 DEFW 9588H ; -89588 8.4400 677
DEFW 8488H
DEFW 0640H
DEFW 8677H
PTA02 DEFW 4101H ; 14189. 85425 276
DEFW 8589H
DEFW 5242H
DEFW 8576H
PTA03 DEFW 5684H ; -45649 31943 867
DEFW 3149H
DEFW 3894H
DEFW 8267H
QTA00 DEFW 3801H ; 13863 796.66 357
DEFW 7963H
DEFW 6366H
DEFW 8857H
QTA01 DEFW 9983H ; -39913 09.518 035
DEFW 0913H
DEFW 8051H
DEFW 8735H
QTA02 DEFW 3501H ; 13538 2.7128 051
DEFW 2738H
DEFW 8012H
DEFW 8651H
QTA03 DEFW 0181H ; -1014.6 56190 253
DEFW 5646H
DEFW 0219H
DEFW 8453H
; QTA04 IS 1
PSI00 DEFW 0602H ; 20664 34.333 700
DEFW 3464H
DEFW 3733H
DEFW 8700H
PSI01 DEFW 8181H ; -18160 3.9879 741
DEFW 3960H
DEFW 9787H
DEFW 8641H
PSI02 DEFW 5903H ; 3599.9 30694 964
\f
DEFW 3099H
DEFW 4969H
DEFW 8464H
PSI03 DEFW 0182H ; -20.107 48329 459
DEFW 4807H
DEFW 9432H
DEFW 8259H
QSI00 DEFW 6302H ; 26310 65.910 265
DEFW 6510H
DEFW 0291H
DEFW 8765H
QSI01 DEFW 9203H ; 39270. 24277 465
DEFW 2470H
DEFW 7427H
DEFW 8565H
QSI02 DEFW 7802H ; 278.11 91948 108
DEFW 9111H
DEFW 8194H
DEFW 8308H
; QSI03 IS 1
PC000 DEFW 2901H ; 12905 39.465 904
DEFW 3905H
DEFW 5946H
DEFW 8704H
PC001 DEFW 7483H ; -37456 7.0391 572
DEFW 7056H
DEFW 1539H
DEFW 8672H
PC002 DEFW 3401H ; 13432. 30098 654
DEFW 3032H
DEFW 8609H
DEFW 8554H
PC003 DEFW 1281H ; -112.31 45082 334
DEFW 4531H
DEFW 2308H
DEFW 8334H
QC000 DEFW 2901H ; 12905 39.465 904
DEFW 3905H
DEFW 5946H
DEFW 8704H
QC001 DEFW 3402H ; 23467. 77310 725
DEFW 7767H
DEFW 0731H
DEFW 8525H
QC002 DEFW 0902H ; 209.69 51819 673
DEFW 5169H
DEFW 9681H
DEFW 8373H
; QC003 IS 1
PAT00 DEFW 1602H ; 216.06 23078 972
DEFW 2306H
DEFW 8907H
DEFW 8372H
PAT01 DEFW 2203H ; 322.66 20700 133
DEFW 2066H
DEFW 0170H
DEFW 8333H
PAT02 DEFW 3201H ; 132.70 23981 640
DEFW 2370H
DEFW 1698H
DEFW 8340H
\f
PAT03 DEFW 2801H ; 12.888 38303 416
DEFW 3888H
DEFW 3430H
DEFW 8216H
QAT00 DEFW 1602H ; 216.06 23078 972
DEFW 2306H
DEFW 8907H
DEFW 8372H
QAT01 DEFW 9403H ; 394.68 28393 123
DEFW 2868H
DEFW 3139H
DEFW 8323H
QAT02 DEFW 2102H ; 221.05 08830 284
DEFW 0805H
DEFW 0283H
DEFW 8384H
QAT03 DEFW 8503H ; 38.501 48650 835
DEFW 4801H
DEFW 0865H
DEFW 8235H
; QAT04 IS 1
;
; REFERENCES
;
GLOBAL POW,IPOW,SQR,EXP,LOG,TAN,COS,SIN,ATN
EXTERNAL ERROR,OVER,UNDER,ZERO,ONE,C1
EXTERNAL ADD,SUB,RSUB,MULT,DIVI,REC
EXTERNAL HALF
EXTERNAL STO4,STO5,STO6,TEMP4,TEMP5,TEMP6
EXTERNAL LD,CP,FIX,FIXA,FLOAT,FLOAT1,BRK
EXTERNAL SRB,NORMLZ
\f
******************************************
DMATH1.S
created 770919; last modified 791023
******************************************
*H DECIMAL TO BINARY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;,,,,,,,,,,,,,,,,,,,,,,
;
; DECIMAL TO BINARY CONVERSION
; INPUT: IX POINTS TO OUTPUT AREA
; OUTPUT: IX POINTS TO FL PT NUMBER
; ERRORS: NO DIGITS IN FRACTION PART
; NO DIGITS IN EXPONENT
; EXPONENT OVERFLOW
; EXPONENT UNDERFLOW
; REGISTER ASSIGNMENT IN MAIN LOOP:
; C - DECIMAL EXPONENT
; B - FLAGS: BIT 6 - DIGITS FOUND
; BIT 7 - FRACTION OVRFLW
; A - NEW DIGIT
; A' - SIGN IN BIT 7
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DTOB CALL LMARK ; MARK BEGINNING OF SCAN
CALL ZERO ; CLEAR RESULT
XOR A ; CLEAR A
LD B,A ; CLEAR FLAGS
LD C,80H+13 ; INIT EXPONENT
EX AF,AF' ; PUT AWAY SIGN
CALL LIN ; GET FIRST CHAR
CP '+'
JR Z,D10 ; SIGN IS +
CP '-'
JR NZ,D20 ; NO SIGN
EX AF,AF'
OR 80H ; FLAG NEGATIVE SIGN
EX AF,AF'
;
; LOOP TO PROCESS CHARS BEFORE DECIMAL POINT
;
D10 CALL LIN ; GET NEXT CHAR
D20 CP '.'
JR Z,D40 ; DECML PT FOUND
CALL DIGIT?
JR C,D50 ; NOT A DIGIT
SET 6,B ; FLAG DIGIT FOUND
BIT 7,B
JR NZ,D30 ; OVERFLOW
CALL CNV ; CONVERT THIS DIGIT
JP D10
D30 INC C ; INC DECML EXP
JP D10
;
; LOOP TO PROCESS CHARS AFTER DECIMAL POINT
;
D40 CALL LIN ; GET NEXT CHAR
CALL DIGIT?
JR C,D50 ; NOT A DIGIT
\f
SET 6,B ; FLAG DIGIT FOUND
BIT 7,B
JR NZ,D40 ; OVERFLOW
DEC C ; DEC DECML EXP
CALL CNV ; CONVERT THIS DIGIT
JP D40
;
; CHANGE FRACTION TO FLOATING POINT FORMAT
;
D50 BIT 6,B
JP Z,LREST ; NO DIGITS FOUND
LD (SAVE),A ; SAVE THIS CHAR
CALL NORML1
JR Z,D130 ; ZERO FRACTION PART
LD A,(SAVE) ; GET CHAR AGAIN
;
; PROCESS EXPONENT
; REGISTERS:
; B - BIT 7 IS SIGN
; BIT 6 IS DIGIT-FOUND FLAG
; BIT 5 IS DIGIT-OVERFLOW FLAG
; C - IS EXP FROM FRACTION PART
; HL - IS ACCUM FOR D-TO-B CONVERSION
;
LD HL,0 ; INITIALIZE REGISTERS
LD B,L
CP 'E'-'0'
JR NZ,D90 ; NOT AN 'E'
;
; CONVERT SIGN
;
CALL LIN
CP '+'
JR Z,D60 ; SIGN IS +
CP '-'
JR NZ,D70 ; NO SIGN
SET 7,B ; FLAG NEG SIGN
;
; CONVERT DIGITS
;
D60 CALL LIN
D70 CALL DIGIT?
JR C,D80 ; NOT A DIGIT
SET 6,B ; FLAG DIGIT FOUND
BIT 5,B
JR NZ,D100 ; OVER OR UNDERFLOW
CALL MAD ; CONVERT THIS DIGIT
LD A,H ; CHECK FOR OVERFLOW
AND A
JP Z,D60 ; HL < 256
SET 5,B ; SET FLAG
JP D60
;
; TEST FOR ILLEGAL EXPONENT PART
;
D80 BIT 6,B
JR Z,D120 ; NO DIGITS FOUND
;
; CONVERT HL ACCUM TO 2'S COMPLEMENT
;
\f
D90 BIT 7,B
JR Z,D92 ; SIGN IS +
EX DE,HL
LD HL,0
AND A
SBC HL,DE
;
; ADD PREVIOUS EXPONENT (C)
; CHECK FOR OVERFLOW
;
D92 LD B,0
AND A
ADC HL,BC ; ADD TWO EXPONENTS
JP Z,UNDER ; UNDERFLOW
LD A,H
AND A
JR NZ,D96 ; EXP < -128 OR > 127
;
; STORE SIGN AND EXPONENT
;
EX AF,AF' ; GET SIGN
OR (IX)
LD (IX),A ; STORE SIGN
LD (IX+7),L ; STORE EXP
JP RTN
;
; DETERMINE SIGN OF EXP
;
D96 BIT 7,H
JR D105
;
; FINISH SCANNING DIGITS
;
D100 CALL LIN ; FINISH SCANNING DIGITS
CALL DIGIT?
JR NC,D100 ; DIGIT IS FOUND
;
; DETERMINE FROM SIGN BIT WHETHER OVER OR UNDER
;
BIT 7,B
D105 JR NZ,D110 ; SIGN IS NEGATIVE
CALL OVER ; FLAG ERROR
JP RTN
D110 CALL UNDER ; FLAG ERROR
JP RTN
;
; ILLEGAL NUMBER
;
D120 LD HL,ERROR
SET 7,(HL)
JP RTN
;
; ZERO
;
D130 CALL ZERO
JP RTN
*EJECT
;
; SCANNER ROUTINES
;
\f
RTN CALL LBACK ; BACK UP POINTER BY 1
JP RC2 ; GO TO SPECIAL RETURN
;
; DIGIT? ROUTINE CONVERTS ASCII CHAR TO 0-9 VALUE
; RETURNS CY ON IF NOT A DIGIT
;
DIGIT? SUB '0'
RET C ; WAS < 30H
CP 10
CCF ; CY SET IF > 9
RET
;
; CNV ROUTINE TO MULTIPLY DECIMAL ACCUM 1 BY 10 AND ADD
;
CNV CALL SLD ; SHIFT A INTO ACCUM
LD A,(IX) ; GET HIGH BYTE
AND A
RET Z ; < 13 DIGITS
SET 7,B ; FLAG DIGIT OVERFLOW
RET
*H BINARY TO DECIMAL
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; BCD TO DECIMAL CONVERSION
;
; INPUT: IX PTS TO FL PT NUMBER
; HL PTS TO OUTPUT AREA
; OUTPUT: FL PT NUMBER IS MODIFIED
; OUTPUT AREA IS 19 BYTES:
; 1 SIGN (SPACE OR -)
; 13 DIGITS OF FRACTION
; 1 "E"
; 1 SIGN OF EXPONENT (+ OR -)
; 3 DIGITS OF EXPONENT (LEADING ZEROS)
; EXPONENT IS FOR DECIMAL PT AFTER FIRST DIGIT
; A IS 2'S COMPLEMENT EXPONENT (-128<=A<=126)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; CONVERT SIGN
;
BTOD BIT 7,(IX) ; TEST SIGN
LD (HL), ' ' ; DEFAULT SIGN
JR Z,BD10 ; + SIGN
LD (HL),'-' ; - SIGN
BD10 INC HL
;
; UNPACK FRACTION PART
;
EX DE,HL ; OUTPUT PTR IN DE
CALL SLD ; SHIFT OUT SIGN BYTE
LD B,13 ; COUNTER
LD A,'0'
BD20 CALL SLD ; GET A DIGIT
LD (DE),A ; OUTPUT IT
INC DE
DJNZ BD20 ; COUNTER NOT 0
;
\f
;
; CONVERT EXPONENT SIGN, GET SIGN MAGNITUDE EXP
;
EX DE,HL ; OUTPUT PTR IN HL
LD (HL),'E'
INC HL
LD (HL),'+' ; DEFAULT SIGN
LD A,(IX+7) ; GET BIASED EXP
AND A
JR Z,BD30 ; ZERO EXPON
SUB 81H ; REMOVE BIAS, DECR BY 1
JR NC,BD30 ; POSITIVE EXP
LD (HL),'-' ; - SIGN
NEG ; CALC MAGNITUDE
;
; CONVERT HUNDREDS
;
BD30 INC HL
LD (HL),'0' ; DEFAULT DIGIT
CP 100
JP C,BD40 ; EXP < 100
LD (HL),'1'
SUB 100
;
; DIVIDE BY 100
;
BD40 INC HL
LD B,2FH ; QUOTIENT COUNTER
LD C,10 ; DIVISOR
BD50 SUB C ; SUBTRACT 10
INC B ; INC QUOTIENT
JR NC,BD50 ; RESULT NOT NEGATIVE
ADD A,C ; RESTORE REMAINDER
LD (HL),B ; STORE QUOTIENT DIGIT
INC HL
OR '0'
LD (HL),A ; STORE REMAINDER DIGIT
LD A,(IX+7) ; GET EXPONENT
SUB 80H ; REMOVE BIAS
RET
*H RND
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RANDOM NUMBER GENERATOR
;
; INPUT: IX PTS TO OUTPUT/WORK AREA
; SEED CONTAINS PREVIOUS RANDOM NUMBER
; OUTPUT: IS PTS TO RANDOM NUMBER
; SEED CONTAINS NEW NUMBER
; ERRORS: NONE
; ALGORITHM: ARITHMETIC DONE MODULO 10 13
; X := 3141592653581 * X + 2718281828459
; RESULT IS DIVIDED BY 10 13, AND NORMALIZED
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; INITIALIZE REGISTERS
;
RND LD IY,CRNDA ; PT TO MPLIER
PUSH IX
\f
POP DE
LD HL,6
ADD HL,DE ; PT TO LS BYTE OF (IX)
LD (SAVE),HL ; SAVE FOR MLDIG
LD HL,SEED ; PT TO LAST NUMBER
CALL MDTL ; SAVE MULTIPLES IN TEMPO-3
CALL ZERO ; CLEAR WORK AREA
LD B,7 ; SET MULTIPLY LOOP COUNTER
JP RN20
;
; MULTIPLICATION, USING (IX) AS ACCUM, (IY) AS
; MULTIPLIER, (SEED) (SEED=IY-8) AS PRODUCT
; MULTIPLY BY 31415 92653 581 (CRNDA)
;
RN10 PUSH AF ; SAVE DIGIT SHIFTED OUT
CALL MLDIG ; MULTIPLY BY 2ND DIGIT
XOR A
CALL SRD ; SHIFT ACCUM RIGHT
RLA ; PUT DIGIT IN HIGH 4 BITS
RLA
RLA
RLA
AND OFOH
LD C,A ; SAVE UPPER DIGIT
POP AF ; GET LAST DIGIT
OR C ; COMBINE
LD (IY-1),A ; STORE IN SEED
RN20 LD C,(IY+6) ; GET NEXT 2 MPLIER DIGITS
DEC IY ; DECR PTR
CALL MLDIG ; MULTIPLY BY 1ST DIGIT
XOR A
CALL SRD ; SHIFT ACCUM RIGHT
DJNZ RN10
LD (IY-1),A ; STORE LAST DIGIT
;
; ADD 27182 81828 459 (CRNDC) TO (SEED)
;
LD B,7 ; LOOP COUNTER
LD HL,CRNDC0 ; PT TO CONSTANT
LD DE,SEED10 ; PT TO LS BYTE OF SEED
AND A ; CLEAR CY
;
; ADD LOOP
;
RN30 LD A,(DE) ; GET 2 DIGITS
ADC A,(HL) ; ADD 2 DIGITS
DAA
LD (DE),A ; STORE SUM
DEC DE
DEC HL
DJNZ RN30 ; COUNTER NOT 0
;
; SCALE AND NORMALIZE RESULT
;
INC DE ; PT TO MS BYTE
AND 0FH ; CLEAR SIGN DIGIT
LD (DE),A
EX DE,HL ; PUT PTR IN HL
CALL LD ; COPY SEED TO (IX)
LD C,80H ; SET EXPONENT
CALL NORML1 ; NORMALIZE
RET
\f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; RANDOMIZE USES REFRESH REGISTER TO MODIFY SEED
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
RANDMZ LD A,R ; GET REFRESH REGISTER
OR A
DAA ; CONVERT TO DECIMAL
LD (SEED10),A
RET
*H INT
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; INTEGER FUNCTION -- FLOOR FUNCTION
; INPUT,OUTPUT: IX POINTS TO FL PT NUMBER
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
INT XOR A
CP (IX+7)
RET Z ; X WAS ZERO
LD A,8DH
SUB (IX+7) ; # DIGITS RIGHT OF PT
RET C ; X >= 10 13
RET Z ; X >= 10 12
CP 13
JR NC,INT40 ; X < 1
LD B,A
;
; SET POINTER TO 1ST DIGIT RIGHT OF PT
;
LD A,14
SUB B ; 1+# DIGITS LEFT OF PT
LD E,A
SRL E ; # BYTES TO SKIP
LD D,0
PUSH IX ; GET PTR
POP HL
ADD HL,DE
;
; CLEAR FIRST DIGIT IF A IS ODD
;
AND 1
JR Z,INT10 ; DEC PT IS BETWEEN BYTES
LD A,(HL) ; GET BYTE WITH DEC PT
LD C,A ; SAVE RIGHT HALF
AND 0F0H ; CLEAR RIGHT HALF
LD (HL),A ; REPLACE IT
INC HL
LD A,C ; GET RIGHT HALF
AND 0FH
;
; CLEAR REMAINING BYTES, OR-ING EACH INTO A FIRST
;
INT10 SRL B ; CALC # BYTES
JR Z,INT30 ; NONE TO CLEAR
INT20 OR (HL)
LD (HL),0
INC HL
DJNZ INT20
\f
;
; POSSIBLE CORRECTION FOR NEGATIVE NUMBERS
;
INT30 BIT 7,(IX) ;
RET Z; POSITIVE
AND A
RET Z ; INPUT WAS AN INTEGER
LD IY,C1
CALL SUB ; SUBTRACT 1 TO CORRECT
RET
;
; X < 1, NONZERO: OUTPUT 0 IF +, -1 IF -
;
INT40 BIT 7,(IX)
JP Z,ZERO ; POSITIVE FRACTION
CALL ONE
SET 7,(IX) ; NEGATIVE 1
RET
*H SHORT FUNCTIONS
;
; BRK SEPARATES INTEGER AND FRACTION PARTS
;
; INPUT: IX PTS TO X
; OUTPUT: IX PTS TO FRACTIONAL PART OF X (POSITIVE)
; HL CONTAINS 2'S COMPL INTEGER PART OF X,
; LOW ORDER 16 BITS VALID IF X < 10 13
; CY SET IF INTEGER WON'T FIT IN 16 BITS
; Z SET IF EXACT INTEGER
; A' IS ORIGINAL SIGN
;
BRK LD A,(IX) ; GET SIGN
PUSH AF
CALL STO4 ; COPY X
CALL INT ; TAKE INTEGER PART
LD IY,TEMP4
CALL RSUB ; CALC. FRACTION PART
PUSH IX ; SAVE PTR
LD IX,TEMP4
CALL FIXA ; CALC. BINARY INTEGER PART
POP IX
EX AF,AF'
POP AF ; GET ORIGINAL SIGN
EX AF,AF'
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; ABSOLUTE VALUE FUNCTION
; INPUT,OUTPUT: IX POINTS TO FL PT NUMBER
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ABS RES 7,(IX) ; TURN OFF SIGN BIT
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; SIGN FUNCTION
; INPUT,OUTPUT. IX POINTS TO FL PT NUMBER
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SGN XOR A ; CLEAR A
CP (IX+7)
\f
RET Z ; ZERO INPUT IS NOP
LD A,(IX) ; GET SIGN
AND 80H
CALL ONE ; OUTPUT 1
OR (IX)
LD (IX),A ; SIGN OF INPUT
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; NEGATE FUNCTION
; INPUT,OUTPUT: IX POINTS TO FL PT NUMBER
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
NEG LD A,(IX) ; GET SIGN BIT
XOR 80H ; COMPLEMENT IT
LD (IX),A ; RESTORE
RET
*H INTEGER ADD AND SUB
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; IADD, ISUB INTEGER ADD AND SUBTRACT
;
; INPUT: IX PTS TO X
; IY PTS TO Y
; OUTPUT: IX PTS TO SUM OR DIFFERENCE
; ERRORS: OVERFLOW (POSITIVE OR NEGATIVE)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IADD CALL ASLOAD ; LOAD ARGUMENTS
ADC HL,DE
JP PO,ASSTO ; NO OVERFLOW
ASOV JP P,NINF ; OVFLW SIGN POS
JP PINF
ISUB CALL ASLOAD ; LOAD ARGUMENTS
SBC HL,DE
JP PO,ASSTO ; NO OVERFLOW
JR ASOV
;
; ASLOAD LOADS ARGS TO HL, DE, RESETS CY
;
ASLOAD LD H,(IX+1)
LD L,(IX)
LD D,(IY+1)
LD E,(IY)
AND A
RET
;
; ASSTO STORES HL AS RESULT
;
ASSTO LD (IX),L
LD (IX+1),H
RET
*H INTEGER MULTIPLY
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; IMUL INTEGER MULTIPLY
;
; INPUT: IX PTS TO X
; IY PTS TO Y
; OUTPUT: IX PTS TO PRODUCT
; ERRORS: OVERFLOW (POS OR NEG)
\f
; REGISTERS: DE IS MULTIPLICAND
; AC IS MULTIPLIER AND ACCUM EXTENSION
; HL IS ACCUM
; B IS LOOP COUNTER
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IMUL CALL MDLOAD ; LOAD ARGS
LD A,B ; X IN AC
;
; 16 BIT BY 16 BIT UNSIGNED MULTIPLY
;
LD HL,0 ; CLEAR ACCUM
LD B,16 ; SET COUNTER
RRA ; INITIALIZE CARRY
RR C
IM10 JR NC,IM20 ; MPLIER BIT IS ZERO
ADD HL,DE ; ADD MULTIPLICAND
IM20 RR H ; ROT ACC-MPLICAND INTO CY
RR L
RRA
RR C
DJNZ IM10 ; COUNTER NOT 0
;
; TEST FOR > 16 BIT PRODUCT
;
LD B,A ; PRODUCT IN BC
LD A,H
OR L
JR NZ,INF? ; OVERFLOW
;
; TEST FOR >15 BITS, AND STORE RESULTS
;
MDSTO EX AF,AF' ; GET SIGN OF RESULT
AND 80H
JR Z,MDS20 ; POS RESULT
;
; NEGATE BC
;
LD HL,0
SBC HL,BC
JR Z,MDS10 ; RESULT WAS ZERO
JP P,NINF ; NEGATIVE OVERFLOW
MDS10 LD (IX),L ; STORE RESULT
LD (IX+1),H
RET
;
; TEST FOR > 15 BITS
;
MDS20 BIT 7,B
JR NZ,PINF ; POSITIVE OVERFLOW
LD (IX),C
LD (IX+1),B
RET
;
; INF? CHECKS SIGN BIT IN A'
; PINF PRODUCES POS OVERFLOW
; NINF PRODUCES NEG OVERFLOW
;
IDVO LD HL,ERROR
SET 4,(HL) ; FLAG ERROR
\f
INF? EX AF,AF' ; GET SIGN BIT
AND 80H
JR NZ,NINF ; NEG SIGN
PINF LD (IX),0FFH ; RESULT IS 7FFFH
LD (IX+1),7FH
JR FINF
NINF LD (IX),0 ; RESULT IS 8000H
LD (IX+1),80H
FINF LD HL,ERROR
SET 6,(HL) ; FLAG ERROR
RET
*H INTEGER DIVIDE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; IDIV INTEGER DIVIDE
;
; INPUT: IX PTS TO X
; IY PTS TO Y
; OUTPUT: IX PTS TO X/Y
; ERRORS: Y IS ZERO
; ALGORITHM: NON-RESTORING DIVISION, 16 BY 15
; REGISTERS: AC IS DIVIDEND, ACCUM EXT
; DE IS DIVISOR
; HL IS ACCUM, REMAINDER AT END
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IDIV CALL MDLOAD ; LOAD ARGS
LD A,D
OR E
JR Z,IDV0 ; DIVISOR IS ZERO
LD A,B ; X IN AC
;
; 16 BIT BY 15 BIT UNSIGNED DIVIDE
;
LD HL,0 ; CLEAR ACCUM
LD B,16 ; SET COUNTER
IDV10 ; 0 <= HL < DE
RL C ; ROT ACC-RESULT LEFT
RLA
ADC HL,HL ; NO CY POSSIBLE
SBC HL,DE ; SUB DIVISOR
IDV20 CCF ; CALC RESULT BIT
JR NC,IDV50 ; ACCUM WENT NEGATIVE
IDV30 DJNZ IDV10 ; COUNTER NOT 0
JP IDV60
IDV40 ; DE <= HL < 0
RL C ; RO ACC-RESULT LEFT
RLA
ADC HL,HL
AND A ; TURN OFF CY
ADC HL,DE ; ADD DIVISOR
JR C,IDV30 ; ACCUM WENT POSITIVE
JR Z,IDV20 ; ACCUM BECAME ZERO
IDV50 DJNZ IDV40 ; COUNTER NOT 0
IDV60 RL C ; SHIFT IN LAST RESULT BIT
RLA
LD B,A ; QUOTIENT IN BC
JP MDSTO ; STORE RESULT
;
; MDLOAD LOADS X INTO BC, Y INTO DE
; TAKES ABS OF EACH, STORES XOR OF SIGNS
; IN A' \f
;
MDLOAD LD B,(IX+1) ; LOAD X
LD C,(IX)
LD A,B
AND 80H
JR Z,MDL10 ; X IS POSITIVE
;
; NEGATE X
;
LD HL,0
SBC HL,BC
LD B,H
LD C,L
;
; LOAD Y
;
MDL10 LD D,(IY+1)
LD E,(IY)
XOR D ; FORM SIGN OF RESULT
EX AF,AF' ; SAVE IT
BIT 7,D
RET Z ; Y IS POSITIVE
;
; NEGATE Y
;
LD HL,0
AND A
SBC HL,DE
EX DE,HL
RET
*H IABS AND ISGN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; IABS, INEG
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IABS BIT 7,(IX+1)
RET Z ; X IS POSITIVE
INEG LD D,(IX+1) ; LOAD X
LD E,(IX)
LD HL,0 ; NEGATE X
AND A
SBC HL,DE
JP PE,NINF ; NEG OVERFLOW
LD (IX+1),H ; STORE X
LD (IX),L
RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; ISGN
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ISGN LD A,(IX+1) ; GET SIGN
BIT 7,A
JR Z,ISG10 ; X IS NONNEG
LD (IX),0FFH ; STORE -1
LD (IX+1),0FFH
RET
ISG10 OR (IX)
RET Z ; X IS ZERO
\f
LD (IX+1),0 ; STORE +1
LD (IX),1
RET
*H ICP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; ICP INTEGER COMPARE
;
; RETURNS CY SET IF X < Y
; RETURNS Z SET IF X = Y
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ICP LD B,(IX+1) ; GET SIGN OF X
LD A,B
AND 80H ; TEST SIGN, CLEAR CY
JR NZ,ICP10 ; X IS NEG
BIT 7,(IY+1)
RET NZ ; Y IS NEG
LD A,B
CP (IY+1) ; SIGNS ARE BOTH POS
RET NZ
LD A,(IX)
CP (IY)
RET
ICP10 XOR (IY+1) ; TEST SIGN, CLEAR Z
RLA ; SIGN BIT INTO CY
RET C ; SIGNS DIFFERENT
LD A,B
CP (IY+1) ; BOTH SIGNS NEG
RET NZ
LD A,(IX)
CP (IY)
RET
;
; REFERENCES
;
EXTERNAL MULT,DIVI,ERROR,OVER,UNDER,SAVE
EXTERNAL SEED,SEED10,CRNDA,CRNDC0
EXTERNAL SRD,LD,MLDIG,MDTL
EXTERNAL ZERO,ONE,NORML1,SLD,SUB,C1,MAD
EXTERNAL STO4,TEMP4,RSUB,FIXA
EXTERNAL LMARK,LREST,LBACK,RC2,LIN
GLOBAL DTOB,BTOD
GLOBAL RND,RANDMZ,INT,BRK,ABS,SGN,NEG
GLOBAL IADD,ISUB,IMUL,IDIV,IABS,ISGN,ICP,INEG
\f
******************************************
DMATHM.S
created 770914; last modified 791023
******************************************
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; MISCELLANEOUS ROUTINES REQUIRED AS EXTERNALS FOR MATH PACKAGE
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
LMARK LD (POINT),HL ; STORE PTR FOR DTOB
RET
LREST RET ; ENTRY FOR UNSUCCESSFUL DTOB (NO DIGITS FOUND)
LBACK RET ; DUMMY ROUTINE (BACK UP PTR FOR BASIC)
RC2 RET ; NORMAL RETURN, IF SOME KIND OF NUMBER FOUND
LIN PUSH HL ; SAVE HL
LD HL,(POINT) ; GET PTR
LIN10 LD A,(HL) ; GET NEXT CHAR
INC HL ; ADVANCE PTR
CP ' '
JR Z,LIN10 ; IGNORE BLANKS
LD (POINT),HL ; SAVE PTR
POP HL ; RESTORE HL
RET
SCP RET ; STRING COMPARE
POINT DEFS 2 ; TEMP PTR STORAGE
ERROR DEFB 0 ; ERROR FLAGS FOR MATH PACKAGE
ILLNUM EQU 7 ; ILLEGAL NUMBER (DTOB)
OVRFLW EQU 6 ; OVERFLOW
UNDFLW EQU 5 ; UNDERFLOW
DVDZRO EQU 4 ; DIVISION BY ZERO
SQRNGN EQU 3 ; SQUARE ROOT OF NEGATIVE NUMBER
LOGNGN EQU 2 ; LOG OF NEGATIVE NUMBER
;
; REFERENCES
;
GLOBAL ERROR,SCP,LMARK,LREST,LBACK,RC2,LIN
\f
DVDIG LD HL,TEMP3 ; PT TO 8Y
CALL DVCP
JR C,DVD10 ; AC1 < 8Y
LD HL,TEMP30
CALL DVSUB ; 8Y <= AC1
DVD10 RL C ; COMPL RESULT BIT IN C
LD HL,TEMP2 ; PT TO 4Y
CALL DVCP
JR C,DVD20 ; AC1 < 4Y
LD HL,TEMP20
CALL DVSUB ; 4Y < AC1
DVD20 RL C ; COMPL RESULT BIT IN C
LD HL,TEMP1 ; PT TO 2Y
CALL DVCP
JR C,DVD30 ; AC1 < 2Y
LD HL,TEMP10
CALL DVSUB ; 2Y < AC1
DVD30 RL C ; COMPL RESULT BIT IN C
LD HL,TEMP0 ; PT TO Y
CALL DVCP ; COMPARE TO AC1
JR C,DVD40 ; AC1 < Y
LD HL,TEMP00
CALL DVSUB ; Y < AC1
DVD40 RL C ; COMPL RESULT BIT IN C
RET
;
; DVCP ROUTINE TO COMPARE (DE) TO AC1
; RETURNS CY SET IFF (DE) < AC1
; RETURNS Z SET IFF (DE) = AC1
; TIMING APPROX 42
;
DVCP LD DE,AC1 ; PT TO AC1
LD B,7 ; SET COUNTER
DVC10 LD A,(DE) ; GET BYTE
CP (HL)
RET NZ ; < OR >
INC HL ; INC PTRS
INC DE
DJNZ DVC10 ; COUNTER NOT 0
RET
;
; DVSUB ROUTINE TO SUBTRACT (DE) FROM AC1
; ASSUMES 14 DIGIT OPERANDS
; TIMING 376
;
DVSUB LD DE,AC10 ; PT TO ACCUM
AND A ; CLEAR CY
LD B,7
DV40 LD A,(DE)
SBC A,(HL)
DAA
LD (DE),A
DEC DE
DEC HL
DJNZ DV40
RET
;
; ROUTINE TO LOAD TEMP REGISTERS
; TIMING 2014
;
\f
MDTL LD DE,TEMP0 ; FIRST DEST
CALL MOV ; LOAD TEMP0
LD HL,TEMP0 ; PT TO SRC
RES 7,(HL) ; CLEAR SIGN BIT
LD B,3 ; SET COUNTER
;
; LOOP TO COPY TEMPN TO TEMPN+1 & SHFT LFT 1 BIT
;
MDTL1 LD A,B ; SAVE COUNTER
CALL MOV ; MOVE TO NEXT TEMP
LD B,A ; RESTORE COUNTER
AND A ; CLEAR CY
CALL SLB1 ; SHFT LEFT (HL ALREADY OK)
INC HL ; PT TO MSBYTE JUST SHIFTED
DJNZ MDTL1 ; COUNTER NOT 0
RET
;
; DETERMINE OVER OR UNDER
;
MERR JP P,UNDER ; UNDERFLOW
JP OVERA
;
; DIVISION BY ZERO ERROR
;
DIV0 LD HL,ERROR
SET 4,(HL)
JP INF
*H FIX
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; FIX CONVERTS FLOATING POINT NUMBER TO
; 16 BIT 2'S COMPLEMENT INTEGER
; (ROUNDING)
;
; INPUT: IX PTS TO FL PT NUMBER
; OUTPUT: IX PTS TO INTEGER
; ERRORS: OVERFLOW IF X > 32767 OR X < -32768
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
FIX LD IY,C _5
CALL ADD ; ADD .5
CALL FIXA ; CONVERT NUMBER
JR NC,FX10 ; NO OVERFLOW
LD HL,ERROR
SET 6,(HL) ; FLAG OVERFLOW
LD HL,7FFFH ; 32767
BIT 7,(IX)
JR Z,FX10 ; POSITIVE SIGN
LD HL,8000H ; -32768
FX10 LD (IX),L ; STORE INTEGER
LD (IX+1),H
RET
;
; MAIN CONVERSION FOR FIX
;
; RETURNS CY SET IF OVERFLOW
; RETURNS Z SET IF EXACT INTEGER
; HL IS LOW 16 BITS OF INT(X) FOR ALL X < 10 13
;
\f
\f
«eof»