I've seen others in various romhacking posts and other places avoid writing routines that convert binary numbers to decimal to display results of calculations or otherwise on screen. Any decent game needs to do this really and it's not all that hard to do. One will note that professional games rarely store values in RAM using BCD format as it would use up a lot of extra memory.
The way to do this very quickly is an algorithm called Shift and Add-3 or "double dabble"
It's not that hard to explain in pseudocode:
Edit: so much for pseudo code.... I basically recalled the entire ASM from memory while house sitting and am away from the computer I actually write code on... o_O
1. start with your binary number padding with 3 nybbles or so for every 3 bits (or portion) of input (or you know that a 32-bit unsigned 4 byte integer has a max value of 4.29 billion and requires 10 digits hence 10 nybbles).
That's the original binary value with zero bytes (10 nybbles after it):
in0 in1 in2 in3 nyb01 nyb23 nyb45 nyb67 nyb89 = 9 bytes
B2D_DIGITS = 10 bytes (stick this somewhere in wram or bw-ram)
we're going to use 16-bit operations so let's pad that odd byte with a 00
in0 in1 in2 in3 nyb01 nyb23 nyb45 nyb67 nyb89 00 = 10 bytes
clear nyb00 thru to the pad byte after nyb89 inclusive
; precondition: in0 thru in3 are set to the 32-bit value to convert
; -- pad lesser sizes (ie: bytes, words, 24-bit ptrs) with $00 in higher order inX values)
- ldx.w #$09
set the shift count to 0:
stz B2D_SHIFTCOUNT ; just define this to be somewhere in WRAM (or BW-RAM if you use SA-1)
2. shift everything left starting from in0,in1 and working towards nyb89 00
rol in0 ; +in1
rol in2 ; +in3
rol nyb01 ; +nyb23
rol nyb45 ; +nyb67
rol nyb89 ; +00
3. count this shift. we are done if this is 32nd shift.
4. now the fun part... we scan each byte in nyb01 thru nyb89 for nybbles >= 5 and add 3 any that are
instead of trying to mess with a whole shwak of logic ops shifts, pushes, pops, etc I used a lookup table to shirnk it down to only a few instructions, the most complicated being to turn the read nybbles into a pointer value (in my code I tend to leave the index regs at 16 bits. The 160-byte lookup table will be described at the end). NB: The order you do the adds does not matter only that you check every
- lda nyb01,y
xba ; makes xxnn into 00nn
5. Repeat for remaining shifts
6. Technically we are done the heavy part but these will be awkward to use in printing functions and they will need to unpack the nybbles to display text so we may as well do the unpacking in the same routine:
; we will unpack so the MSB digits come first as humans would read them
ldx.w #9 ; points to digit to store lsd
ldy.w #0 ; points to nybbles lsb
- lda nyb01,y
lsr : lsr : lsr : lsr
7. That's all, folks
The look up table:
first 16 bytes the table looks as follows (based on a truth table for shift and add-3)
For the table I've zeroed the unreachable entries (it needs to be padded to 16 bytes)
this is the horizontal part of the table that takes care of the low nybble...
now we repeat the pattern with the upper nybble counting the same pattern vertically:
You can safely lose the last six 00 bytes on the final ($cx) row, making this a 154-byte table.
There now everyone should be able to write their players' experience and money to the screen in decimal rather than hex