#ifndef included_atof24
#define included_atof24
#include "f24mul.z80"
#include "ascii_to_uint8.z80"
#include "f24pow10_LUT.z80"
#ifndef TOK_ENG
#define TOK_ENG 'e'
#endif
; Negative sign
#ifndef TOK_NEG
#define TOK_NEG '-'
#endif
; Decimal point
#ifndef TOK_DECIMAL
#define TOK_DECIMAL '.'
#endif
#define ptr_sto scrap+9
atof24:
;Inputs:
; HL points to the string
;Output:
; AHL is the f24 float
; scrap is the pointer to the end of the string
;Destroys:
; BC, DE
; 4 bytes at scrap
;
;Check if there is a negative sign.
; Save for later
; Advance ptr
ld a,(hl)
sub TOK_NEG
sub 1
push af
jr nc,$+3
inc hl
;Skip all leading zeroes
ld a,(hl)
cp '0'
jr z,$-4 ;jumps back to the `inc hl`
;Set exponent to 0
ld b,0
;Check if the next char is TOK_DECIMAL
sub TOK_DECIMAL
or a ;to reset the carry flag
jr nz,atof24_skip_1
.db $FE ;start of cp *
;Get rid of zeroes
dec b
inc hl
ld a,(hl)
cp '0'
jr z,$-5 ;jumps back to the `dec b`
scf
atof24_skip_1:
; at this point, we ought to pointing at our first non-zero digit, unless all
; digits were 0, in which case we might be pointing to TOK_ENG
rl c
ld a,(hl)
sub '0'
cp 10
jp nc,atof24_zero_check_eng
srl c
;Now we read in the next 6 digits
ld de,scrap+2
call ascii_to_uint8
call ascii_to_uint8
call ascii_to_uint8
;Now `scrap` holds the 3-digit base-100 number.
;b is the exponent
;if carry flag is set, just need to get rid of remaining digits
;Otherwise, need to get rid of remaining digits, while incrementing the exponent
sbc a,a
ld c,a
atof24_loop_1:
ld a,(hl)
cp TOK_DECIMAL
jr nz,$+8
dec c
jp pe,atof24_skip_7
jr atof24_skip_2 ; else C was already FF, then a decimal was already encountered
sub '0'
cp 10
jr nc,atof24_skip_6
atof24_skip_7:
; carry flag is set
inc hl
ld a,b
adc a,c
; if carry flag is set, then we added 0
jr c,atof24_loop_1
jp z,atof24_inf
ld b,a
jr atof24_loop_1
atof24_skip_6:
ld a,(hl)
;Now check for engineering `E` to modify the exponent
cp TOK_ENG
call z,atof24_str_eng_exp
atof24_skip_2:
ex de,hl ; DE points to the end of the string
;Gotta multiply the number at (scrap) by 2^17
ld hl,(scrap)
ld a,(scrap+2)
ld (ptr_sto),de ; save the pointer to the end of the string
ld e,a
ld d,-100
call atof24_scrap_times_256
push bc
call atof24_scrap_times_256
push bc
call atof24_scrap_times_256
pop hl
pop de
ld h,e
;HLC holds the 3-digit significand, need to normalize it
; make sure it isn't zero
ld a,c
or h
or l
jp z,atof24_zero
pop af
ld a,c
ld c,$7E ;0x3F * 2 because we'll be shifting down later
rr c
atof24_loop_3:
dec c
add a,a
adc hl,hl
jr nc,atof24_loop_3
; round
add a,a
jr nc,+_
inc l
jr nz,+_
inc h
jr nz,+_
inc c
_:
ex de,hl
;CDE * 10^B
xor a
sub b
jp p,atof24_small
ld a,b
cp 20
jr c,$+9
ld a,c
or %01111111
ld hl,0
ret
cp 10
jr c,atof24_mul
sub 10
push af
ld a,$60
ld hl,$2A06
jr atof24_continue
atof24_small:
cp 20
jr c,$+6
xor a
ld h,a
ld l,a
ret
cp 10
jr c,atof24_mul
ld a,b
add a,10
push af
ld a,$1D
ld hl,$B7CE
atof24_continue:
call f24mul
ex de,hl
pop bc
ld c,a
atof24_mul:
ld a,b
neg
add a,19
ld b,a
add a,a
add a,b
add a,(f24pow10_LUT+2)&255
ld l,a
adc a,(f24pow10_LUT+2)>>8
sub l
ld h,a
ld a,(hl)
dec hl
ld b,(hl)
dec hl
ld l,(hl)
ld h,b
;AHL * CDE
jp f24mul
atof24_str_eng_exp:
; HL points to the string, B is the current exponent, returns adjusted exponent in B
ld e,0
inc hl
ld a,(hl)
sub TOK_NEG ;negative exponent?
ld c,a ;backup result
jr nz,atof24_skip_5
jr atof24_skip_3
atof24_loop_2:
ld d,a ; save the digit to add
; make sure E doesn't exceed 2
ld a,e
cp 3
jr nc,atof24_eng_overflow
add a,a
add a,a
add a,e
add a,a ; E*10
add a,d ; E*10+D
ld e,a
atof24_skip_3:
inc hl
atof24_skip_5:
ld a,(hl)
sub '0'
cp 10
jr c,atof24_loop_2
ld a,e
cp 20
jr nc,atof24_eng_overflow
ld a,c
or a
ld a,b
jr nz,atof24_skip_4
sub e
.db $FE ; start of `cp *` to skip the next byte
atof24_skip_4:
add a,e
ld b,a
ret
atof24_scrap_times_256:
call atof24_scrap_times_16
atof24_scrap_times_16:
call atof24_scrap_times_4
atof24_scrap_times_4:
call atof24_scrap_times_2
atof24_scrap_times_2:
;EHL is a 3-digit base-100 number that needs to be multiplied by 256
; multiply the bottom 2 digits by 2
add hl,hl
; check for overflow
ld a,l
add a,d
jr nc,$+4
ld l,a
inc h
ld a,h
add a,d
jr nc,$+3
ld h,a
ld a,e
adc a,a
add a,d
jr c,$+3
sub d
ld e,a
rl c
ret
atof24_eng_overflow:
pop af ; pop off the return address for the call
ld a,c
or a
jr z,atof24_zero
atof24_inf:
;return inf
pop af
ld hl,0
ld a,-1
rra
ret
atof24_zero_check_eng:
cp TOK_ENG-'0'
jr nz,atof24_zero_write_hl
; otherwise, we need to read through the engineering exponent
inc hl
ld a,(hl)
cp TOK_NEG
jr nz,$+3
inc hl
ld a,(hl)
sub '0'
cp 10
jr c,$-6 ; jumps back to the `inc hl`
atof24_zero_write_hl:
ld (ptr_sto),hl ; save the pointer to the end of the string
atof24_zero:
pop af
xor a
ld h,a
ld l,a
ret
#endif