Just roll out bit by bit from the binary number, and for each bit set, add the BCD power of two to an ackumulating BCD sum. For best speed, use a table of BCD powers of two. For good speed and saving memory, calculate the next BCD power of two by adding the current to itself. (For 32 bit numers, you would need a table of 32*5 bytes; 32 powers of two, 10 digits each.)
Code: Select all
bcdsize = 5 ;number of bytes to hold BCD number
;(number of decimal digits / 2)
binsize = 4 ;number of bits / 8
sei
sed
lda #$40
sta vflag_Set ;zero page location
;clear BCD power of 2 variable & BCD ackumulator:
ldx #bcdsize
lda #0
clr sta bcdpow2-1.x
sta bcdackum-1.x
dex
bne clr
lda #1
sta bcdpow2+bcdsize-1 ;start with 2^0
loop
;shift out next bit
ldx #binsize
bit vflag_set ;sets the overflow flag
clc
shift ror binnumber-1.x
beq @zero
clv ;overflow flag cleared if any byte was nonzero
zero dex
bne shift
bcc noadd ;no adding this time?
;add current BCD power of 2 to BCD ackumulator
ldx #bcdsize
clc
add lda bcdpow2-1.x
adc bcdackum-1.x
sta bcdackum-1.x
dex
bne add
clv ;overflow flag not reliable after BCD arithmetic
noadd bvs exit
;calculate next BCD power of 2
clc
ldx #bcdsize
double
lda bcdpow2-1.x
adc bcdpow2-1.x
sta bcdpow2-1.x
dex
bne double
beq loop
exit
cld
cli
rts
The interrupt flag has to be set whenever the decimal flag is set, or the interrupt routine will go nuts. Don't forget to clear the flag!
For faster loop execution, the BCD numbers are stored "backwards" compared to normal binary numbers, i.e. the most significant digits comes first, and the loop index counts backwards to avoid an CPX instruction (which would discard the carry).
You can easily increase the sizes of the numbers to very large ones. The execution time increases (almost) linearly with the number of bits/digits. Just make sure that the largest possible binary numer fits into the number of BCD pairs that you specify.
This method could easily be adopted to floating point numbers. When printing it to screen, just insert a period where appropriate.