mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1275 lines
37 KiB
Plaintext
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
|
|
|
|
|