#ifndef included_atof32
 
#define included_atof32
 
#include "f32mul.z80"
 
#include "ascii_to_BCD.z80"
 
#include "ascii_to_BCD.z80"
 
#include "f32_pow10_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
 
atof32:
 
;Inputs:
 
;  HL points to the string
 
;  BC points to where to write the float
 
;Output:
 
;  AHL is the f32 float
 
;  scrap is the pointer to the end of the string
 
;Destroys:
 
;  BC, DE
 
;  2 bytes at scrap
 
;
 
;
 
  call pushpop
 
  push bc ; save the pointer to the output
 
;Check for a negative sign, save for later, and advance the pointer if so.
 
;   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,atof32_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
 
atof32_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,atof32_zero_check_eng
 
  srl c
 
 
 
;Now we read in the next 8 digits. Ideally, we want 27 bits worth, but 8 digits
 
; gives us about 26.5 bits
 
  call ascii_to_BCD
 
  ld d,a
 
  call ascii_to_BCD
 
  ld e,a
 
  push de
 
  call ascii_to_BCD
 
  ld d,a
 
  call ascii_to_BCD
 
  ld e,a
 
 
 
;Now `scrap` holds the 4-digit base-100 number (little-endian)
 
;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
 
atof32_loop_1:
 
  ld a,(hl)
 
  cp TOK_DECIMAL
 
  jr nz,$+8
 
  dec c
 
  jp pe,atof32_skip_7 ; we've reached our first decimal
 
  jr atof32_skip_2    ; else C was already FF, then a decimal was already encountered
 
 
 
  sub '0'
 
  cp 10
 
  jr nc,atof32_skip_6
 
; carry flag is set
 
atof32_skip_7:
 
  inc hl
 
  ld a,b
 
  adc a,c
 
  ; if carry flag is set, then we added 0
 
  jr c,atof32_loop_1
 
  jp z,atof32_inf2
 
  ld b,a
 
  jr atof32_loop_1
 
 
 
atof32_skip_6:
 
  ld a,(hl)
 
;Now check for engineering `E` to modify the exponent
 
  cp TOK_ENG
 
  call z,atof32_str_eng_exp
 
 
 
atof32_skip_2:
 
  ld (ptr_sto),hl ; save the pointer to the end of the string
 
  pop hl
 
  ex de,hl        ; DEHL is the number
 
 
 
  push bc         ; B is the base-10 exponent
 
  call atof32_scrap_times_256
 
  ld b,c
 
  call atof32_scrap_times_256
 
  push bc         ; BC is the upper 16 bis of the result
 
  call atof32_scrap_times_256
 
  ld b,c
 
  call atof32_scrap_times_256
 
  pop de
 
  ld h,b
 
  ld l,c
 
  ; DEHL is 32 bits of the significand
 
  pop bc  ; B is the base-10 exponent
 
 
 
;HLC holds the 3-digit significand, need to normalize it
 
; make sure it isn't zero
 
  ld a,e
 
  or d
 
  or l
 
  or h
 
  jp z,atof32_zero
 
 
 
 
 
  ld c,$7E
 
  ld a,d
 
  or a
 
  jr atof32_loop_3_start
 
atof32_loop_3:
 
  dec c
 
  add hl,hl
 
  rl e
 
  adc a,a
 
atof32_loop_3_start:
 
  jp p,atof32_loop_3
 
 
 
  add a,a
 
  ld d,a
 
  pop af
 
  rr c
 
  rr d
 
 
 
; round
 
  sla l
 
  jr nc,+_
 
  inc h
 
  jr nz,+_
 
  inc e
 
  jr nz,+_
 
  inc d
 
  jr nz,+_
 
  inc c
 
_:
 
;CDEH * 10^B
 
 
 
; write the float in CDEH to the output
 
  ld a,h
 
  pop hl
 
  ld (hl),a
 
  inc hl
 
  ld (hl),e
 
  inc hl
 
  ld (hl),d
 
  inc hl
 
  ld (hl),c
 
  dec hl
 
  dec hl
 
  dec hl
 
 
 
