Depends on your definition of "best". I've found your approach the simplest as well. Just set up a table of the 16-bit values and loop through.
Here's the version written for clarity and simplicity (that means little attempt at optimization, as that wasn't a stated goal):
Code:
binary: .res 2 ; 16-bit unsigned input value
decimal: .res 5 ; output decimal digits, one per byte, natural order
; Converts 16-bit binary to 5-digit decimal.
bin_to_dec:
ldx #0
@digit:
ldy #0
; Just compare first time through loop
jmp @compare
@increment:
iny
; Subtract weight from binary
sec
lda binary
sbc lsb,x
sta binary
lda binary+1
sbc msb,x
sta binary+1
@compare:
; Compare binary to digit weight
sec
lda binary
sbc lsb,x
lda binary+1
sbc msb,x
; Increment digit if binary >= weight
bcs @increment
sty decimal,x
inx
cpx #5
bne @digit
rts
lsb: .byte <10000,<1000,<100,<10,<1
msb: .byte >10000,>1000,>100,>10,>1
Here's a variation that's a little more compact and faster, as it merges the compare and subtract; it's still not meant for speed, since there are far faster algorithms:
Code:
bin_to_dec:
ldx #0
@digit:
lda #0
sta decimal,x
jmp @subtract
@increment:
inc decimal,x
; Commit new value
sta binary+1
sty binary
@subtract:
; Subtract digit weight from binary, but don't commit
sec
lda binary
sbc lsb,x
tay
lda binary+1
sbc msb,x
; Loop if subtraction didn't wrap binary around
bcs @increment
inx
cpx #5
bne @digit
rts
lsb: .byte <10000,<1000,<100,<10,<1
msb: .byte >10000,>1000,>100,>10,>1
Both routines have been decently tested with edge-case values.