sys7.1-doc-wip/Toolbox/SANE/FPBD.a
2019-07-27 22:37:48 +08:00

1275 lines
37 KiB
Plaintext

;
; File: FPBD.a
;
; Contains: Floating Point Binary-To-Decimal conversions
;
; Written by: Jerome T. Coonen
;
; Copyright: © 1982-1990 by Apple Computer, Inc., all rights reserved.
;
; This file is used in these builds: Mac32
;
; Change History (most recent first):
;
; <4> 4/30/91 dba get rid of extraneous branch causing warning
; <3> 9/17/90 BG Removed <2>. 040s are behaving more reliably now.
; <2> 7/4/90 BG Added EclipseNOPs for flakey 040s.
; <1.1> 11/11/88 CCH Fixed Header.
; <1.0> 11/9/88 CCH Adding to EASE.
; <1.0> 2/12/88 BBM Adding file for the first time into EASE…
;-----------------------------------------------------------
;-----------------------------------------------------------
; old FBD2B
;-----------------------------------------------------------
;-----------------------------------------------------------
;-----------------------------------------------------------
; 12JUL82: WRITTEN BY JEROME COONEN
; 12AUG82: TIDIED (JTC)
; 01SEP82: ENCODING OF RNDXXX CHANGED (JTC)
; 04SEP82: PASCAL ENUM TYPES USE HI-ORDER BYTE OF HOST WORD,
; SO FLOAT/FIXED, DECFORM.SGN FIELDS CHANGED TO BYTE.
; 18JAN82: NANS HAVE FORM NXXXX (JTC)
; 09JUN83: CHANGE REG CONVENTIONS TO PRESERVE A5,A6. (JTC)
; 14JAN85: MDS (JTC)
; 26MAR85: CHANGE SETTING OF QNANBIT; REMOVE CODE FROM CANONLOOP; FIX TWEAK <26MAR85>
; 01AUG85: BACK TO WORKSHOP. (JTC)
;
; DECIMAL->BINARY CONVERSION.
; INPUT: POINTER TO STRUCTURE WITH SGN, EXP, DGS -- THE
; FIRST TWO ARE WORDS, THE LAST A STRING.
; OUTPUT: POINTER TO FP CELL OF TYPE GIVEN IN OPCODE.
;
; ASSUME STARTUP REGISTER MASK:
; OPWORD -- D6.LO
; STATE PTR -- A0
; DST PTR -- A1
; SRC PTR -- A2
;
; INPUT ASSUMPTIONS:
; SIGN ALWAYS MEANINGFUL
; EXP MEANINGFUL UNLESS LEAD "DIG" IS 0,I,N
; DIGITS:
; LEAD 0 --> ZERO
; LEAD I --> INFINITY
; LEAD N --> NAN WITH HEX NIBBLES
; 1-9 --> NUMBER <= 20 DIGITS, LAST
; FOR ROUNDING
;
; FOR NOW, AN INPUT NAN IS SET TO AN INNOCUOUS QUIET
; NAN WITH CODE FROM APPLE 3 PASCAL.
;-----------------------------------------------------------
D2B:
;-----------------------------------------------------------
; FIRST ARRANGE INPUT ARGUMENTS IN REG FILE. MUST SAVE
; OPWORD IN D6 FOR STORE OF RESULT AT LAST STEP.
;-----------------------------------------------------------
BLANKS ON
STRING ASIS
SUBA.W #20,SP ; 20-BYTE STACK FRAME
MOVEA.L SP,A3 ; FRAME PTR
LEA 4(A2),A4 ; PTR TO STRING
MOVE.W 2(A2),D3 ; EXP
SWAP D6 ; SAVE OPWORD TILL LATER
;-----------------------------------------------------------
; CLEAR OUT DIGIT ACCUMULATOR AND INITIALIZE COUNTERS.
;-----------------------------------------------------------
CLR.L D4 ; DIGIT BUFFER
MOVE.L D4,D5
MOVE.L D4,D7 ; LO BYTE IS 'LOST' FLAG
MOVEQ #19,D2 ; MAX DIGIT COUNTER
MOVE.B (A4)+,D6 ; DIGIT STRING LENGTH COUNT
BEQ.S DBZSTO ; ZERO LENGTH --> 0.0
;-----------------------------------------------------------
; GET FIRST CHARACTER BUT DON'T AUTOINCREMENT.
;-----------------------------------------------------------
MOVE.B (A4),D0 ; FIRST CHAR
;-----------------------------------------------------------
; CHECK FOR 'I' -- INFINITY.
;-----------------------------------------------------------
CMPI.B #$49,D0 ; IS IT 'I'?
BEQ.S DBNFIN
;-----------------------------------------------------------
; CHECK FOR 'N', IF SO GET HEXITS FOR SIGNIFICAND. IF THERE
; ARE FEWER THAN THREE, FORCE LEAD ZEROS.
;-----------------------------------------------------------
CMPI.B #'N',D0 ; ALLOW ONLY CAPITAL N
BNE.S DBZER
MOVE.B -1(A4),D2 ; CHARACTER COUNT
ADDQ.L #1,A4 ; POINT TO FIRST HEXIT
SUBQ.B #1,D2 ; DON'T COUNT 'N'
MOVEQ #8,D0 ; ASSUME 8 DIGITS
CMPI.B #4,D2 ; OK IF AT LEAST 4
BGE.S @31
SUBQ.B #4,D0 ; FOUR 0'S AND WHAT'S THERE
ADD.B D2,D0
@31:
BSR.S @35
MOVE.L D5,D4
CLR.L D5
MOVEQ #8,D0
BSR.S @35
BRA.S @39
;-----------------------------------------------------------
; ROUTINE TO GET D0 DIGITS TO D5, UP TO COUNT IN D2
;-----------------------------------------------------------
@35:
ROL.L #4,D5 ; ALIGN BITS SO FAR
SUBQ.B #1,D2 ; DEC STRING COUNT
BMI.S @37
MOVE.B (A4)+,D1
CMPI.B #'9',D1
BLE.S @36
ADDI.B #9,D1 ; TRUE NIBBLE VALUE
@36:
ANDI.B #$0F,D1 ; NIBBLE MASK
OR.B D1,D5
@37:
SUBQ.W #1,D0
BNE.S @35
RTS
;-----------------------------------------------------------
; CLEAR IRRELEVANT LEAD BIT AND TEST FOR ANYTHING NONZERO.
;-----------------------------------------------------------
@39:
ANDI.L #$7FFFFFFF,D4
BNE.S DBNFIN
MOVEQ #nanzero,D4
SWAP D4 ; ALIGN LEAD BITS
BSET #QNANBIT,D4 ; MAKE IT QUIET <26MAR85>
DBNFIN:
MOVE.W #$7FFF,D0 ; STORE HUGE EXP
BRA.S DBSSTO
;-----------------------------------------------------------
; GET HERE IF ALL DIGITS ZERO: FORCE SIGNED 0 AND STORE
;-----------------------------------------------------------
DBZER:
CMPI.B #$30,D0 ; IS IT '0'?
BNE.S SIGDIGS
DBZSTO:
CLR.L D0
DBSSTO:
;-----------------------------------------------------------
; DECIMAL.SGN ENUM TYPE TEST USES HI BYTE ONLY
;-----------------------------------------------------------
TST.B (A2) ; CHECK OPERAND SIGN
BEQ.S @1
BSET #15,D0
@1:
BSR TOA3
BRA DBSTORE
;-----------------------------------------------------------
; PROCEDURE:
; MULTIPLY D4,5 BY 10, USING D0,1 AS BUFFER FOR (*2)
;-----------------------------------------------------------
DIG10:
ADD.L D5,D5 ; DIG * 2
ADDX.L D4,D4
MOVE.L D5,D1
MOVE.L D4,D0
ADD.L D5,D5 ; DIG * 4
ADDX.L D4,D4
ADD.L D5,D5
ADDX.L D4,D4 ; DIG * 8
ADD.L D1,D5 ; DIG * (8 + 2)
ADDX.L D0,D4
RTS
;-----------------------------------------------------------
; LOOP TO GET SIGNIFICANT DIGITS.
;-----------------------------------------------------------
SIGDIGS:
BSR.S DIG10 ; CURRENT * 10
MOVEQ #$0F,D0 ; NIBBLE MASK
AND.B (A4)+,D0 ; NEXT DIGIT
ADD.L D0,D5 ; ADD IT IN
CLR.W D0 ; TO PROPAGATE X
ADDX.L D0,D4
SUBQ.B #1,D6 ; STRING LENGTH
BEQ.S CANON ; ASSURE CANONICAL
SUBQ.B #1,D2 ; MAX DIG COUNT
BNE.S SIGDIGS
;-----------------------------------------------------------
; GET HERE WHEN MORE THAN 19 DIGITS INPUT. PLACE 20-TH INTO
; D7.LO FOR LATER ROUNDING TWITCH.
;-----------------------------------------------------------
TRAILDIG:
MOVE.B #$0F,D7 ; NIBBLE MASK
AND.B (A4),D7 ; NO AUTOINC -- LAST CHAR
BRA.S DONEDIG
;-----------------------------------------------------------
; GET HERE WHEN AT MOST 19 DIGITS INPUT. GET TO CANON
; FORM BY 'APPENDING TRAILING 0S' WHILE DECREMENTING
; POSITIVE EXPONENT. THIS TENDS TO CUT DOWN MAGNITUDE OF
; EXPONENT AND, CONSEQUENTLY, ITS ROUNDING ERROR.
; NOTE THAT ON ENTRY, MAX DIGIT COUNT MUST BE DECREMENTED,
; AND CHECKED FOR INSTANT EXIT.
; CAN STOP SHIFTING ONCE EXP IS LESS THAN 27, WHICH IS THE
; MAX EXACT CASE.
; MUST WATCH FOR OVERFLOW OF 16-BIT SIGNED EXPONENT; IF IT
; OVERFLOWS, ANY HUGE VALUE WITH CORRECT SIGN WILL DO.
;-----------------------------------------------------------
CANONTOP:
CMPI.W #27,D3 ; EXP ALREADY REASONABLE?
BLE.S DONEDIG
BSR.S DIG10 ; D4,5 TIMES 10
SUBQ.W #1,D3
; WHAT WERE THESE LINES DOING???? <26MAR85>
;BVC.S CANON ; $8000 --> $7FFF ?? <26MAR85>
;ADDQ.W #1,D3 ; IF SO RESTORE $8000 <26MAR85>
CANON:
SUBQ.W #1,D2 ; MAX DIG COUNT
BNE.S CANONTOP
;-----------------------------------------------------------
; NOW PLACE A SIGN ON THE NONZERO DIGIT FIELD IN D4,5 AND
; STUFF IT INTO THE FIRST FRAME ELEMENT FOR SCALING.
; TRICK: JUST STUFF IT WITHOUT PRENORMALIZATION SINCE IT'S
; KNOWN TO BE A NUMBER.
;-----------------------------------------------------------
DONEDIG:
MOVE.W #$403E,D0 ; BIASED 63, FOR EXP
;-----------------------------------------------------------
; DECIMAL.SGN ENUM TYPE TEST USES HI BYTE ONLY
;-----------------------------------------------------------
TST.B (A2) ; CHECK OPERAND SIGN
BEQ.S @1
BSET #15,D0
@1:
;-----------------------------------------------------------
; USE UTILITY TO SAVE EXTENDED VALUE D0.W,D4,D5 IN (A3)
;-----------------------------------------------------------
BSR.S TOA3
;-----------------------------------------------------------
; THE CORE COMPUTATION IN D2B AND B2D IS THE SAME
;-----------------------------------------------------------
BSR.S DBCORE
;-----------------------------------------------------------
; SET UP STORE TO DESTINATION FIELD USING ORIGINAL OPWORD
;-----------------------------------------------------------
DBSTORE:
SWAP D6 ; OPWORD TO D6.LO
ANDI.W #OPFOMASK,D6
ORI.W #OPEXT2,D6 ; SET TO CONVERT FROM EXT
PEA (A3) ; SRC IS CURRENT EXT'D
MOVE.L LKADR1(A6),-(SP) ; DST IS AS SAVED
MOVE.W D6,-(SP)
BSR REFP68K
ADDA.W #20,SP ; CLEAR STACK WORK AREA
BRA POP2
EJECT
;-----------------------------------------------------------
; STORE OPERAND IN D0.W,D4.L,D5.L TO (A3)
;-----------------------------------------------------------
TOA3:
MOVE.W D0,(A3)+
MOVE.L D4,(A3)+
MOVE.L D5,(A3)
SUBQ.L #6,A3
RTS
;-----------------------------------------------------------
; LUCKILY, CONVERSION IN BOTH DIRECTIONS USES THE SAME CORE
; ROUTINE. THIS CORRESPONDS TO STEPS B4-B7 OF ALGORITHM B
; AND STEPS D5 TO D8 OF ALGORITHM D OF J. COONEN'S PAPER
; (MAY 1982 DRAFT) ON CONVERSIONS. IN BOTH CASES THE LAST
; ROUND STEP IS UNIQUE TO THE PARTICULAR CONVERSION.
;-----------------------------------------------------------
DBCORE:
;-----------------------------------------------------------
; SET THE ROUNDING DIRECTION FOR THE SCALE FACTOR BASED
; ON CURRENT MODE, SIGN OF OPERAND, AND SIGN OF EXPONENT.
;-----------------------------------------------------------
MOVE.B (A0),D6 ; MODE INFO
MOVE.B d6,-(sp) ; Save old rounding mode/flags on stack.
ANDI.B #RNDMSK,D6 ; ISOLATE ROUND MODE BITS
BEQ.S @51 ; EASY IF ZERO (NEAREST)
MOVEQ #RNDDN,D1 ; ASSUME TOWARD -INF
TST.B (A3) ; SIGN OF OPERAND
BPL.S @30
CMPI.B #RNDDN,D6 ; NEG AND #RNDDN
BEQ.S @37
BRA.S @40
@51:
MOVE.B d6,(a0) ; Round to nearest - clear flags.
BRA.S @50
@30:
CMPI.B #RNDUP,D6 ; POS AND #RNDUP
BNE.S @40
@37:
EORI.B #RNDMSK,D1 ; SET TO TOWARD +INF
@40:
TST.W D3 ; IS EXP < 0?
BPL.S @43
EORI.B #RNDMSK,D1 ; FLIP +INF <-> -INF
@43:
MOVE.B D1,(A0) ; STUFF NEW MODES and clear flags.
@50:
;-----------------------------------------------------------
; COMPUTE 10^ABS(D3.W) IN 10(A3).
;-----------------------------------------------------------
LEA 10(A3),A1 ; ADRS FOR POW10
BSR POW10
;-----------------------------------------------------------
; FORCE ROUNDING TOWARD 0.
;-----------------------------------------------------------
ORI.B #RND0,(A0)
;-----------------------------------------------------------
; SET UP CALL TO MUL/DIV TO DO SCALING.
;-----------------------------------------------------------
PEA 10(A3) ; SRC IS SCALE FACTOR
PEA (A3) ; DST IS NUM
MOVEQ #OPMUL,D0
TST.W D3 ; SCALE NEG?
BPL.S @5
MOVEQ #OPDIV,D0
@5:
MOVE.W D0,-(SP)
BSR REFP68K
;-----------------------------------------------------------
; LOGICALLY OR THE LOST INFO INTO TRAILING BITS OF EXT'D
; VALUE (A3). BE SURE D7.B IS SET TO ZERO IN B->D CONVERT
; WHERE IT ISN'T USED.
;-----------------------------------------------------------
BTST #ERRX,(A0) ; RND ERROR IN power of ten, multiply, or DIVIDE?
SNE D0
TST.B D7 ; LOST DIGITS?
SNE D7
OR.B D7,D0
MOVE.B (a0),d1 ; d1 gets new modes and flags.
ANDI.B #$1f,d1 ; d1 gets new flags.
OR.B (sp)+,d1 ; d1 gets old modes + old flags + new flags.
MOVE.B d1,(a0) ; Store old modes + old flags + new flags.
NEG.B D0 ; 0 OR 1
BEQ.S dbcorereturn ; Status of D0 was set on exit.
; Branch if exact.
BSET #errx,(a0) ; Set inexact for lost digits in case we missed it.
TST.B d6 ; Round bits conveniently in D6.b.
BEQ.S jam1lsb ; Round Nearest - hopeless.
; nothing better than Jam 1.
CMPI.B #rnd0,d6
BEQ.S dbcorereturn ; Round Zero - ignore extra info - don't jam.
; Directed roundings - add lsb hard way.
; Add one half in least significant bit.
MOVE.L #1,-(SP) ; LOW 32 SIG BITS <26MAR85>
CLR.L -(SP) ; HIGHT 32 SIG BITS <26MAR85>
MOVE.W (A3),-(SP) ; SIGN/EXPONENT <26MAR85>
SUBQ.W #1,(SP) ; DECREMENT SIGN/EXP, BUT WATCH FOR... <26MAR85>
BCS.S MINEXP ; 0000 -> FFFF SETS CARRY <26MAR85>
BVC.S NOTMINEXP ; 8000 -> 7FFF SETS OVERFLOW <26MAR85>
MINEXP ; <26MAR85>
ADDQ.W #1,(SP) ; RESTORE MIN EXP WITH PROPER SIGN <26MAR85>
NOTMINEXP ; <26MAR85>
PEA (SP) ; ADDRESS OF HALF-ULP <26MAR85>
PEA (A3) ; ADDRESS OF CONVERTEE <26MAR85>
MOVE.W #FOADD,-(SP) ; ADD OPCODE <26MAR85>
BSR REFP68K ; GO DO IT! <26MAR85>
ADDA.W #10,SP ; REMOVE HALF-ULP OPERAND <26MAR85>
BRA.S DBCORERETURN ; AND EXIT <26MAR85>
jam1lsb ; FORCE A ONE BIT IN FINITE CONVERTEES <26MAR85>
MOVE.W (A3),D0 ; GET SIGN/EXP, WATCH FOR 7FFF AND FFFF <26MAR85>
ADDQ.W #1,D0 ; WATCH FOR 8000 AND 0000 <26MAR85>
ADD.W D0,D0 ; WATCH FOR 0000! <26MAR85>
BEQ.S DBCORERETURN ; SKIP MAX EXP <26MAR85>
BSET #0,9(A3) ; SET THE LSB AND FALL THROUGH <26MAR85>
dbcorereturn
RTS
;-----------------------------------------------------------
;-----------------------------------------------------------
; old FBPTEN
;-----------------------------------------------------------
;-----------------------------------------------------------
;-----------------------------------------------------------
; 25JUL82: BUILT FROM COMPACT VERSION OF PTEN.
; 14AUG82: TABLE CUT DOWN TO 0-14 FROM 0-28 (JTC).
; 30AUG82: HI ENTRIES MODIFIED TO GET 10^206, ACCURATE (JTC)
; 13OCT82: ASSURE PROPERLY DIRECTED RESULTS (JTC).
; 30DEC82: CLEAN UP DIRECTED ROUNDINGS (JTC).
; 15APR84: ADDED INEXACT FEATURE A LA HOUGH (JTC).
; 14JAN85: MDS (JTC)
;
; COMPUTE POWER OF TEN INTO SLOT ADDRESSED BY (A1).
; POWER IS ABSOLUTE VALUE OF D3.
; ALLOWED TO CHANGE D0-D2 AND A2.
; QUICK VERSION USES PUFFY TABLE OF POWERS OF TEN TO
; AVOID MULTIPLIES AT TAIL END.
;-----------------------------------------------------------
TAB10SZ EQU 9
;-----------------------------------------------------------
; TABLE ENTRIES ARE 7 WORDS LONG:
; 1 -- N, WHERE TABLE VALUE IS 10^N
; 2 -- ROUNDING ERROR, +1 IF ROUNDED UP, -1 IF DOWN
; 3-7 -- EXTENDED VALUE
;-----------------------------------------------------------
TAB10:
DC.W 14
DC.W 0
DC.W $402D
DC.W $B5E6
DC.W $20F4
DC.W $8000
DC.W $0000
DC.W 27
DC.W 0
DC.W $4058
DC.W $CECB
DC.W $8F27
DC.W $F420
DC.W $0F3A
DC.W 55
DC.W 1
DC.W $40B5
DC.W $D0CF
DC.W $4B50
DC.W $CFE2
DC.W $0766
DC.W 108
DC.W 1
DC.W $4165
DC.W $DA01
DC.W $EE64
DC.W $1A70
DC.W $8DEA
DC.W 206
DC.W -1
DC.W $42AB
DC.W $9F79
DC.W $A169
DC.W $BD20
DC.W $3E41
DC.W 412
DC.W 1
DC.W $4557
DC.W $C6B0
DC.W $A096
DC.W $A952
DC.W $02BE
DC.W 824
DC.W 1
DC.W $4AB0
DC.W $9A35
DC.W $B246
DC.W $41D0
DC.W $5953
DC.W 1648
DC.W 1
DC.W $5561
DC.W $B9C9
DC.W $4B7F
DC.W $A8D7
DC.W $6515
;-----------------------------------------------------------;
; TABLE IS ACCESSED FROM HIGH EXPONENTS TO LOW. IT IS
; ADDRESSED FROM BOTTOM UP FOR HISTORICAL REASONS.
;-----------------------------------------------------------
TAB10E:
DC.W 3296
DC.W 1
DC.W $6AC4
DC.W $86D4
DC.W $8D66
DC.W $26C2
DC.W $7EEC
;-----------------------------------------------------------
; START CODE. TWO SPECIAL CASES:
; EXP < 15 -- JUST PULL VALUE FROM TABLE BELOW.
; EXP > 5000 -- OUTRAGEOUS VALUES ARE SET TO 5000.
;-----------------------------------------------------------
POW10:
MOVEQ #TAB10SZ,D1 ; NOTE D1.HI IS 0
MOVE.W D3,D0 ; GET SIGNED EXP,
BPL.S @1 ; THEN ITS ABSOLUTE VALUE
NEG.W D0
@1:
CMPI.W #15,D0 ; EASY CASE WHEN < 15
BCS.S PTQUICK
CMPI.W #5000,D0 ; EXP BIGGER THAN 5000?
BCS.S @10
MOVE.W #5000,D0 ; FORCE OVERFLOW
;-----------------------------------------------------------
; LOOP THROUGH TABLE FROM HI VALS TO LO, ACCUMULATING
; POWERS OF TEN.
;-----------------------------------------------------------
@10:
IF PCOK THEN ; GET TABLE ADDRESS
LEA TAB10E(PC),A2
ELSE
LEA TAB10E,A2
ENDIF
PTLOOP:
CMP.W (A2),D0 ; TABLE EXP VS. EXP
BCS.S PTSKIP ; CARRY -> D0 < (A2)
;-----------------------------------------------------------
; WHEN EXPONENT EXCEEDS CURRENT TABLE ENTRY, DECREMENT THE
; EXPONENT AND MULTILY/STORE BY THE POWER OF TEN.
; IF THE POWER MUST BE FIXED, A COPY IS MADE ON THE STACK.
; RECALL THAN #RNDUP=01B, #RNDDN=10B, #RND0=11B.
;
; NOTE: IF AN INEXACT POWER OF TEN IS USED HERE, THE INEXACT
; EXCEPTION BIT IS ARBITRARILY FORCED ON, REGARDLESS OF THE
; CORRESPONDING HALT BIT. THIS IS THE ONLY KNOWN OCCURRENCE
; OF THIS IN ALL OF FP68K/ELEMS68K. THE PROBLEM IS THAT IT
; IS IMPOSSIBLE TO CALL THE CUSTOM ROUTINE SETEXCEPTION FROM
; WITHIN THE PACKAGE ITSELF. PITY.
;-----------------------------------------------------------
SUB.W (A2)+,D0 ; DEC EXP AND SET A2 TO ERR
TST.W (a2) ; CHECK INEXACT INFO
BEQ.S @31 ; OK IF EXACT
BSET #ERRX,(a0) ; BLAST INEXACT BIT IF INEXACT
BTST #RNDHI,(A0) ; NONZERO --> RNDDN OR RND0
BEQ.S @13
TST.W (A2) ; (A2) <= 0 --> ERROR OK
BLE.S @31
BRA.S @15
@13:
BTST #RNDLO,(A0) ; NONZERO --> RNDUP
BEQ.S @31
TST.W (A2)
BGE.S @31 ; (A2) >= 0 --> ERROR OK
;-----------------------------------------------------------
; IF MUST ADJUST VALUE, COPY IT TO STACK FIRST, BEING SURE
; TO SAVE A2 POINTER FOR LATER RESTORATION.
; FIXES: ERROR=1 --> SUBTRACT 1 FROM LSB. ERROR=-1 --> ADD.
; VALUES ARE SUCH THAT NO CARRY PROPAGATION HAPPENS.
;
; TRICKY USE OF A2: WHEN LEAST SIGNIFICANT WORD IS ACCESSED,
; A2 POINTS TO ERROR WORD; THEN WHEN ERROR WORD IS TESTED,
; A2 IS INCREMENTED TO SIGN/EXP WORD.
;-----------------------------------------------------------
@15:
MOVE.L A2,-(SP) ; SAVE POINTER TO ERROR
MOVE.W 10(A2),-(SP) ; LOW SIGNIFICANT WORD
TST.W (A2)+ ; NOTE CHANGE IN A2
BPL.S @21 ; IF ERROR=1, SUBTRACT
ADDQ.W #1,(SP) ; FORCE OPPOSITE ROUNDING
BRA.S @23
@21:
SUBQ.W #1,(SP)
@23:
MOVE.L 4(A2),-(SP) ; MIDDLE 32 SIG BITS
MOVE.L (A2),-(SP) ; EXP AND HI 16 SIG BITS
MOVEA.L SP,A2 ; POINT TO FIXED VALUE
BSR.S PTMUL
ADDQ.L #8,SP ; KILL FIXED VALUE
ADDQ.L #2,SP
MOVEA.L (SP)+,A2 ; RESTORE POINTER TO ERR
ADDQ.L #2,A2 ; POINT TO NUMBER
BRA.S @33
;-----------------------------------------------------------
;-----------------------------------------------------------
@31:
ADDQ.L #2,A2 ; SKIP OVER ERROR
BSR.S PTMUL
@33:
SUBQ.L #4,A2 ; POINT TO TABLE ENTRY
;-----------------------------------------------------------
; NEXT TABLE ENTRY IS 7 WORDS (14 BYTES) UP.
;-----------------------------------------------------------
PTSKIP:
SUBA.W #14,A2 ; SKIP TO NEXT TABLE ENTRY
SUBQ.W #1,D1 ; DECREMENT NUM COUNTER
BNE.S PTLOOP ; ZERO WHEN FINISHED
;-----------------------------------------------------------
; NOW HAVE EXP <= 14. IF D1<0 THEN MUST MULTIPLY IN, ELSE
; JUST MOVE IT FROM TABLE.
;-----------------------------------------------------------
PTQUICK:
MULU #10,D0 ; POWER * 10
IF PCOK THEN
LEA TAB10S(PC,D0),A2
ELSE
LEA TAB10S(D0),A2
ENDIF
;-----------------------------------------------------------
; NOTE THIS IS SEQUENCE IS USED AS ROUTINE BY TABLE CODE
; AT START AND IS FALLEN INTO FROM JUST ABOVE.
; TRICK WITH HIGH BIT OF D1: 0 IMPLIES FIRST PASS THROUGH
; MULTIPLY CODE, SO JUST LOAD VALUE, RATHER THAN MULTIPLY
;-----------------------------------------------------------
PTMUL:
TST.L D1 ; PLUS MEANS MUST NOT MULT
BPL.S @42
PEA (A2)
PEA (A1)
MOVE.W #OPMUL,-(SP)
BSR REFP68K
RTS
@42:
MOVE.W (A2)+,(A1)+
MOVE.L (A2)+,(A1)+
MOVE.L (A2),(A1)
SUBQ.L #6,A1
SUBQ.L #6,A2
BSET #31,D1 ; MARK FOR LATER MULTS
RTS
;-----------------------------------------------------------
;-----------------------------------------------------------
TAB10S:
DC.W $3FFF ; 10 ^ 0
DC.W $8000
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $4002 ; 10 ^ 1
DC.W $A000
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $4005 ; 10 ^ 2
DC.W $C800
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $4008 ; 10 ^ 3
DC.W $FA00
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $400C ; 10 ^ 4
DC.W $9C40
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $400F ; 10 ^ 5
DC.W $C350
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $4012 ; 10 ^ 6
DC.W $F424
DC.W $0000
DC.W $0000
DC.W $0000
DC.W $4016 ; 10 ^ 7
DC.W $9896
DC.W $8000
DC.W $0000
DC.W $0000
DC.W $4019 ; 10 ^ 8
DC.W $BEBC
DC.W $2000
DC.W $0000
DC.W $0000
DC.W $401C ; 10 ^ 9
DC.W $EE6B
DC.W $2800
DC.W $0000
DC.W $0000
DC.W $4020 ; 10 ^ 10
DC.W $9502
DC.W $F900
DC.W $0000
DC.W $0000
DC.W $4023 ; 10 ^ 11
DC.W $BA43
DC.W $B740
DC.W $0000
DC.W $0000
DC.W $4026 ; 10 ^ 12
DC.W $E8D4
DC.W $A510
DC.W $0000
DC.W $0000
DC.W $402A ; 10 ^ 13
DC.W $9184
DC.W $E72A
DC.W $0000
DC.W $0000
DC.W $402D ; 10 ^ 14
DC.W $B5E6
DC.W $20F4
DC.W $8000
DC.W $0000
;-----------------------------------------------------------
;-----------------------------------------------------------
; old FBB2D
;-----------------------------------------------------------
;-----------------------------------------------------------
;-----------------------------------------------------------
; 06AUG82: WRITTEN BY JEROME COONEN
; 12AUG82: TIDIED (JTC)
; 04SEP82: PASCAL ENUM TYPES KEPT IN HI BYTE OF WORD, SO
; CHANGES REQUIRED TO DECFORM.STYLE AND DECIMAL.SGN
; 30DEC82: ADD TEST FOR SCALED RESULT AGAINST 10^N-1 JTC.
; 18JAN83: PRINT ALL HEX DIGITS OF NANS.
; 09JUN83: CHANGE REG CONVENTIONS TO PRESERVE A5,A6 (JTC).
; 11JAN85: MDS (JTC).
;
; BINARY->DECIMAL CONVERSION. BASED ON ALGORITHM B OF
; J. COONEN'S PAPER "ACCURATE, YET ECONOMICAL BINARY-
; DECIMAL CONVERSIONS".
;
; INPUT: POINTERS TO
; DESTINATION: DECIMAL STRUCTURE WITH SGN, EXP, DIGS
; SOURCE: BINARY FLOATING-POINT NUMBER IN FORMAT
; ENCODED IN INSTRUCTION
; FORMAT: STRUCTURE WITH TYPE KEY AND COUNT DIGITS
; KEY: 0 - FLOAT, 1 - FIXED, 2 - NICE
;
; ASSUME ODDBALL REGISTER MASK AT START:
; OPWORD -- D6.LO
; STATE PTR -- A0
; DST PTR -- A1
; SRC PTR -- A2
;
; DELIVERS ONE-CHARACTER DIGIT STRING IN CASE OF
; ZERO (0), INF (I), NAN (N), OR FIXED-PT OFLOW (?).
;
; DEPENDS ON RETURN CODES FROM UNPACK ROUTINE.
;-----------------------------------------------------------
B2D:
;-----------------------------------------------------------
; UNPACK INPUT VALUE TO D6.B, A4.W, D4, D5 IN ORDER TO
; CATCH SPECIAL CASES
;-----------------------------------------------------------
MOVE.W D6,D0 ; OPWORD
ROL.W #6,D0 ; ALIGN INPUT FORMAT FIELD
CLR.L D2 ; IF-NAN FLAG
MOVE.L D2,D3 ; NUMBER-CASE FLAG
MOVE.L D2,D6 ; SIGN AND ERROR FIELD
MOVE.L D2,D7 ; ROUNDING INFO
MOVEA.L A2,A3 ; SET UP SRC ADRS
BSR UNPACK
;-----------------------------------------------------------
; NOW GET FORMAT OPERAND AND SET UP 30-BYTE (3 EXTENDEDS)
; STACK FRAME.
;-----------------------------------------------------------
MOVE.W A4,D0 ; EXPONENT
MOVEA.L LKADR3(A6),A4 ; FORMAT POINTER
SUBA.W #30,SP
MOVEA.L SP,A3 ; FRAME POINTER
;-----------------------------------------------------------
; CAN PLACE SIGN REGARDLESS OF NUMERICAL VALUE.
; THEN PLACE COUNT OF 1 IN STRING LENGTH FIELD -- DEFAULT.
;-----------------------------------------------------------
ROL.B #1,D6 ; LEAVE SIGN IN BIT #0
;-----------------------------------------------------------
; ENUM TYPE: DELIVER DECIMAL.SGN TO HI BYTE. SET DEFAULT
; STRING LENGTH TO 1, USEFUL JUST BELOW AND LATER WHEN
; SCALED FIXED-PT RESULT OVERFLOWS TO '?'.
;-----------------------------------------------------------
MOVE.B D6,(A1) ; DELIVER SIGN
MOVE.B #1,4(A1) ; LENGTH TO 1
;-----------------------------------------------------------
; NOW PICK OUT NAN, INF, ZERO CASES...
;-----------------------------------------------------------
TST.W D2 ; IF-NAN
BEQ.S @10
;-----------------------------------------------------------
; PUT NXXXX... FOR 16 HEXITS OF A NAN, REGARDLESS OF FORMAT
; SINCE TRAILING ZEROS WILL BE STRIPPED LATER. NOTE THAT
; NAN STRUCT IS 22 BYTES LONG: 2 WORDS FOR SIGN AND EXP,
; AND 18 BYTES FOR LENGTH, N, AND 16 HEXITS.
;-----------------------------------------------------------
ADDQ.L #4,A1 ; POINT TO RESULT STRING
MOVE.B #17,(A1)+ ; LENGTH = N PLUS 2 SETS OF 8
MOVE.B #'N',(A1)+ ; FIRST CHAR
BSR.S @31 ; FIRST 8 HEXITS FROM D4
MOVE.L D5,D4 ; MOVE LOW 8 HEXITS
BSR.S @31 ; AND CONVERT
SUBA.W #22,A1 ; POINT TO HEAD OF STRUCT
BRA BDFIN
;-----------------------------------------------------------
; ROUTINE TO DISPLAY D4 IN 0-9, A-F.
;-----------------------------------------------------------
@31:
MOVEQ #8,D0 ; LOOP COUNT
@33:
ROL.L #4,D4 ; PRINT FROM HI TO LO
MOVEQ #$0F,D1 ; NIBBLE MASK
AND.B D4,D1 ; STRIP NIBBLE
OR.B #'0',D1 ; '0' IS $30
CMPI.B #'9',D1 ; HEX LETTER?
BLE.S @35
ADDQ.B #7,D1 ; TRANSLATE TO A-F
@35:
MOVE.B D1,(A1)+ ; STUFF CHARACTER
SUBQ.W #1,D0
BNE.S @33
RTS
;-----------------------------------------------------------
; CHECK FOR 0, INF, OR (GASP) AN HONEST NUMBER.
;-----------------------------------------------------------
@10:
TST.W D3 ; IF-SPECIAL-NUMBER
BEQ.S BD1 ; 0 --> FINITE, NONZERO
MOVEQ #'0',D0 ; ASSUME IT'S ZERO
CMPI.W #2,D3 ; 2 --> ZERO
BEQ.S @16
MOVEQ #'I',D0
@16:
MOVE.B D0,5(A1) ; SAVE 1-CHAR FIELD
BRA BDFIN ; GO TO END OF CONVERSION
;-----------------------------------------------------------
; NEED NORMALIZED FORM OF NUMBER (EVEN WHEN VALUE IS
; EXTENDED DENORMALIZED) IN ORDER TO COMPUTE
; FLOOR( LOG10 ( | X | ) ).
; AS EXPLAINED IN THE B-D PAPER, WE CAN APPROXIMATE
; LOG2 ( | X | ) BY EXP.FRAC .
; SO WE PUT THIS INFORMATION TOGETHER BEFORE STORING THE
; SIGNED EXTENDED VALUE AT THE TOP OF THE STACK FRAME (A3).
; FOR CONVENIENCE, THIS INFORMATION IS KEPT EVEN IN THE
; CASE OF FIXED CONVERSIONS, IN WHICH IT IS IRRELEVENT.
;-----------------------------------------------------------
BD1:
MOVE.L D4,D1 ; INTEGER-BIT.FRAC
MOVE.W D0,D1 ; EXP IN LOW WORD
SUBI.W #$3FFF,D1 ; UNBIAS EXP
SWAP D1 ; ALIGN EXP AND INT.FRAC
ADD.W D1,D1 ; FINALLY HAVE EXP.FRAC
;-----------------------------------------------------------
; DENORMALIZE IF NECESSARY TO RETURN TO EXTENDED FORMAT
; AND STORE IN FRAME.
;-----------------------------------------------------------
TST.W D0 ; NEGATIVE EXP?
BPL.S @7
@3:
LSR.L #1,D4 ; SHIFT DIGITS RIGHT 1 BIT
ROXR.L #1,D5
ADDQ.W #1,D0 ; INCREMENT EXP, TOWARD 0
BMI.S @3
@7:
ROR.W #1,D6 ; PUT SIGN INTO HI BIT
OR.W D6,D0 ; PLACE ABOVE EXP
;-----------------------------------------------------------
; USE UTILITY TO PLACE NUMBER IN FRAME
;-----------------------------------------------------------
BSR TOA3
;-----------------------------------------------------------
; CLEAR OUT D4 FOR LOGX AND BYPASS MULTIPLY IF FIXED CVT.
;-----------------------------------------------------------
CLR.L D4
;-----------------------------------------------------------
; DECFORM.STYLE ENUM TYPE TEST
;-----------------------------------------------------------
TST.B (A4) ; NONZERO --> FIXED
BNE.S BD3
MOVE.L #$4D104D42,D0 ; FLOOR( LOG10 (2) )
TST.L D1 ; EXP NEGATIVE?
BPL.S @1
ADDQ.W #1,D0 ; BUMP LOG TO ASSURE FLOOR
@1:
;-----------------------------------------------------------
; COMPUTE LOG10(2) * LOG2(X) INTO D4.W. THIS IS A 32*32
; SIGNED MULTIPLY SO CANNOT USE CORE ROUTINE OF THE MULT
; OPERATION. SINCE ONLY THE LEADING 16 BITS ARE OF
; INTEREST, IT IS NOT NECESSARY TO CARRY OUT THE LOW ORDER
; 16*16 PARTIAL PRODUCT. THE SCHEME IS:
;
; A B = D0 = FLOOR( LOG10 (2) ) > 0
; * X Y = D1 = FLOOR( LOG2 |X| )
; -------
; A--Y
; B--X
; + A--X
; ------------
; ???????? = D4.W, KEEPING ONLY 16 BITS
;-----------------------------------------------------------
MOVE.L D0,D4
SWAP D4 ; D4.W = A
MULU D1,D4 ; D4.L = A--Y
CLR.W D4
SWAP D4 ; D4.W = A--Y.HI
SWAP D1 ; D1.W = X
MOVE.W D1,D5
MULS D0,D5 ; D5.L = B--X
SWAP D5
EXT.L D5 ; D5.W = B--X.HI WITH SIGN
ADD.L D5,D4 ; CANNOT CARRY OR BORROW
SWAP D0 ; D0.W = A
MULS D1,D0 ; D0.L = A--X
ADD.L D0,D4
SWAP D4 ; D4.W = FLOOR(LOG10(X))
;-----------------------------------------------------------
; ADD 1 TO D4.W YIELDING THE NUMBER OF DIGITS LEFT OF THE
; DECIMAL POINT WHEN X IS WRITTEN OUT, A HANDY VALUE.
;-----------------------------------------------------------
ADDQ.W #1,D4
;-----------------------------------------------------------
; COMPUTE THE VALUE SCALE WHICH HAS BEEN COOKED SO THE
; COMPUTATION IS INDEPENDENT OF WHETHER FIXED OR FLOAT.
; ITS NEGATIVE IS THE TENTATIVE DECIMAL EXP.
; NOTE MUST LOAD OPERAND ADDRESS SINCE MAY LOOP BACK TO BD3.
; THAT IS DONE ABOVE BDGETCNT BELOW.
;-----------------------------------------------------------
BD3:
BSR BDGETCNT
SUB.W D4,D3 ; D4 = 0 OR LOG10(X)
MOVEA.L LKADR1(A6),A1 ; RESULT ADDRESS
MOVE.W D3,2(A1) ; DELIVER EXPONENT...
NEG.W 2(A1) ; ...WITH CORRECT SIGN
;-----------------------------------------------------------
; SAVE X IN CASE ROUNDING ERROR IN LOG10(X) FORCES
; RECOMPUTATION (JUST FALLS THROUGH FOR FIXED CONVERSIONS).
;-----------------------------------------------------------
MOVE.W (A3),20(A3)
MOVE.L 2(A3),22(A3)
MOVE.L 6(A3),26(A3)
;-----------------------------------------------------------
; COMPUTE SCALED VALUE (STEPS B4-B7) USING COMMON CORE.
;-----------------------------------------------------------
BSR DBCORE
;-----------------------------------------------------------
; ROUND RESULT TO INTEGER ACCORDING TO INPUT MODE.
;-----------------------------------------------------------
PEA (A3) ; ADRS OF NUM BUFFER
MOVE.W #OPRINT,-(SP) ; ROUND TO INTEGER OPCODE
BSR REFP68K
;-----------------------------------------------------------
; COMPUTE 10^N TO CHECK WHETHER FIXED OVERFLOW (RESULT = ?)
; OR ROUND ERROR IN FLOOR( LOG10 (X) ) .
; NOTE THAT POW10 PRESERVES A1 ACROSS CALL, SO A1 MAY BE
; USED IN SUBSEQUENT ACCESSES.
;-----------------------------------------------------------
LEA 10(A3),A1 ; PUT 10^N ABOVE SCALED VAL
;-----------------------------------------------------------
; ENUM TYPE DECFORM.STYLE IN HI BYTE OF WORD.
; IF FLOAT, CHECK AGAINST REQUESTED NUMBER OF SIG DIGITS.
; IF FIXED, CHECK AGAINST MAX OF 19.
;-----------------------------------------------------------
TST.B (A4) ; FLOAT OR FIXED?
BNE.S @3
BSR.S BDGETCNT
BRA.S @5
@3:
MOVEQ #19,D3
@5:
BSR POW10
;-----------------------------------------------------------
; NOW PERFORM COMPARISON RIGHT ON MEMORY OPERANDS, WHICH
; MAKES SENSE SINCE BOTH VALUES ARE NORMALIZED. NOTE THAT
; THE SCALED VALUE IS SIGNED.
;-----------------------------------------------------------
MOVE.W (A3),D0 ; SIGN, EXP OF SCALED VAL
BCLR #15,D0 ; ABSOLUTE VALUE
CMP.W (A1),D0 ; (SCALED) - (10^N)
BNE.S @13
MOVE.L 2(A3),D0 ; HIGH ORDER DIGITS
CMP.L 2(A1),D0
BNE.S @13
MOVE.L 6(A3),D0
CMP.L 6(A1),D0
@13:
BCS.S BD85 ; LESS THAN --> OK
;-----------------------------------------------------------
; IF SCALED VALUE OUT OF RANGE DISTINGUISH CASES:
; FLOAT: JUST FIX LOG10 AND RECOMPUTE (EVEN IF EXACTLY 10^N)
; FIXED: STORE '?' AND GIVE UP.
;-----------------------------------------------------------
;-----------------------------------------------------------
; ENUM TYPE DECFORM.STYLE IS IN HI BYTE
;-----------------------------------------------------------
TST.B (A4) ; FLOAT OR FIXED
BNE.S @15
ADDQ.W #1,D4 ; FIX LOG10(X)
MOVE.W 20(A3),(A3) ; RESTORE SAVED VALUE
MOVE.L 22(A3),2(A3)
MOVE.L 26(A3),6(A3)
BRA.S BD3
@15:
MOVEA.L LKADR1(A6),A1
MOVE.B #'?',5(A1) ; STORE 1-CHAR STRING
BRA BDFIN
;-----------------------------------------------------------
; IF TYPE OF CONVERSION IS FLOAT, THEN DELIVER DIGIT COUNT,
; FORCED TO BE BETWEEN 1 AND 19.
; IF TYPE IS FIXED, THEN DELIVER STATED COUNT.
;-----------------------------------------------------------
BDGETCNT:
MOVE.W 2(A4),D3 ; COUNT VALUE FROM FORMAT
TST.B (A4) ; NONZERO --> FIXED
BNE.S @3
TST.W D3 ; COUNT <= 0 --> FORCE 1
BLE.S @1
CMPI.W #19,D3 ; BIGGER THAN 19?
BLE.S @3
MOVEQ #19,D3
BRA.S @3
@1:
MOVEQ #1,D3 ; FORCE AT LEAST 1 DIGIT
@3:
RTS
;-----------------------------------------------------------
; NOW CHECK FLOAT RESULT AGAINST LOWER BOUND 10^N-1.
;-----------------------------------------------------------
BD85:
TST.B (A4) ; NONZERO --> FIXED
BNE.S BD9
BSR.S BDGETCNT ; GET NUMBER OF DIGITS N
SUBQ.W #1,D3 ; WANT N-1
BSR POW10 ; 10^N-1 IN (A1)
;-----------------------------------------------------------
; AGAIN, PERFORM COMPARISON RIGHT ON MEMORY OPERANDS.
;-----------------------------------------------------------
MOVE.W (A3),D0 ; SIGN, EXP OF SCALED VAL
BCLR #15,D0 ; ABSOLUTE VALUE
CMP.W (A1),D0 ; (SCALED) - (10^N)
BNE.S @13
MOVE.L 2(A3),D0 ; HIGH ORDER DIGITS
CMP.L 2(A1),D0
BNE.S @13
MOVE.L 6(A3),D0
CMP.L 6(A1),D0
@13:
BCC.S BD9 ; UNSIGNED >= --> OK
;-----------------------------------------------------------
; IF SCALED VALUE IS TOO SMALL, JUST FORCE 10^N-1,
; CONVENIENTLY KEPT IN (A1).
;-----------------------------------------------------------
MOVE.W (A1),(A3)
MOVE.L 2(A1),2(A3)
MOVE.L 6(A1),6(A3)
; fall into BD9 to compute the digit string
;-----------------------------------------------------------
; COMPUTE THE DIGIT STRING.
;-----------------------------------------------------------
BD9:
;-----------------------------------------------------------
; TO CONVERT THE BINARY INTEGER FIELD TO A DECIMAL STRING,
; DIVIDE BY 10^19 (TO GET A FRACTION), THEN REPEATEDLY
; MULTIPLY BY 10 AND STRIP THE DIGIT THAT FALLS OFF THE
; LEFT. DIVIDE, WHICH USES THE CODE FROM FLOATING DIV,
; IS COOKED SO THAT THE BINARY POINT AFTER DIVISION IS TO
; THE LEFT OF THE QUOTIENT IN D4/5. TO PREPARE FOR THE
; DIVISION, MUST RIGHT-ALIGN THE INTEGER FIELD.
;
; THE SCALED VALUE MAY BE ZERO IN FIXED CONVERSION, IN WHICH
; CASE STORE '0' AND EXIT.
;-----------------------------------------------------------
MOVEA.L LKADR1(A6),A1 ; DST ADRS
MOVE.W (A3),D3 ; SIGN AND EXP OF SCALED VAL
MOVE.L 2(A3),D1 ; HIGH DIGITS
BNE.S @3
MOVE.B #'0',5(A1)
BRA BDFIN
@3:
MOVE.L 6(A3),D2 ; LOW DIGITS
BCLR #15,D3 ; CLEAR SIGN
SUBI.W #$403E,D3 ; UNBIAS EXPONENT
BEQ.S @7 ; ZERO IF HUGE INT
@5:
LSR.L #1,D1 ; SHIFT RIGHT A BIT
ROXR.L #1,D2
ADDQ.W #1,D3
BMI.S @5
@7:
;-----------------------------------------------------------
; PREPARE FOR CALL TO RESTORE ROUTINE:
; DIVIDEND: D1,D2 DIVISOR: D3,A2 QUO: D4,D5
;
; TO AVOID THE XXXXX.99999 CASE WHICH CHOPS TO WRONG INT,
; ADD 1 IN LAST PLACE AND PROPAGATE.
; NOTE THAT 'RESTORE' RETURNS WITH D0 SET TO 0.
;-----------------------------------------------------------
MOVE.L #$8AC72304,D3 ; 10^19 HIGH
MOVE.L #$89E80000,A2
MOVEQ #65,D0 ; GET FULL WIDTH QUOTIENT
BSR RESTORE
ADDQ.L #1,D5
ADDX.L D0,D4
;-----------------------------------------------------------
; NOW WRITE THE DIGIT STRING, GUARANTEED NONZERO, SKIPPING
; LEADING ZEROS.
;-----------------------------------------------------------
ADDQ.L #4,A1 ; POINT TO STRING
MOVEA.L A1,A2 ; COPY PTR TO OUTPUT STRING
CLR.B (A2)+ ; ZERO OUT LENGTH BYTE
MOVEQ #19,D6 ; DIGIT COUNTER
@11:
ADD.L D5,D5 ; DOUBLE FRACTION
ADDX.L D4,D4
ADDX.W D0,D0
MOVE.L D5,D3 ; SAVE 2 * DIG
MOVE.L D4,D2
MOVE.W D0,D1
ADD.L D5,D5 ; 4 * DIG
ADDX.L D4,D4
ADDX.W D0,D0
ADD.L D5,D5 ; 8 * DIG
ADDX.L D4,D4
ADDX.W D0,D0
ADD.L D3,D5 ; 10 * DIG
ADDX.L D2,D4
ADDX.W D1,D0
;-----------------------------------------------------------
; D0 IS GUARANTEED NONZERO IF ANY NONZERO DIGITS HAVE BEEN
; SEEN. THE HIGH BYTE OF D0 CONTAINS EXTRANEOUS INFO TO
; MARK "FIRST DIGIT SEEN".
;-----------------------------------------------------------
TST.W D0 ; ADDX.W WON'T SET THE Z BIT
BEQ.S @12 ; 0 --> LEAD 0
ORI.L #$0130,D0 ; ASCII-FY THE DIG
MOVE.B D0,(A2)+ ; STUFF IT
CLR.B D0 ; LEAVE HI BYTE MARK
ADDQ.B #1,(A1) ; INCREMENT LENGTH
@12:
SUBQ.B #1,D6
BNE.S @11
;-----------------------------------------------------------
; THE EXIT POINT FOR ALL THE TRIVIAL CASES.
;-----------------------------------------------------------
BDFIN:
ADDA.W #30,SP ; KILL STACK FRAME
BRA POP3