; now multiply the float at HL by 10^B
 
  xor a
 
  sub b
 
  ld de,f32_pown10_LUT
 
  jp p,$+7
 
  ld a,b
 
  ld de,f32_pow10_LUT
 
 
 
  cp 38
 
  jr c,$+4
 
  ld a,-1
 
 
 
  ld b,h
 
  ld c,l
 
  call atof32_mul_first
 
  call atof32_mul_twice
 
atof32_mul_twice:
 
  call atof32_mul_once
 
atof32_mul_once:
 
  inc de
 
  inc de
 
  inc de
 
  inc de
 
atof32_mul_first:
 
  rra
 
  call c,f32mul
 
  ret
 
 
 
atof32_str_eng_exp:
 
; HL points to the string, B is the current exponent, returns adjusted exponent in B
 
  push de   ; save lower digits of input
 
  ld e,0
 
  inc hl
 
  ld a,(hl)
 
  sub TOK_NEG   ;negative exponent?
 
  ld c,a        ;backup result
 
  jr nz,atof32_skip_5
 
  jr atof32_skip_3
 
atof32_loop_2:
 
  ld d,a  ; save the digit to add
 
 
 
; make sure E doesn't exceed 3 (else the exponent is over 40)
 
  ld a,e
 
  cp 4
 
  jr nc,atof32_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
 
 
 
atof32_skip_3:
 
  inc hl
 
atof32_skip_5:
 
  ld a,(hl)
 
  sub '0'
 
  cp 10
 
  jr c,atof32_loop_2
 
 
 
  ld a,e
 
  cp 60
 
  jr nc,atof32_eng_overflow
 
  ld a,c
 
  or a
 
  ld a,b
 
  jr nz,atof32_skip_4
 
  sub e
 
  .db $FE  ; start of `cp *` to skip the next byte
 
atof32_skip_4:
 
  add a,e
 
  ld b,a
 
  pop de
 
  ret
 
 
 
atof32_scrap_times_256:
 
  call atof32_scrap_times_16
 
atof32_scrap_times_16:
 
  call atof32_scrap_times_4
 
atof32_scrap_times_4:
 
  call atof32_scrap_times_2
 
atof32_scrap_times_2:
 
;DEHL 8 BCD digits, need to multiply by 2
 
  ld a,l
 
  add a,a
 
  daa
 
  ld l,a
 
 
 
  ld a,h
 
  adc a,a
 
  daa
 
  ld h,a
 
 
 
  ld a,e
 
  adc a,a
 
  daa
 
  ld e,a
 
 
 
  ld a,d
 
  adc a,a
 
  daa
 
  ld d,a
 
 
 
  rl c
 
  ret
 
 
 
atof32_inf2:
 
  ld c,-1
 
atof32_eng_overflow:
 
  pop de  ; pop off saved digits
 
  pop af  ; pop off the return address for the call
 
  pop hl  ; pop off the other saved digits
 
  ld a,c
 
  or a
 
  jr z,atof32_zero
 
atof32_inf:
 
;return inf
 
  pop af
 
  pop hl
 
  ld a,0
 
  ld (hl),a
 
  inc hl
 
  ld (hl),a
 
  inc hl
 
  ld (hl),a
 
  dec a
 
  rra
 
  rr (hl)
 
  inc hl
 
  ld (hl),a
 
  ret
 
 
 
atof32_zero_check_eng:
 
  cp TOK_ENG-'0'
 
  jr nz,atof32_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`
 
atof32_zero_write_hl:
 
  ld (ptr_sto),hl ; save the pointer to the end of the string
 
atof32_zero:
 
  pop af
 
  pop hl
 
  ld a,0
 
  ld (hl),a
 
  inc hl
 
  ld (hl),a
 
  inc hl
 
  ld (hl),a
 
  inc hl
 
  rra
 
  ld (hl),a
 
  ret
 
#endif