   .include #macros
   .include #16bit

   .if .not .def TEST
      .zext    _string1
      .zext    _value
      .zext    _tmp1
      .zext    _tmp2
      .zext    _tmp3
   .else

      .include #cio

_string1 = $F0
_value   = $F2
_tmp1    = $F4
_tmp2    = $F6
_tmp3    = $F8


main:
      dpoke    _value,2456
      dpoke    _string1,buffer
      jsr      utoa
      poke     buffer+5,155
      print    0,header,255,@p1+@p2+@p3
      dpoke    _value,40001
      dpoke    _string1,buffer
      jsr      utoa
      poke     buffer+5,155
      print    0,header,255,@p1+@p2+@p3
      brk


header:
      .byte    "Value = "
buffer:
      .ds      6

      .endif
;; -------------------------------------------------------------
;; utoa:
;; Convert a unsigned word into ASCII.
;; Parameters via zeropage STRING1 and VALUE. Needs also
;; 6 bytes of temporary zeropage storage. String will end
;; with a (char *) 0. (That's a binary 0 not a '0')
;; returns:
;;    _STRING1 contains the converted string (always 5 digits)
;;    Y        contains last index (usually 6)
;; -------------------------------------------------------------
:digits.wl
   .byte <10,<100,<1000,<10000
:digits.wm
   .byte >10,>100,>1000,>10000
:table.wl
   .byte <50,<500,<5000,<30000
:table.wm
   .byte >50,>500,>5000,>30000
:table.b
   .byte 5,5,5,3
:table2.b
   .byte 9,9,9,6


utoa:
   ldy   #0
_utoa:
   sty   _tmp3
   ldy   #3
:loop
   lda   :digits.wl,y         ; fill _tmp2 with 10000 1000 100 or 10
   sta   _tmp2
   lda   :digits.wm,y
   sta   _tmp2+1

   lda   :table.wl,y          ; fill _tmp1 with 30000 5000 500 or 50
   sta   _tmp1
   lda   :table.wm,y
   sta   _tmp1+1

   lda   :table.b,y
   tax

:justadded
   poke  _tmp3+1,0            ; last time we added ...

:next
   cmp.w _tmp1,_value,0       ; if the user _value is larger than
   bcs   :more                ; _tmp1 then add 10000 1000 100 or 10 to it

:less
   sbc.w _tmp2,_tmp1,0        ; else subtract 10000 1000 100 or 10 from it
   dex                        ; did we add the last time around ??
   stx   _tmp3+1              ; set _tmp3 + 1, to remember we just subbed
   bne   :next                ; if 0 it's much too low apparently
   beq   :xdone

:more
   lda   _tmp3+1              ; did we subtract last time ?
   bne   :done                ; Yup! than we found it.
   txa
   cmp   :table2.b,y          ; if we have been @ end
   bcs   :done                ; then leave ->
   inx
   adc.w _tmp2,_tmp1,@special ; else add 10000 1000 100 or 10
   bcc   :justadded           ; can't overflow

:done
   sbc.w _tmp1,_value,@special; now strip that off _value

:xdone
   tya                        ; save Y register
   pha
   txa                        ; get result in A
   clc
   adc   #'0                  ; add ASCII '0 to it
   ldy   _tmp3
   sta   (_string1),y
   inc   _tmp3

   pla
   tay
   dey
   bpl   :loop

   lda   _value
   adc   #'0
   ldy   _tmp3
   sta   (_string1),y
   iny
   lda   #0
   sta   (_string1),y
   iny
   rts

