TITLE 'FAST FLOATING POINT (ATARI)' SUBTTL 'SYSTEM EQUATES USED' ; ; FAST FLOATING POINT ROM FOR THE ATARI 800/400 (TM ATARI, INC) ; Written by Charles W. Marslett, August-November, 1981 ; Copyright 1981, Charles W. Marslett ; Copyright 1982 and 1984, Charles W. Marslett ; ; Permission is granted by the author for any use whatsoever of this ; code, so long as this notice remains in the source code, and so ; long as the source to this routine, however modified or unmodified, ; is made available for a nominal cost. ; ; SPEED IMPROVED OVER ATARI ROM, IN MOST CASES BY A FACTOR OF 3. ; ERRORS IN LOG AND DIVIDE ALGORITHMS CORRECTED. ; ACCURACY IN EXP FUNCTION IMPROVED (I THINK). ; ; REVISION A, ASCII-->FLOATING CONVERSION OF 9 DIGITS ONLY (LIKE ATARI), ; 19 NOVEMBER 1981. ; REVISION B, RETURNED TO USING REDARG IN LOG (LIKE ATARI), TO ALLOW ; INCLUSION OF SIN/COS/SQR CONSTANTS FOR BASIC CARTRIDGE ; 27 NOVEMBER 1981. ; REVISION C, ELIMINATED USE OF DEGRAD AND FRX IN THE FMUL/FDIV CODE AND ; FURTHER SPEEDED UP FMUL BY UNROLLING SHIFT LOOP, 30-NOV-81 ; REVISION D, INSERTED COPYRIGHT NOTICE IN THE ROM, 1-DEC-81 ; REVISION E, ADDED ASCII HEX DISPLAY ROUTINE, 4-MAR-82 ; REVISION F, MODIFIED EXP AND LOG FUNCTIONS FOR THE 600XL ; AND 800XL BASIC ROM POWER ROUTINE BUG, 17-JUNE-84 ; ROMBASE = $D800 ;STARTING ADDRESS OF F.P. ROM FPREC = 6 ;NUMBER OF BYTES IN A F.P. NUMBER ; ; BASE PAGE DEFINITIONS ; ORG $D4 FR0 DS FPREC FRE DS FPREC FR1 DS FPREC FR2 DS FPREC FRX DS FPREC EEXP = FRX+1 NSIGN = FRX+2 ESIGN = FRX+3 FCHRFLG = FRX+4 DIGRT = FRX+5 CIX DS 1 INBUFF DS 2 Z1 DS 2 Z2 DS 2 Z3 DS 2 DEGRAD DS 1 ;DEGREE OR RADIAN UNITS FOR BASIC FLPTR DS 2 FPTR2 DS 2 ; ; POLYNOMIAL WORK AREA ; ORG $57E LBPR1 DS 1 LBPR2 DS 1 LBUFF DS $60 PLYARG DS FPREC FSCR DS FPREC FSCR1 DS FPREC DS 128-$60-FPREC-FPREC-FPREC LBFEND = *-1 SUBTTL 'FLOATING POINT/ASCII CONVERSION ROUTINES' ; ; ASCII TO FLOATING POINT CONVERSION ROUTINE (ADDR=D800) ; ORG ROMBASE AFP JSR SKBLK ;SKIP ANY LEADING BLANKS JSR NXTCH ;LOAD THE NEXT CHARACTER BCS EXIT ;IF NOT NUMERIC, EXIT LDX #FRX ;ZERO FRX AND FR0 JSR ZF1 JSR ZFR0 DEC DIGRT ;STORE -1 INTO DIGRT ; CHRLP STA FCHRFLG ;CLEAR THE FIRST CHARACTER INDICATION JSR GETCH ;GET THE NEXT CHARACTER BCS INVLD ;IF NOT NUMERIC LDX FR0 BNE NOTZER ;IF FR0 IS NORMALIZED JSR SH0L4 ;ELSE, SHIFT CONTENTS LEFT 4 BITS ORA FR0+FPREC-1 STA FR0+FPREC-1 ;MERGE IN NEW DIGIT LDX DIGRT BMI CHRLP0 ;IF STILL AN INTEGER, JUST LOOP BACK ; DECFND INC DIGRT ;ELSE, BUMP NUMBER OF DECIMAL PLACES ; NOTZER LDX DIGRT ;FILLED UP THE 10 DIGITS FOR THE NUMBER BPL CHRLP0 ;IF AFTER DECIMAL, IGNORE REMAINING DIGIT INC EEXP ;IF NOT, BUMP THE EXPONENT BY 1 CHRLP0 LDA #$FF ;RESET FIRST CHARACTER FLAG BNE CHRLP ; INVLD CMP #'.' ;FOUND DECIMAL? BNE NODEC0 ;YES, START DECIMAL PLACE COUNTER LDX DIGRT ;BY MAKING NEGATIVE DIGRT POSITIVE BMI DECFND ;IF NOT NEGATIVE, SECOND '.' ENDS FIELD ; NODEC0 CMP #'E' BNE NOEXP ;IF NOT 'E', THEN NO EXPONENT SUBFIELD LDX CIX JSR GETCH BCC NOESG ;X CONTAINS 'CIX' BEFORE PARSING EXPONENT CMP #'+' BEQ SKESG CMP #'-' BNE RSTEXP ;IF NO + OR - AFTER 'E' THEN NO EXPONENT STA ESIGN ;MARK NEGATIVE IF '-' FOUND SKESG JSR GETCH ;IN ANY CASE, SEE IF NEXT CHARACTER IS NUMERIC BCS RSTEXP ;IF NOT, NO EXPONENT SUBFIELD EXPLP TAY ;SAVE NEXT DIGIT LDA FRX ASL A ASL A ;MULTIPLY PREVIOUS TOTAL BY 10 ADC FRX ASL A STA FRX ;THEN ADD TO THIS DIGIT (IN Y) TYA ADC FRX NOESG STA FRX ;AND UPDATE FRX JSR GETCH BCC EXPLP ;IF NO OVERFLOW AND NEXT CHARACTER NUMERIC BCS NUMEND ;IF NONNUMERIC, END OF THE NUMBER ; ; STUFF A BYTE INTO THE TEXT BUFFER (CONVERTING TO ASCII IF REQ.) ; CVASC ORA #'0' ;CONVERT DIGIT TO ASCII CHARACTER ; STUFF STA LBUFF,Y ;STORE BYTE INTO BUFFER INY ;BUMP THE INDEX EXIT RTS ; ; CONDITIONALLY PUT A DECIMAL POINT IN A BUFFER ; CDPNT DEC Z2 BNE EXIT ;IF NO POINT TO BE STUFFED LDA #'.' ;ELSE, PUT IT IN BNE STUFF ; NOEXP LDX FCHRFLG BNE NUMEND CMP #'+' BEQ CHRLP0 ;IF LEADING '+', IGNORE IT CMP #'-' BNE NUMEND ;IF LEADING '-', SET NEGATIVE FLAG STA NSIGN BEQ CHRLP0 ; RSTEXP STX CIX ;RESTORE POINTER AT BEGINNING OF PARSE TRY LDA #0 STA FRX ;REZERO EXPONENT NUMEND LDA EEXP CLC ADC #$88 LDX DIGRT BMI NODP ;IF NO DECIMAL POINT ADJUSTMENT SEC SBC DIGRT ;ELSE, SUBTRACT NUMBER OF DIGITS TO RIGHT OF DP NODP LDX ESIGN ;CHECK EXPONENT SIGN BNE SUBEXP ;IF NEGATIVE, SUBTRACT VALUE CLC ADC FRX ;ELSE, ADD VALUE OF EXPONENT TO BASE ONE JMP EXPOK ; ; REST OF THE BYTE TO ASCII (HEX) CONVERSION ROUTINE ; CTUHEX PLA ;RESTORE ORIGINAL BYTE LSR A LSR A LSR A LSR A ;POSITION UPPER 4 BITS FOR CONVERSION JMP HEXDGT ;RETURN THROUGH THE CONVERSION ROUTINE ; EXP3DG TXA SBC #100 ;TAKE THE 100 OUT OF THE EXPONENT TAX LDA #'1' ;PRINT THE LEADING '1' BNE NNEXP ; SUBEXP SEC SBC FRX EXPOK LSR A ;CONVERT TO POWERS OF 100 BCC EVEXP ;SKIP AROUND TIMES 10 JSR SH0L4 EVEXP LDY FR0 BEQ NORGT ADC #1 LDX #FPREC-2 SH0R LDY FR0,X STY FR0+1,X DEX BPL SH0R NORGT LDX NSIGN BEQ NOXOR EOR #$80 NOXOR DEC CIX ;BACK UP OVER THE FINAL (INVALID) CHARACTER JMP IFPE ;STORE EXPONENT AND NORMALIZE ; NOEXPF JSR PRTDGT ;GO PUT ASCII DIGIT STRING INTO BUFFER INY ORA #$80 BNE PUTSGN ;GO PUT MINUS SIGN IN IF REQUIRED ; ; RETURN A VALUE OF ASCII ZERO ; ASCZER LDA #$80+'0' ;ZERO, END OF STRING BNE STZERO ; ; FLOATING POINT TO ASCII CONVERSION (ADDR=D8E6) ; ORG AFP+$E6 FASC JSR INITBF ;PUT ADDRESS OF LBUFF INTO INBUFF LDA FR0 ;IS THE NUMBER ZERO? BEQ ASCZER ;IF YES, RETURN ASCII ZERO ; ASL A ;GET RID OF SIGN BIT SEC SBC #$7E ;DO RANGE CHECK (>0.01 AND < 1E10) CMP #12 ;11 POSSIBLE DECIMAL POINTS (0-10) BCC NOEXPF SBC #2 ;CONVERT TO SIGNED EXPONENT OF 10 STA EEXP ;AND SAVE IT FOR LATER PRINTING LDA #3 ;SET CODE FOR XX.XXXXXXXX, BIT0=1, EXP FORMAT JSR PRTDGT INY LDA #'E' ;FOLLOW DIGITS WITH AN 'E' JSR STUFF ; LDA #'+' ;ASSUME SIGN IS POSITIVE LDX EEXP BPL NNEXP ;IF EXPONENT IS POSITIVE LDA #0 ;COMPUTE ABSOLUTE VALUE OF EXPONENT SEC SBC EEXP TAX LDA #'-' ;THEN, DISPLAY A '-' NNEXP JSR STUFF ;DISPLAY SIGN CPX #100 ;EXPONENT > 100? BCS EXP3DG ;IF SO, GO PRINT 3 DIGIT EXPONENT (1XX) TXA ;RESTORE EXPONENT TO ACC INY ;ALLOW FOR 10-S DIGIT OF EXPONENT LDX #'0'-1 ;SET UP FOR CONVERT-TO-DECIMAL SEC CVDLP SBC #10 ;SUBTRACT 10 FROM ACC INX BCS CVDLP ;AND CONTINUE DOING SO UNTIL CONVERTED ADC #$80+'0'+10 ;RESTORE THE LAST 10 SUBTRACTED STA LBUFF,Y ;STUFF IT INTO THE BUFFER TXA ;MOVE 10-S DIGIT TO ACC PUTSGN STA LBUFF-1,Y ;AND PUT IT INTO THE BUFFER LDA FR0 ;STRIP OFF LEADING ZERO? BPL MINXIT ;IF NOT, ALL IS OK NOW DEC INBUFF ;ELSE, MAKE ROOM FOR MINUS LDA #'-' STZERO LDY #0 STA (INBUFF),Y ;PUT MINUS IN THE BUFFER MINXIT RTS ;THEN FINALLY, WE EXIT ; ; COPYRIGHT NOTICE IN THE ROM TEXT ; COPYRIGHT 1984, C. W. MARSLETT ; DB 'CPYRT.1984,MARSLETT' SUBTTL 'FLOATING POINT/INTEGER CONVERSION ROUTINES' ; ; INTEGER TO FLOATING POINT CONTINUATION ; IFPSU STY FR0+5 LDY #16 ;SIXTEEN BITS IN NUMBER TO BE CONVERTED IFPS ASL FR0+1 ROL A ;FIND FIRST 1 BIT DEY BCS IFPEN ;EXIT IF FOUND BPL IFPS ;ELSE, CONTINUE LOOPING RTS ;ELSE, RETURN ZERO TO CALLER ; IFPEN SED STA Z3 ;SAVE UPPER BYTE OF INTEGER IFPL LDA FR0+3 ADC FR0+3 ;DOUBLE FR0 AND AND IN ONE BIT FROM INTEGER STA FR0+3 LDA FR0+2 ADC FR0+2 STA FR0+2 ROL FR0+1 ;UPPER TWO DIGITS MAY BE ROTATED (NEVER > 9) ROL Z3 DEY BPL IFPL ;THEN GO BACK TO HANDLE THE NEXT BIT ; LDA #$42 ;GENERATE THE EXPONENT JMP IFPE ;THEN STORE, NORMALIZE AND EXIT ; ; FLOATING POINT TO INTEGER CONTINUATION ; FPICTU LDY #0 STY FR0 TAX BEQ FFRAC ;IF PROPER FRACTION, GO DO ROUNDING ASL A ;ELSE, MULTIPLY BY 16 (NUMBER OF BITS * 2) ASL A ASL A ASL A TAX ;PUT INTO X REGISTER ; CVTLP ASL FR0+4 ;SHIFT NUMBER LEFT FOR CONVERSION ROL FR0+3 ROL FR0+2 ROL FR0+1 BCC CVTST ;IF NO BIT, DO NO ADD LDA FR0 ;FIRST ADD LOW BITS ADC BITTAB,X STA FR0 TYA ;THEN THE HIGH BITS ADC BITTAB+1,X TAY ;STORE BACK INTO Y-REG CVTST DEX DEX BNE CVTLP ;IF NOT SHIFTED OUT, LOOK AT NEXT BIT ; FFRAC LDA FR0+1 ;ROUND OFF FRACTION CMP #$50 BCC FFEXIT INC FR0 BNE FFEXIT INY ;ADD CARRY TO UPPER BYTE FFEXIT STY FR0+1 CLC RTS ;FINALLY, RETURN ; ; ; INTEGER --> FLOATING POINT ENTRY POINT (ADDR=D9AA) ; ORG AFP+$1AA IFP LDA FR0+1 LDX FR0 STX FR0+1 LDY #0 ;ZERO FR0+2 TO FR0+5 STY FR0+2 STY FR0+3 STY FR0+4 BEQ IFPSU ;GO FINISH SETUP (DUE TO LACK OF SPACE HERE) ; FDIF5 LDA FR0,X SBC FR1+1,Y STA FR0,X DEX DEY BPL FDIF5 ; FDIF6 DEX BMI FNME ;IF NO CARRY PROP. REQ. LDA FR0+1,X SBC #0 STA FR0+1,X BCC FDIF6 ;IF CARRY PROP. NOT COMPLETE BCS FNORM ;IF DONE, GO NORMALIZE ; ; FLOATING POINT NUMBER TO INTEGER CONVERSION (ADDR=D9D2) ; ORG AFP+$1D2 FPI LDA FR0 ;USED HEAVILY BY BASIC ! ! ! ! ! ! ! ! ! ! CMP #$43 ;IS IT TOO BIG? BCS ZFR0 ;IF SO, EXIT WITH CARRY SET SBC #$3E ;ELSE, SUBTRACT 3F (NOTE CARRY IS CLEARED) BCS FPICTU ;IF CARRY, THEN AT LEAST ROUNDING NEEDED BCC ZFR0 ;IF LESS THAN 0.01, RETURN ZERO, NO CARRY ; ; CONVERSION ROUTINE FOR A SINGLE HEX DIGIT ; HEXDGT SEC SED SBC #$9 ;CONVERSION USES A VERY FUNNY ALGORITHM ADC #'9' CLD RTS ; ; FLOATING POINT ADD/SUBTRACT CODE (SPREAD ABOUT YOU SEE) ; ORG AFP+$1E7 ;LINE UP ZFR0, ZF1 AND INITBF FNME BCS FNORM SEC LDX #FPREC-1 FNM0 LDA #0 SBC FR0,X STA FR0,X DEX BNE FNM0 ; LDA FR0 EOR #$80 IFPE STA FR0 FNORM CLD LDY #FPREC-1 FNML LDA FR0+1 BEQ FNM2 ;IF UNNORMALIZED, GET RID OF LEADING ZEROS CLC ;ELSE, CLEAR CARRY AND RETURN RTS ; FNM3 LDX #1-FPREC FNM4 LDA FR0+FPREC+1,X STA FR0+FPREC,X INX BNE FNM4 DEY BNE FNML ;GO BACK AND CHECK NEXT DIGIT PAIR BEQ RZERO ;IF SHIFTED 5 TIMES, THEN = ZERO! ; FR0BIG EOR #$FF ;IF THE OTHER WAY AROUND, COMPUTE 4-DIF ADC #FPREC-2 BCC FNML ;IF SECOND NUMBER IS NON-SIGNIFICANT TAY SED LDA FR0 EOR FR1 BMI FDIF5 CLC ;CLEAR CARRY FOR ADD FADD5 LDA FR0,X ADC FR1+1,Y STA FR0,X DEX DEY BPL FADD5 ; FADD6 DEX BMI FHTST ;IF NO CARRY PROPOGATE REQUIRED LDA FR0+1,X ADC #0 STA FR0+1,X BCS FADD6 ;IF CARRY OUT, PROPOGATE TO NEXT BYTE BCC FHTST ; FNM2 STA FR0+FPREC FNMUL LDA FR0 DEC FR0 EOR FR0 BPL FNM3 RZERO CLC ;RETURN A ZERO WITH CARRY CLEAR ; ; ZERO FR0 (ADDR=DA44) ; ZFR0 LDX #FR0 ;POINT AT FIRST BYTE TO BE ZEROED ; ; ZERO ANY (6-BYTE) FLOATING REGISTER ON PAGE 0 (ADDR=DA46) ; ZF1 LDY #FPREC ; ; ZERO ANY PART OR ALL OF PAGE ZERO (ADDR=DA48) ; ZPG0 LDA #0 ZF1LP STA 0,X INX DEY BNE ZF1LP RTS ;THEN RETURN ; ; POINT INBUFF TO LBUFF (ADDR=DA51) ; INITBF LDA #HIGH[LBUFF] ;COPY ADDRESS OF LBUFF INTO INBUFF STA INBUFF+1 LDA #LOW[LBUFF] STA INBUFF RTS ; ; SHIFT 2-BYTE POINTER LEFT 1 BIT ; DBLZ2 ASL Z2+1 ;SHIFT 0 INTO LOW BIT OF SECOND BYTE ROL Z2 ;SHIFT HIGH BYTE INTO LOW BIT OF FIRST RTS ;THEN RETURN SUBTTL 'ADD/SUBTRACT ROUTINES' ORG AFP+$260 ; ; FLOATING SUBTRACT ENTRY POINT (ADDR=DA60) ; FSUB LDA FR1 EOR #$80 ;FLIP THE SECOND ARGUMENT-S SIGN STA FR1 ;BEFORE DOING AN ADD! ; ; FLOATING ADD ENTRY POINT (ADDR=DA66) ; FADD LDX #FPREC-1 ;GET THE NUMBER OF MANTISSA BYTES INTO X LDA FR1 ;GET THE EXPONENT OF THE SECOND ARGUMENT AND #$7F ;STRIP OFF THE SIGN BIT STA Z2 ;SAVE IT FOR EXPONENT COMPARE LDA FR0 ;GET THE EXPONENT OF THE FIRST ARGUMENT AND #$7F ;STRIP OFF ITS SIGN BIT SEC SBC Z2 ;SUBTRACT SECOND EXPONENT BPL FR0BIG ;IF THE FIRST IS GREATER, GO ON WITH IT ADC #FPREC-1 ;SEE IF THE FIRST IS EVEN SIGNIFICANT TAY ;STORE NUMBER OF SIGNIFICANT BYTES SED ;GO TO DECIMAL MODE FOR ARITHMETIC LDA FR0 ;COMPUTE REAL OPERATION (XOR OF SIGNS) EOR FR1 BMI FDIF0 ;IF DIFFERENT, THIS IS REALLY A SUBTRACT CLC ;CLEAR CARRY DEY ;Y=0? BMI FADD1 ;IF SO, SKIP ADD FADD0 LDA FR0+1,Y ;ELSE, ADD THE TWO SELECTED BYTES ADC FR1,X STA FR0,X DEX DEY BPL FADD0 ;AND LOOP UNTIL ALL ARE DONE ; FADD1 LDA FR1,X ;THEN PROPOGATE CARRY TO TOP OF LARGER ARGUMENT ADC #0 STA FR0,X DEX BNE FADD1 ; LDA FR1 ;COPY EXPONENT FROM SECOND TO FIRST ARG STA FR0 FHTST BCC FADDX ;IF NO CARRY, EXIT (ADD COMPLETE!) LDX #FPREC-2 ;ELSE, SHIFT MANTISSA RIGHT 1 BYTE FADD2 LDA FR0,X STA FR0+1,X DEX BNE FADD2 ;UNTIL ENTIRE BYTE IS MOVED OVER LDA #1 ;PUT A '1' IN THE HIGH MANTISSA BYTE STA FR0+1 LDA FR0 ;THEN INCREMENT THE EXPONENT INC FR0 EOR FR0 ;SEE IF OVERFLOW (SIGN CHANGE FROM INCR.!) ROL A FADDX CLD ;RETURN TO BINARY MODE RTS ;THEN RETURN (OV==>CY SET) ; FDIF0 SEC ;SET THE CARRY FLAG DEY BMI FDIF2 ;SKIP SUBTRACT PHASE IF NO SIGNIFICANT BYTES FDIF1 LDA FR1,X ;SUBTRACT FR0 FROM FR1*10^N STORING IN FR0 SBC FR0+1,Y STA FR0,X DEX DEY BPL FDIF1 ; FDIF2 LDA FR1,X SBC #0 STA FR0,X ;PROPOGATE CARRIES DEX BNE FDIF2 LDA FR1 ;THEN COPY EXPONENT TO RESULT STA FR0 JMP FNME ;AND DO NORMALIZATION SUBTTL 'FLOATING POINT (DECIMAL) MULTIPLY' ; ; FLOATING (DECIMAL) MULTIPLY ROUTINE ; ORG AFP+$2D5 ;FORCE ADDRESS OF ROUTINE TO MATCH ATARI-S NOOVFL LDX #FPREC-1 ;SET UP MAJOR LOOP COUNTER FOR EITHER MUL/DIV STX Z3 SED ;DECIMAL MODE FOR ADD LOOPS RTS ;NOTE THAT X IS ALSO SET UP AS LOOP COUNTER TOO ; FMUL LDA FR1 BEQ JZERO LDA FR0 BEQ FDXIT ;IF ZERO FR0, JUST RETURN ; TAX ;SAVE FOR LATER ERROR CHECK SEC SBC #$3F ;EXCESS 64 ADJUSTMENT CLC ADC FR1 JSR MDEXP ;GO CHECK FOR OVER/UNDER-FLOW IN EXPONENT CALC MOVEL LDA FR0,X STA FRE,X STA FR2,X LDA #0 ;THEN ZERO FR0 TO ACCUMULATE RESULT STA FR0,X DEX BNE MOVEL ;SETUP FOR MULTIPLY LOOP STA FRE ;ZERO HIGH ORDER 2 DIGITS OF BOTH FRE AND FR2 STA FR2 STA Z3+1 LDX #FRE JSR SHL4 BEQ LOOPE ;GO DO ACTUAL MULTIPLYING LOOP ; MDEXP STA FR0 TXA ;COMPUTE SIGN OF RESULT WITH XOR EOR FR1 EOR FR0 ;THEN SEE IF THE SIGNS ARE THE SAME BPL NOOVFL ;IF NOT, THIS IS OVER/UNDERFLOW ; PLA ;FLUSH TOP RETURN ADDRESS PLA LDA FR0 ;RESTORE OVER(UNDER)FLOWED EXPONENT ROL A ;IS IT OVERFLOW OR UNDERFLOW? BMI JZERO ;IF UNDERFLOW, RETURN A ZERO FOR THE RESULT OVFLDV SEC ;IF OVERFLOW, RETURN GARBAGE AND CARRY SET! RTS ; FDXIT CLC ;RETURN ORIGINAL CONTENTS OF FR0 (ZERO) RTS ;WITH NO ERROR INDICATION ; JZERO JMP RZERO ;RESULT IS UNDERFLOW (=0) ; ; ; FLOATING POINT DIVIDE (DECIMAL) ROUTINE ENTRY POINT ; ORG AFP+$320 ;FDIV IS ATARI ENTRY POINT, FLDDIV USED BY REDARG ;RFCONT IS USED BY LOG10 RFCONT LDA #3 JSR CTUEVL ;CALCULATE NUMERATOR FLDDIV JSR FLD1P ;LOAD THE DIVISOR FROM LOC POINTED TO BY (FLPTR) ; FDIV LDA FR1 ;IS THIS DIVIDE BY ZERO? BEQ OVFLDV ;IF SO, IT IS AN OVERFLOW! LDA FR0 BEQ FDXIT TAX ;ELSE, COMPUTE RESULTANT EXPONENT SEC SBC FR1 CLC ADC #$40 ;EXCESS 64 ADJUSTMENT JSR MDEXP ;GO CHECK FOR EXPONENT OVER OR UNDER FLOW ; DSETUP LDA FR1,X ;LOOP CTR (X) ALREADY SET TO FPREC-1 STA FR2,X LDA FR0,X STA FR0+1,X ;PROVIDE A LEADING BYTE OF 0 FOR ALGORITHM DEX BNE DSETUP STX FR2 STX FR0+1 ;STUFF ZERO AFTER SHIFTING FR0 RIGHT LDX #FR2 JSR SHL4 SEC LDX #0-FPREC ;POINTER TO CURRENTLY GENERATED QUOTIENT BYTE JMP SUB10E ;SKIP ZEROING 7-TH BYTE OF NUMBER ; ; MAIN MULTIPLY LOOP ; LOOP0 LDA FR0+5 STA Z3+1 LDA FR0+4 STA FR0+5 LDA FR0+3 ;SHIFT ACCUMULATED PRODUCT RIGHT ONE BYTE STA FR0+4 LDA FR0+2 STA FR0+3 LDA FR0+1 STA FR0+2 STY FR0+1 ;AND SHIFT IN 00 AT HIGH BYTE ; LOOPE LDX Z3 ;LOAD DIGIT PAIR BEING USED LDA FR1,X ;GET NEXT DIGIT PAIR TO MULTIPLY BY BEQ NOONE ;IF ZERO, SKIP BOTH MULTIPLY LOOPS LSR A LSR A LSR A LSR A ;EXTRACT UPPER DIGIT BEQ NOTEN ;IF 10-S DIGIT IS ZERO LDX #FRE ;GO ADD IN FRE-S (MULTIPLIER X 10) JSR DOMULT ; LDX Z3 NOTEN LDA FR1,X ;GET 1-S DIGIT FROM BYTE AND #$F BEQ NOONE ;IF ONES DIGIT IS ZERO, DONE! LDX #FR2 JSR DOMULT ; NOONE DEC Z3 ;DONE WITH ALL DIGITS? BNE LOOP0 ;IF NOT, CONTINUE LDA Z3+1 ;COPY 6-TH QUOTIENT DIGIT TO FR0 STA FR0+6 FNDIV CLD ;BACK OUT OF DECIMAL MODE LDA FR0+1 BNE FDXIT ;IF ALREADY NORMALIZED, EXIT TO CALLER LDY #FPREC ;ELSE, NORMALIZE WITH GUARD DIGIT JMP FNMUL ; ; LOAD 0.5 INTO FR1 ; GETHALF LDY #HIGH[HALF] LDX #LOW[HALF] JMP FLD1R ; ; SKIP OVER A STRING OF BLANKS IN INPUT BUFFER (ADDR=DBA1) ; ORG AFP+$3A1 SKBLK LDY CIX ;SKIP BLANKS IN BUFFER LDA #' ' BNE FSTTST ;TEST FIRST CHARACTER LPBLK INY FSTTST CMP (INBUFF),Y BEQ LPBLK STY CIX ;UPDATE INDEX INTO BUFFER RTS ;FOUND A NON-BLANK CHAR. RETURN! ; ; GET A CHARACTER (AND TRY TO CONVERT IT TO DECIMAL) (ADDR=DBAF) ; ; ORG AFP+$3AF GCHAR LDY CIX ;GET POINTER INTO BUFFER LDA (INBUFF),Y ;GET BYTE FROM BUFFER SEC SBC #'0' ;CONVERT FROM ASCII TO BINARY CMP #10 ;SEE IF IT FALLS OFF ON THE OTHER SIDE RTS ;CARRY SET==>NOT A DIGIT ; ; GET THE NEXT CHARACTER IF IT IS NOT A VALID NUMERIC CHARACTER ; NXTCH JSR GETCH ;GET THE CURRENT CHARACTER BCC GDCHR ;IF NUMERIC CMP #'.' BEQ DOTVLD ;DECIMAL, GO SEE IF VALID CMP #'+' BEQ SGNCHK ;PLUS OR MINUS, GO SEE IF VALID CMP #'-' BNE BADCH ; SGNCHK LDA (INBUFF),Y CMP #'.' ;IF FOLLOWED BY A DECIMAL, VALID BEQ GDCHR DOTVLD LDA (INBUFF),Y ;MAKE SURE ACC HAS NEXT CHARACTER IN IT!! CMP #'0' BCS MAYBE ;IF DIGIT FOLLOWS, SIGN IS VALID ; BADCH SEC ;IF INVALID, SET CARRY AND RETURN RTS ; ; GET A CHARACTER FROM A TEXT BUFFER ; GETCH JSR GCHAR ;GET A CHARACTER FROM BUFFER BCC UPCIX ;IF DIGIT, UPDATE CIX LDA (INBUFF),Y ;ELSE, RESTORE ACTUAL ASCII CODE UPCIX INY STY CIX ;BUMP BOTH CIX AND Y-REG RTS ;AND RETURN ; ; SHIFT FR0 LEFT 4 BIT POSITIONS (ADDR=DBE4) ; ORG AFP+$3E4 SH0L4 LDX #FR0 SHL4 LDY #4 SHLM ASL 5,X ROL 4,X ROL 3,X ROL 2,X ROL 1,X ROL 0,X DEY BNE SHLM RTS ; MAYBE CMP #'9'+1 BCS BADCH ; GDCHR CLC DEC CIX ;ADJUST INDEX BACK (NOT INCREMENTED) RTS ;AND RETURN ; ORG AFP+$400 ;NORMALIZE ENTRY POINT NORMAL JMP FNORM ;MOVED UP INTO THE FADD/FSUB ROUTINES ; ; ; DIVISION LOOP (GENERATE RESULTANT FRACTION ONLY) ; ; FDIVLP STY FRE+FPREC,X ;ZERO NEW LOW ORDER BYTE BMI SUB10E ;THEN GO TO LOOP NORMAL ENTRY ; SUB10N INY ;ADD ANOTHER 10 TO QUOTIENT LOW BYTE SUB10E LDA FRE+6,X SBC FR2+5 STA FRE+6,X LDA FRE+5,X SBC FR2+4 STA FRE+5,X LDA FRE+4,X SBC FR2+3 STA FRE+4,X LDA FRE+3,X SBC FR2+2 STA FRE+3,X LDA FRE+2,X SBC FR2+1 STA FRE+2,X LDA FRE+1,X SBC FR2 STA FRE+1,X BCS SUB10N ;IF NOT NEGATIVE YET, CONTINUE LOOPING ; TYA ASL A ASL A ;SHIFT QUOTIENT DIGIT LEFT 4 BITS ASL A ASL A ORA #10 ;THEN ADD IN UNITS DIGIT (FIRST GUESS) TAY ;RESTORE TO Y-REG ; ADD01N LDA FRE+6,X ADC FR1+5 STA FRE+6,X LDA FRE+5,X ADC FR1+4 STA FRE+5,X LDA FRE+4,X ADC FR1+3 STA FRE+4,X LDA FRE+3,X ADC FR1+2 STA FRE+3,X LDA FRE+2,X ADC FR1+1 STA FRE+2,X LDA FRE+1,X ADC #0 STA FRE+1,X DEY ;DECREMENT THE 1-S DIGIT BCC ADD01N ;AND IF NOT POSITIVE, DO ANOTHER ADD OF DIVISOR STY FRE+1,X ;ELSE, STORE RESULTANT 2 DIGITS TAY ;REZERO THE Y-ACCUMULATOR INX ;THEN SEE IF DIVIDE COMPLETED BMI FDIVLP ;IF NOT, GO GENERATE NEXT 2 DIGITS JMP FNDIV ;IF SO, GO NORMALIZE RESULT AND EXIT ; DOMULT TAY ;SAVE NUMBER OF TIMES TO ADD IN Y-REG CLC MULLP LDA Z3+1 ADC 5,X STA Z3+1 LDA FR0+5 ADC 4,X STA FR0+5 LDA FR0+4 ADC 3,X STA FR0+4 LDA FR0+3 ADC 2,X STA FR0+3 LDA FR0+2 ADC 1,X STA FR0+2 LDA FR0+1 ADC 0,X STA FR0+1 DEY ;ALL ADDITIONS DONE? BNE MULLP ;IF NOT GO DO THE NEXT ONE RTS ;ELSE, RETURN ; ; TABLE TO CONVERT FROM DECIMAL TO BINARY (BITWISE) QUICKLY ; BITTAB = *-2 DW 0,1,3,7 DW 9,19,39,79 DW 99,199,399,799 DW 999,1999,3999,7999 DW 9999,19999,-25537,-1 DW -1,-1,-1,-1 SUBTTL 'GENERALLY USEFUL SUBROUTINES' ; ; CONVERT PACKED DECIMAL MANTISSA (WITH DECIMAL INFORMATION) ; TO AN ASCII (NUMERIC) CHARACTER STRING ; PRTDGT LSR A ;GET NUMBER OF BYTES BEFORE DECIMAL POINT ROR CIX ;SAVE LOW BIT AS E-FORMAT FLAG STA Z2 ;SAVE DIGITS BEFORE DECIMAL POINT LDX #1-FPREC ;SET UP BYTE COUNTER FOR A F.P. NUMBER LDY #0 ;ZERO BOTH INDICES INC Z2 ;OFFSET FIRST DECREMENT DGTLP JSR CDPNT ;CONDITIONALLY PRINT A DECIMAL POINT LDA FR0+FPREC,X LSR A LSR A ;POSITION HIGH 4-BIT DIGIT LSR A LSR A JSR CVASC ;PUT THAT CHARACTER IN THE BUFFER LDA FR0+FPREC,X AND #$F ;EXTRACT SECOND DIGIT JSR CVASC ;AND PUT IT INTO THE BUFFER INX ;NEXT DIGIT PAIR BMI DGTLP ;IF NOT FINISHED, PROCESS THEM ; JSR CDPNT ;ELSE, SEE IF TRAILING DECIMAL REQ. LDA #'0' ;CHECK FOR LEADING DECIMAL OR ZERO CMP LBUFF BEQ TRNKZE ;IF ZERO, CLIP IT OFF LEAVING 9 DIGIT RESULT BCC DECSFT ;IF SIGNIFICANT DIGIT, MOVE DECIMAL IF IN E-FORMAT DEC INBUFF ;ELSE, IT IS A DECIMAL, BACK UP AND INSERT A STA LBUFF-1 ;LEADING ZERO! BCS ZSCAN ;THEN STRIP OFF TRAILING ZEROS ; TRNKZE INC INBUFF ;STEP TO SECOND DIGIT (WHICH CANNOT BE ZERO!) BCS ZSCAN ; DECSFT LDA CIX ;SEE IF IN E-FORMAT TRANSLATION BPL ZSCAN ;IF NOT, BUFFER IS OK, STRIP OFF TRAILING ZEROS LDA LBUFF+1 STA LBUFF+2 ;ELSE, MOVE DECIMAL POINT LEFT ONE DIGIT LDA #'.' STA LBUFF+1 INC EEXP ;AND ADJUST EXPONENT FOR THE MOVEMENT ; ; SCAN TO ELIMINATE TRAILING ZEROES ; ZSCAN LDY #11 ;START WITH DIGIT 10 (AFTER FOLLOWING 'DEC') ZSCNLP DEY BEQ LSTCHR ;IF FIRST CHARACTER, THEN USE 1 CHARACTER LDA LBUFF,Y ;GET THE LAST CHARACTER CMP #$30 ;IS IT A TRAILING ZERO? BEQ ZSCNLP ;IF SO, CONTINUE SCAN TIL NONZERO OR FIRST CHARACTER CMP #'.' ;IF NOT, IS IT A DECIMAL POINT? BNE TRXIT ;NO, THEN THIS IS THE LAST CHARACTER DEY ;YES, THEN DIGIT BEFORE IT IS THE LAST CHARACTER LSTCHR LDA LBUFF,Y ;LOAD IT AND RETURN TO CALLER TRXIT RTS SUBTTL 'POLYNOMIAL EVALUATION ROUTINE' ORG AFP+$522 RSTARG LDX #FPREC-1 ;COPY PLYARG TO FR1 RSTALP LDA PLYARG,X STA FR1,X DEX BPL RSTALP RTS ; LDARG LDX #FPREC-1 LDALP LDA PLYARG,X STA FR0,X DEX BPL LDALP RTS ; PLYONE JSR SAVARG ;SAVE ARGUMENT AND POLYNOMIAL ADDRESS CTUONE STA CIX ;SAVE ORDER OF POLYNOMIAL BNE PLYADD ;ENTER LOOP WITH AN ADD RTS ;IF A=0, VALUE IS ARGUMENT ; ; POLYNOMIAL EVALUATION ENTRY (ADDR=DD40) ; PLYEVL JSR SAVARG ;SAVE FR0, X, Y AS ARGUMENTS CTUEVL STA CIX ;SEE IF MORE THAN 1 TERM JSR LDPLY ;LOAD FIRST COEFFICIENT DEC CIX BNE PLYENT ;IF OK, GO DO MULTIPLY AND ADD RTS ;ELSE, JUST RETURN ; PLYLP DEC CIX ;END OF POLYNOMIAL? BEQ PLYXIT ;YES, EXIT JSR RSTARG ;RESTORE ARGUMENT PLYENT JSR FMUL ;ARGUMENT TIMES PARTIAL SUM BCS PLYXIT ;EXIT IF OVERFLOW HERE! PLYADD JSR LDPLY ;LOAD NEXT COEFFICIENT IN FR1 JSR FADD ;ADD NEXT COEFFICIENT BCC PLYLP PLYXIT RTS ;ELSE, RETURN ; LDPLY LDY #FPREC-1 ;INDEX BY Y SINCE INDIRECT REFERENCE LDPLYL LDA (FPTR2),Y ;GET ARGUMENT BYTE STA FR1,Y ;STORE IN FR1 DEY BPL LDPLYL ;DO ALL 6 BYTES CLC ;THEN ADVANCE THE POINTER LDA FPTR2 ADC #FPREC ;BY THE LENGTH OF 1 FLOATING POINT NUMBER STA FPTR2 BCC LDPXIT ;EXIT IF NO CARRY INC FPTR2+1 ;ELSE, BUMP UPPER BYTE LDPXIT RTS ;AND RETURN ; SAVARG STY FPTR2+1 STX FPTR2 ;STORE ADDRESS OF POLYNOMIAL PUTARG TAY ;SAVE ACC LDX #FPREC-1 ;COPY FR0 TO PLYARG SAVALP LDA FR0,X STA PLYARG,X DEX BPL SAVALP ;LOOP UNTIL ALL 6 BYTES MOVED TYA ;RESTORE ACC RTS SUBTTL 'MEMORY TO MEMORY MOVE SUBROUTINES' ; ; LOAD FLOATING REGISTER 0 ; ORG AFP+$589 FLD0R STY FLPTR+1 ;STORE (Y,X) AS ADDRESS STX FLPTR FLD0P LDY #FPREC-1 FLD0L LDA (FLPTR),Y STA FR0,Y DEY BPL FLD0L ;COPY ALL BYTES OF THE NUMBER RTS ; ; LOAD FLOATING REGISTER 1 ; ORG AFP+$598 FLD1R STY FLPTR+1 ;STORE (Y,X) AS ADDRESS STX FLPTR FLD1P LDY #FPREC-1 FLD1L LDA (FLPTR),Y STA FR1,Y DEY BPL FLD1L ;COPY ALL BYTES RTS ; ; STORE FLOATING REGISTER 0 ; FST0R STY FLPTR+1 ;STORE (Y,X) AS ADDRESS OF TARGET STX FLPTR FST0P LDY #FPREC-1 FST0L LDA FR0,Y STA (FLPTR),Y DEY BPL FST0L ;LOOP UNTIL ENTIRE FIELD IS STORED RTS ; ; MOVE FR0 TO FR1 ; ORG AFP+$5B6 FMOVE LDX #FPREC-1 FMOVL LDA FR0,X STA FR1,X DEX BPL FMOVL OVFEXP RTS SUBTTL 'EXPONENTIAL FUNCTIONS' ; ; BASE e EXPONENTIAL FUNCTION ; ORG AFP+$5C0 EXP LDY #HIGH[INVL10] LDX #LOW[INVL10] JSR FLD1R ;MULTIPLY ARGUMENT TO CONVERT FUNCTION TO EXP10 JSR FMUL BCS OVFEXP ;IF OVERFLOW, RETURN CARRY SET ; ; BASE 10 EXPONENTIAL FUNCTION ; EXP10 JSR FMOVE ;SAVE UNMODIFIED ARGUMENT (PRECISION REQ.) ASL FR0 LSR FR0 ;STRIP OFF SIGN BIT JSR FPI ;CONVERT TO INTEGER SEC ;SAVE A BYTE BY SETTING CARRY BEFORE TEST LDA FR1 ;SEE WHAT SIGN WAS BPL PLSEXP ;IF EXPONENT IS ALREADY POSITIVE LDA #128 SBC FR0 ;NEGATE RESULT OF IFP CALL IF NOT STA Z1+1 LDA #0 SBC FR0+1 BEQ EXPRV JMP RZERO ; PLSEXP LDA FR0 ADC #127 ;SEE IF EXPONENT IS IN RANGE STA Z1+1 BCS OVFEXP ;IF EXPONENT BETWEEN 128 AND 255 SEC ;RETURN ERROR LDA FR0+1 ;IS THE EXPONENT BETWEEN -128 AND 127? BNE OVFEXP ;<-128 OR > 255 EXPRV STA Z1 ;MARK RANGE AS UNSHIFTED JSR IFP ;BACK TO FLOATING POINT ASL FR0 ;GET RID OF INTEGER SIGN (ALWAYS +) LDA #$7F ;COPY COMPLIMENT OF SIGN OF FR1 TO CY CMP FR1 ROR FR0 ;PUT NEW SIGN BACK INTO FR0 JSR FADD ;GENERATE FRACTIONAL PART OF EXPONENT ; LDA FR0 ;SEE IF FRACTION > 0.25 AND #$7F CMP #$3F ;IF EXPONENT NOT 3F THEN ITS NOT BNE EVALG LDA FR0+1 ;ELSE, LOOK AT UPPER 2 DIGITS CMP #$25 BCC EVALG ;IF < 25 THEN FRACTION IS OK STA Z1 ;MARK AS NEEDING ADJUSTMENT JSR GETHALF LDA FR0 ASL FR1 ASL A ROR FR1 ;COPY SIGN TO 0.5 LOADED INTO FR1 BPL NODEC DEC Z1+1 NODEC JSR FSUB ; EVALG LDY #HIGH[FSCR] ;SAVE V (REDUCED ARGUMENT) IN FSCR LDX #LOW[FSCR] JSR FST0R JSR FMOVE JSR FMUL ;SQUARE V LDY #HIGH[EXPPLY] LDX #LOW[EXPPLY] ;GENERATE P(V^2) LDA #2 ;2 TERM POLYNOMIAL JSR PLYEVL JSR FLD1P ;GET ORIGINAL ARGUMENT JSR FMUL ;COMPUTE V*P(V^2) JSR FST0P ;SAVE RESULT JSR LDARG ;COPY ARG TO FR0 LDA #2 JSR CTUONE ;CONTINUE (ARG AND POLY PTR BOTH RETAINED) JSR FLD1P ;GET NUMERATOR JSR FSUB ;COMPUTE DENOMINATOR (Q-V*P) JSR FMOVE ;PUT IN FR1 JSR FLD0P ;GET NUMERATOR JSR FDIV JSR GETHALF JSR FADD JSR FMOVE ;THEN DOUBLE RESULT JSR FADD LDA Z1 ;SEE IF ADJUSTMENT REQUIRED BEQ NOSQR JSR LDPMUL ;ELSE, LOAD FR1 WITH SQR(10) NOSQR LSR Z1+1 ;THEN SEE IF *10 REQUIRED BCC NOSFT ;IF NOT, SKIP TO EXPONENT BUILD LDY #HIGH[C10] LDX #LOW[C10] JSR FLD1R ;MULTIPLY RESULT BY 10 JSR FMUL NOSFT CLC LDA FR0 ADC Z1+1 ;ADD EXPONENT TO ORIGINAL SBC #$3F STA FR0 ;GENERATED EXP(X) COMPLETE! CLC ;TURN OFF CARRY (RANGE ERROR) FLAG OVFLOG RTS ; ; REDUCE AN ARGUMENT WITH THE FORMULA REDARG=(ARG-K)/(ARG+K) ; (ADDR=DE95) ; ORG AFP+$68D LOGRED BCS RARG1 ;IF SO, SKIP MULTIPLY BY 10 DEC Z1 STX FR1+1 ;CHANGING CONSTANT TO 0.05 BCC RARG1 ; REDARG JSR FLD1R ;GET K FROM MEMORY INTO FR1 RARG1 JSR PUTARG ;SAVE UNREDUCED ARGUMENT IN PLYARG JSR FADD ;COMPUTE ARG+K LDY #HIGH[FSCR] ;SAVE DENOMINATOR IN FSCR LDX #LOW[FSCR] JSR FST0R JSR LDARG ;RESTORE UNREDUCED ARGUMENT TO FR0 JSR FSUB JMP FLDDIV SUBTTL 'LOGRITHMIC FUNCTIONS' ORG AFP+$6AF ;PUT RIGHT BEFORE THE LOG ENTRY POINT EXPPLY DB $40,$08,$70,$38,$83,$65 DB $40,$69,$01,$09,$31,$26 ; DB $40,$34,$04,$40,$20,$67 DB $40,$59,$94,$21,$33,$27 ; SQR10 DB $40,$03,$16,$22,$77,$66 ; ; LOGRITHM FUNCTIONS (BASE e, ADDR=DECD) ; ORG AFP+$6CD ;ATARI DEFINED ENTRY POINT LOG LDA #$80 ;SET FLAG TO INDICATE THIS IS NOT BASE 10 LOG BNE LOGS ; ; LOGRITHM FUNCTIONS (BASE 10, ADDR=DED1) ; LOG10 LDA #0 LOGS STA Z1+1 ;STORE FLAG TO INDICATE WHICH CLASS OF LOGS LDA FR0 ASL A BCS OVFLOG ;IF LOG OVERFLOW (NEGATIVE ARG.) SBC #$7D STA Z1 ;SAVE RANGE DATA LDA FR0+1 ;IS NUMBER > 0.1? CMP #$10 BCS NOLSFT ;IF SO, SHIFT DENOMINATOR RIGHT 1 DIGIT DEC Z1 ;UPDATE EXPONENT FOR LEADING ZERO ELIMINATED JSR SH0L4 ;ELSE, SHIFT NUMERATOR LEFT 1 DIGIT NOLSFT LDA #$3F ;INITIAL VALUE FOR EXPONENT STA FR0 JSR GETHALF ;REDUCTION CONSTANT = 0.50 JSR FMUL ;HALVE ARGUMENT LDA FR0+1 LDX #$05 CMP #$16 ;IS THE REDUCED ARGUMENT > 0.32 (SQR(0.1)) ; JSR LOGRED ;REDUCE ARGUMENT VIA Z=(X-1)/(X+1) LDX FR0 BPL LNORM INC FR0+4-$BF,X ;FORCE NEGATIVE ROUNDING INC FR0+4-$BF,X LNORM JSR FST0P ;THEN STORE Z IN 'FSCR' JSR FMOVE JSR FMUL ;SQUARE IT LDY #HIGH[LOGPLY] LDX #LOW[LOGPLY] LDA #3 JSR PLYONE ;CALCULATE DENOMINATOR OF RAT. FRACTION LDX #LOW[FSCR1] JSR FST0R+2 ;NOTE THAT HIGH BYTE OF FLPTR IS UNCHANGED JSR LDARG ;PUT ARGUMENT BACK INTO FR0 JSR RFCONT ;CALC. DENOM. & R(Z), THE RAT. FRAC. ; JSR RSTARG ;THEN MULTIPLY BY 'Z' JSR FMUL JSR LDPLY JSR FADD LDX #LOW[FSCR] JSR FLD1R+2 ;NOTE THAT HIGH BYTE OF FLPTR IS UNCHANGED JSR FMUL JSR PUTARG INX ;CONVERT X (FROM FMOVE) TO ZERO STX FR0+1 ;ZERO HIGH BYTE OF INTEGER (EXPONENT) LDA Z1 BPL INTPRT ;IF EXPONENT IS NEGATIVE, THEN GET ABSOLUTE VALUE SEC TXA ;ZERO ACC SBC Z1 ;SUBTRACT FROM 0 (NEGATE) INTPRT STA FR0 ;STORE Z1 OR -Z1 AS APPROPRIATE JSR IFP ASL FR0 ;NEXT, CHANGE SIGN OF RESULT IF NEGATIVE ASL Z1 ROR FR0 JSR GETHALF JSR FMUL JSR FMOVE JSR LDARG ; JSR FADD ;ADD INTEGER TO FRACTION JSR FADD LDA Z1+1 BEQ LOG10E ;IF LOG BASE 10 LDPMUL JSR LDPLY ;ELSE, MULTIPLY RESULT BY LN(10) JMP FMUL ; ; CONSTANTS USED IN THE FLOATING POINT PACKAGE ; ORG AFP+$76C ;REFERENCED BY BASIC SIN/COS ROUTINE HALF DB $3F,$50,$00,$00,$00,$00 ; ; COEFFICIENTS USED IN THE LOG POLYNOMIALS ; LOGPLY DB $C0,$08,$19,$08,$00,$45 ; -8.19080045 DB $40,$16,$96,$69,$81,$40; 16.96698140 DB $C0,$10,$07,$04,$06,$95 ;-10.07040695 ; LOG10E = *+4 ;RETURN INSTRUCTION DB $BF,$67,$35,$81,$60,$15;-0.6735816015 DB $40,$03,$16,$30,$34,$92 ; 3.16303492 DB $C0,2,$91,$56,$81,$44 ;-2.91568144 ; DB $3F,$86,$85,$88,$96,$38; 0.8685889638 LN10 DB $40,$2,$30,$25,$85,$9; 2.30258509 ; INVL10 DB $3F,$43,$42,$94,$48,$19 ; C10 DB $40,$10,$00,$00,$00,$00 ; ; POLYNOMIAL FOR SIN/COS FUNCTIONS (11 COEFFICIENTS) ; ORG AFP+$7AE PLYSIN DB $3E,$16,$05,$44,$49,$00 ;REF BY BASIC SIN/COS ROUTINES DB $BE,$95,$68,$38,$45,$00 DB $3F,$02,$68,$79,$94,$16 DB $BF,$04,$92,$78,$90,$80 DB $3F,$07,$03,$15,$20,$00 DB $BF,$08,$92,$29,$12,$44 DB $3F,$11,$08,$40,$09,$11 DB $BF,$14,$28,$31,$56,$04 DB $3F,$19,$99,$98,$77,$44 DB $BF,$33,$33,$33,$31,$13 NONE DB $3F,$99,$99,$99,$99,$99 ;ALMOST EQUAL TO 1.0 (USED FOR ROUNDOFF PROBLEM) ; ; SIN OF 45 DEG. ; SIN45 DB $3F,$78,$53,$98,$16,$34 ; ; CONVERT A BYTE TO TWO HEX DIGITSIN (A,X) ; CVTHEX PHA ;SAVE UPPER DIGIT AND #$0F JSR HEXDGT ;CONVERT LOWER DIGIT TAX JMP CTUHEX ;RESTORE AND CONVERT UPPER DIGIT END