131 lines
3.5 KiB
ArmAsm
131 lines
3.5 KiB
ArmAsm
;; #LAYOUT# STD * #TAKE
|
|
;; #LAYOUT# X16 BASIC_0 #TAKE-OFFSET 2000
|
|
;; #LAYOUT# * BASIC_0 #TAKE
|
|
;; #LAYOUT# * * #IGNORE
|
|
|
|
; This file is under the MIT license, it contains code released by Microsoft Corporation.
|
|
; See LICENSE for more information.
|
|
|
|
; Math package - imports string to FAC1, ignores spaces
|
|
;
|
|
; This is verified to be identical to the original Microsoft implementation where it was named FIN.
|
|
;
|
|
; Input:
|
|
; - .A needs to be loaded with first char of the string
|
|
; - Carry flag must be clear
|
|
; - string address in $7A/$7B
|
|
;
|
|
; See also:
|
|
; - [CM64] Computes Mapping the Commodore 64 - page 116
|
|
; - https://www.c64-wiki.com/wiki/Floating_point_arithmetic
|
|
; - https://codebase64.org/doku.php?id=base:kernal_floating_point_mathematics
|
|
;
|
|
|
|
; NUMBER INPUT IS LEFT IN FAC.
|
|
; AT ENTRY [TXTPTR] POINTS TO THE FIRST CHARACTER IN A TEXT BUFFER.
|
|
; THE FIRST CHARACTER IS ALSO IN ACCA. FIN PACKS THE DIGITS
|
|
; INTO THE FAC AS AN INTEGER AND KEEPS TRACK OF WHERE THE
|
|
; DECIMAL POINT IS. [DPTFLG] TELL WHETHER A DP HAS BEEN
|
|
; SEEN. [DECCNT] IS THE NUMBER OF DIGITS AFTER THE DP.
|
|
; AT THE END [DECCNT] AND THE EXPONENT ARE USED TO
|
|
; DETERMINE HOW MANY TIMES TO MULTIPLY OR DIVIDE BY TEN
|
|
; TO GET THE CORRECT NUMBER.
|
|
|
|
|
|
!ifdef CONFIG_MEMORY_MODEL_38K {
|
|
|
|
FIN:
|
|
ldy #0 ; Zero FAC1_sign and SGNFLG
|
|
ldx #10 ; Zero exp and hi bytes
|
|
FINZLP:
|
|
sty DECCNT,X ; Zero low bytes
|
|
dex ; Zero TENEXP and EXPSGN
|
|
bpl FINZLP ; Zero DECCNT, DPTFLG
|
|
bcc FINDGQ ; Flags still set from CHRGET
|
|
cmp #'-' ; A negative sign?
|
|
bne QPLUS ; No, try plus sign
|
|
stx SGNFLG ; It's negative
|
|
beq FINC ; Always branches
|
|
QPLUS:
|
|
cmp #'+' ; Plus sign?
|
|
bne FIN1 ; Yes, skip it
|
|
FINC:
|
|
jsr CHRGET
|
|
FINDGQ:
|
|
bcc FINDIG
|
|
FIN1:
|
|
cmp #'.' ; The decimal point?
|
|
beq FINDP ; No kidding
|
|
cmp #'E' ; Exponent follows
|
|
bne FINE ; No
|
|
;HERE TO CHECK FOR SIGN OF EXP.
|
|
jsr CHRGET ; Yes, Get another
|
|
bcc FNEDG1 ; It is a digit. (Easier than backing up pointer)
|
|
cmp #$AB ; Minus with sign set (from table)
|
|
beq FINEC1 ; Negate
|
|
cmp #'-' ; Minus sign?
|
|
beq FINEC1
|
|
cmp #$AA ; Plus with sign set (from table)
|
|
beq FINEC
|
|
cmp #'+' ; Plus sign?
|
|
beq FINEC
|
|
bne FINEC2
|
|
FINEC1:
|
|
ror EXPSGN ; Turn it on
|
|
FINEC:
|
|
jsr CHRGET ; Get another
|
|
FNEDG1:
|
|
bcc FINEDG ; It is a digit
|
|
FINEC2:
|
|
bit EXPSGN
|
|
bpl FINE
|
|
lda #0
|
|
sec
|
|
sbc TENEXP
|
|
jmp FINE1
|
|
FINDP:
|
|
ror DPTFLG
|
|
bit DPTFLG
|
|
bvc FINC
|
|
FINE:
|
|
lda TENEXP
|
|
FINE1:
|
|
sec
|
|
sbc DECCNT ; Get number of places to shift
|
|
sta TENEXP
|
|
beq FINQNG ; Negate?
|
|
bpl FINMUL ; Positive so multiply
|
|
FINDIV:
|
|
jsr div10_FAC1_p
|
|
inc TENEXP ; Done?
|
|
bne FINDIV ; No
|
|
beq FINQNG ; Yes
|
|
FINMUL:
|
|
jsr mul10_FAC1
|
|
dec TENEXP ; Done
|
|
bne FINMUL ; No
|
|
FINQNG:
|
|
lda SGNFLG
|
|
bmi NEGXQS ; If positive, Return
|
|
rts
|
|
NEGXQS:
|
|
jmp toggle_sign_FAC1 ; Otherwise, negate and return
|
|
|
|
FINDIG:
|
|
pha
|
|
bit DPTFLG
|
|
bpl FINDG1
|
|
inc DECCNT
|
|
FINDG1:
|
|
jsr mul10_FAC1
|
|
pla ; Get it back
|
|
sec
|
|
sbc #'0'
|
|
jsr FINLOG ; Add it in
|
|
jmp FINC
|
|
|
|
|
|
} else {
|
|
+STUB_IMPLEMENTATION
|
|
}
|