Login

Subversion Repositories NedoOS

Rev

Blame | Last modification | View Log | Download | RSS feed

#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