;; #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 - outputs FAC1 to string at $0100
;
; This is verified to be identical to the original Microsoft implementation where it was named FOUT
;
; Output:
; - .A - address low byte
; - .Y - address high byte
;
; 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
;


FOUT:
        ldy #1
FOUTC:
        lda #' '        ; Print space if positive.
        bit FAC1_sign
        bpl FOUT1
        lda #$2D
FOUT1:
        sta FBUFFR-1,Y  ; Store the character.
        sta FAC1_sign   ; Make FAC1 pos for QINT
        sty FBUFPT      ; Save for later
        iny
        lda #'0'        ; Get zero to type if FAC1=0
        ldx FAC1_exponent
        bne @1
        jmp FOUT19
@1      lda #0
        cpx #$80        ; Is number .LT. 1.0 ?
        beq FOUT37      ; No
        bcs FOUT7
FOUT37:
        lda #<const_NZMIL
        ldy #>const_NZMIL
        jsr mul_MEM_FAC1
        lda #$F7
FOUT7:
        sta DECCNT      ; Save count or zero it
FOUT4:
        lda #<const_NZ9999
        ldy #>const_NZ9999
        jsr FCOMP       ; Is number .GT. 999999.499 ? or 999999999.499?
        beq BIGGES
        bpl FOUT9       ; Yes. Make it smaller
FOUT3:
        lda #<const_NZ0999
        ldy #>const_NZ0999
        jsr FCOMP       ; Is number .GT. 99999.9499 ? or 99999999.9499?
        beq FOUT38
        bpl FOUT5       ; Yes. Done multiplying

FOUT38:
        jsr MUL10       ; Make it bigger
        dec DECCNT
        bne FOUT3       ; See if that does it.
FOUT9:
        jsr div10_FAC1_p        ; Make it smaller
        inc DECCNT
        bne FOUT4               ; See if that does it
FOUT5:
        jsr add_HALF_FAC1       ; Add a half to round up
BIGGES:
        jsr QINT
        ldx #1          ; Decimal point count
        lda DECCNT
        clc
        adc #$0A        ; Should the number be printed in E notation? i.e. is number .LT. .01 ?
        bmi FOUTPI      ; Yes
        cmp #$0B        ; Is it .GT. 999999 (999999999)?
        bcs FOUT6       ; Yes. Use E notation.
        adc #$FF        ; Number of places before decimal point
        tax
        lda #2          ; No E notation

FOUTPI: 
        sec
FOUT6:
        sbc #2          ; Effectively add 5 to orig exp
        sta TENEXP      ; That is the exponent to print
        stx DECCNT      ; Number of decimal places
        txa
        beq FOUT39
        bpl FOUT8       ; Some places before dec pnt
FOUT39:
        ldy FBUFPT      ; Get pointer to output
        lda #'.'        ; Put in "."
        iny
        sta FBUFFR-1,Y
        txa
        beq FOUT16
        lda #'0'        ; Get the ensuing zero
        iny
        sta FBUFFR-1,Y
FOUT16:
        sty FBUFPT      ; Save for later.
FOUT8:
        ldy #0
FOUTIM:
        ldx #$80        ; First pass thru, X has MSB set
FOUT2:
        lda FAC1_mantissa+3
        clc
        adc FOUTBL+3,Y
        sta FAC1_mantissa+3
        lda FAC1_mantissa+2
        adc FOUTBL+2,Y
        sta FAC1_mantissa+2
        lda FAC1_mantissa+1
        adc FOUTBL+1,Y
        sta FAC1_mantissa+1
        lda FAC1_mantissa+0
        adc FOUTBL,Y
        sta FAC1_mantissa+0
        inx             ; It was done yet another time
        bcs FOUT41
        bpl FOUT2
        bmi FOUT40        
FOUT41:
        bmi FOUT2
FOUT40:
        txa
        bcc FOUTYP      ; Can use A as is
        eor #$FF        ; Find 11.-[A]
        adc #10         ; CF C is still on to complete negation. And will always be on after

FOUTYP: 
        adc #'0' - 1    ; Get a character to print
        iny             ; Bum pointer up
        iny
        iny
        iny
        sty FDECPT
        ldy FBUFPT
        iny             ; Point to place to store output
        tax
        and #$7F        ; Get rid of MSB
        sta FBUFFR-1,Y
        dec DECCNT
        bne STXBUF      ; Not time for DP yet
	    lda #'.'        ; "."
        iny
        sta FBUFFR-1,Y  ; Store DP
STXBUF:
        sty FBUFPT      ; Store PNTR for later
        ldy FDECPT
FOUTCM:
        txa             ; Complement X
        eor #$FF        ; Complement A
        and #$80        ; Save only MSB
        tax
        cpy #FDCEND-FOUTBL

        beq FOULDY
        cpy #TIMEND-FOUTBL
        bne FOUT2       ; Continue with output
FOULDY:
        ldy FBUFPT      ; Get back output PNTR
FOUT11:
        lda FBUFFR-1,Y  ; Remove trailing zeroes
        dey
        cmp #'0'
        beq FOUT11
        cmp #'.'
        beq FOUT12      ; Run into DP STOP
        iny             ; Something else. Save it
FOUT12:
        lda #'+'
        ldx TENEXP
        beq FOUT17      ; No exponent to output
        bpl FOUT14
        lda #0
        sec
        sbc TENEXP
        tax
        lda #'-'        ; Exponent is negative
FOUT14:
        sta FBUFFR+1,Y  ; Store sign of exp
        lda #'E'
        sta FBUFFR,Y    ; Store the "E" character
        txa
        ldx #'0' - 1
        sec
FOUT15:
        inx             ; Move closer to output value
        sbc #10
        bcs FOUT15      ; Not negative yet
        adc #'0' + 10   ; Get second output character
        sta FBUFFR+3,Y  ; Store high digit
        txa
        sta FBUFFR+2,Y  ; Store low digit
        lda #0          ; Put in terminator
        sta FBUFFR+4,Y
        beq FOUT20      ; Return (always branches)
FOUT19:
        sta FBUFFR-1,Y  ; Store the character
FOUT17:
        lda #0          ; A terminator
        sta FBUFFR,Y
FOUT20:
        lda #<FBUFFR
        ldy #>FBUFFR
FPWRRT:
         rts            ; All done


