Login

Subversion Repositories NedoOS

Rev

Rev 1485 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

 ifndef included_strtox
 define included_strtox
 include "../common/mov.asm"
 include "../common/pushpop.asm"
 include "routines/sla64.asm"
 ;include "routines/ascii_to_uint8.asm"
 include "../common/ascii_to_uint8.asm"
 include "tables.asm"
 include "constantsx.asm"
 include "xmul.asm"

 ifndef char_TI_TOK
char_NEG='-';$1A
char_ENG='e';$1B
char_DEC='.'
 else
;otherwise, char_TI_CHR
char_NEG=$B0
char_ENG=$3B
char_DEC=$3A
 endif

;#ifndef strtox_ptr
strtox_ptr=xOP1+25 ;FIXME
;#endif
strtox:
;;#Routines/Extended Precision
;;Inputs:
;;  HL points to the string
;;  BC points to where the float is output
;;Output:
;;  xOP1+25 is the pointer to the end of the string
;;Destroys:
;;  25 bytes at xOP1 ?
  call pushpop
  push bc

;Check if there is a negative sign.
;   Save for later
;   Advance ptr
  ld a,(hl)
  sub char_NEG
  sub 1
  push af
  jr nc,$+3;+_
  inc hl
;_:
  call strtox_sub0
TItox_stepin:
;bc=exp-1
;Gotta multiply the number at (xOP1) by 2^64

;Save the location of the ending byte of the string
  ld (strtox_ptr),hl
  ld d,100
  call xOP1_xtimes_256
  ld (xOP1+17),a
  call xOP1_xtimes_256
  ld (xOP1+16),a
  call xOP1_xtimes_256
  ld (xOP1+15),a
  call xOP1_xtimes_256
  ld (xOP1+14),a
  call xOP1_xtimes_256
  ld (xOP1+13),a
  call xOP1_xtimes_256
  ld (xOP1+12),a
  call xOP1_xtimes_256
  ld (xOP1+11),a
  call xOP1_xtimes_256
  ld (xOP1+10),a
  call xOP1_xtimes_256
  ld (xOP1+9),a

;Now xOP1+9 is a 9-byte mantissa that needs to be normalized
;
  ld hl,(xOP1+10)
  or h
  or l
  ld hl,(xOP1+12)
  or l
  or h
  ld hl,(xOP1+14)
  or h
  or l
  ld hl,(xOP1+16)
  or l
  or h
  jp z,strtox_zero-1
  pop af
  push bc
  ld bc,$7FFF
  rr b
  ld a,h
  or a
  jp m,strtox_normed
  ;Will need to iterate at most three times
strtox_norm0;_:
  dec bc
  ld hl,xOP1+9
  call sla64
  adc a,a
  jp p,strtox_norm0;-_
strtox_normed:
;Move the number to xOP1
  ld hl,(xOP1+10)
  ld (xOP1),hl
  ld hl,(xOP1+12)
  ld (xOP1+2),hl
  ld hl,(xOP1+14)
  ld (xOP1+4),hl
  ld hl,(xOP1+16)
  ld h,a
  ld (xOP1+6),hl
  ld (xOP1+8),bc
  pop bc
;now (xOP1) is our number, need to multiply by power of 10!
;Power of 10 is stored in BC, need to put in A first
  xor a
  or b;sub b ;Alone Coder
  ld de,pow10table+120
  jp p,strtox_powp;+_
  xor a : sub c : ld c,a
  sbc a,a : sub b : ld b,a
  ld de,pown10table+120
strtox_powp;_:
  ld hl,xOP1
strtox_muls0;_:
  srl b
  rr c
  call strtox_mul;+_
  ld a,b
  or c
  jr nz,strtox_muls0;-_
  pop de
  jp mov10
strtox_mul;_:
  push bc
  ld b,h
  ld c,l
  call c,xmul
  pop bc
  ld a,e
  sub 10
  ld e,a
  ret nc
  dec d
  ret

strtox_sub00;_:
  inc hl
strtox_sub0:
;Skip all leading zeroes
  ld a,(hl)
  cp '0'
  jr z,strtox_sub00;-_

;Set exponent to 0
  ld bc,0
;Check if the next char is char_DEC
  sub char_DEC
  or a
  jr nz,strtox_skipzeroesq;+_
  inc c
;Get rid of zeroes
  ld a,'0'
  cpi
  jr z,$-2
  scf
strtox_skipzeroesq;_:
;Now we read in the next 20 digits
  ld de,xOP1+9
  push bc
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  call ascii_to_uint8
  ld a,b
  pop bc
  push af
  add a,c
  ld c,a
  jr nc,$+3
  inc b
  pop af
;Now `xOP1` holds the 10-digit base-100 number.
;BC 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
  call skipdigits
;Now check for engineering `E` to modify the exponent
  cp char_ENG-'0'
  ret nz
str_xeng_exp:
  ld de,0
  inc hl
  ld a,(hl)
  cp char_NEG    ;negative exponent?
  push af
  jr nz,$+3
  inc hl
str_xeng_exp0;_:
  ld a,(hl)
  sub 3Ah
  add a,10
  jr nc,str_xeng_expq;+_
  inc hl
  push hl
  ld h,d
  ld l,e
  add hl,hl
  add hl,hl
  add hl,de
  add hl,hl
  add a,l
  ld l,a
  ex de,hl
  pop hl
  jr str_xeng_exp0;-_
str_xeng_expq;_:
  ld a,d
  cp 20
  jp nc,xeng_overflow
  pop af
  ld a,c
  jr nz,str_xeng_add;+_
  sub e
  ld c,a
  ld a,b
  sbc a,d
  ld b,a
  ret
str_xeng_add;_:
  add a,e
  ld c,a
  ld a,d
  adc a,b
  ld b,a
  ret

xOP1_xtimes_256:
  push bc
  ld e,8
xOP1_xtimes_2560;_:
  or a
  ld hl,xOP1
  call xOP1_xtimes_256pp;+_
  call xOP1_xtimes_256pp;+_ ;╨╕╤В╨╛╨│╨╛ 10 ╤А╨░╨╖ xOP1_xtimes_sub
  rl c
  dec e
  jr nz,xOP1_xtimes_2560;-_
  ld a,c
  pop bc
  ret
xOP1_xtimes_256pp;_:
  call xOP1_xtimes_sub
  call xOP1_xtimes_sub
  call xOP1_xtimes_sub
  call xOP1_xtimes_sub
xOP1_xtimes_sub:
  ld a,(hl)
  rla
  cp d
  jr c,$+2+1;+_
  sub d
;_:
  ld (hl),a
  inc hl
  ccf
  ret
xeng_overflow:
  pop af
  jr nz,strtox_inf
  pop af
strtox_zero:
  ld hl,xconst_0
  pop de
  jp mov10
strtox_inf:
;return inf
  pop af
  ld hl,xconst_INF
  jr nc,$+2+3;+_
  ld hl,xconst_nINF
;_:
  pop de
  jp mov10


skipdigits:
  jr nc,skipdigits_nodec
  db $FE     ; start of `cp *` to skip the `inc hl`
skipdigits0;_:
  inc hl
  ld a,(hl)
  sub '0'
  cp 10
  jr c,skipdigits0;-_
  ret

skipdigits_nodec0;_:
  inc hl
  inc bc
skipdigits_nodec:
  ld a,(hl)
  sub '0'
  cp 10
  jr c,skipdigits_nodec0;-_
  ret
 endif