Converting Hexadecimal to Decimal Numbers
Numbers in the NES are stored as 8-bit binary values, usually represented via the hexadecimal number system. This is all well and good, except when it comes time to show those numbers to the player. 0 through 9 are fine, but we'd rather display 10 and 11 than A and B.
So before we can display things like scores, lives, experience points, and gold, we need to convert those values' hex representations into their decimal equivalents. Unfortunately, the NES lacks any built-in capability for doing so. Fortunately, there are any number of clever algorithms to do it for us. Here's one of them. (Note: this only works for positive numbers!)
To begin, we'll need to reserve seven bytes in the zero page. The first two store the high and low bytes of the hex value we're converting. The other five each store a single digit of our decimal output, enabling us to store any value from 0 to 99,999 (though 16 bits will max out at 65,535).
.segment "ZEROPAGE"
hex_value: .res 2
ascii_result: .res 5 Let's move on to the code. Make sure to import those zero page values. Next, we'll create a table in the read-only data portion of memory. This table stores the decimal representations of each hex number, and will be accessed via table offsets as we lop each bit off our hex value. Notice how each five-byte row of the table represents a power of two, and there are sixteen rows in total—one for each digit of the starting value.
.segment "RODATA"
decimal_table:
.byte 0,0,0,0,1
.byte 0,0,0,0,2
.byte 0,0,0,0,4
.byte 0,0,0,0,8
.byte 0,0,0,1,6
.byte 0,0,0,3,2
.byte 0,0,0,6,4
.byte 0,0,1,2,8
.byte 0,0,2,5,6
.byte 0,0,5,1,2
.byte 0,1,0,2,4
.byte 0,2,0,4,8
.byte 0,4,0,9,6
.byte 0,8,1,9,2
.byte 1,6,3,8,4
.byte 3,2,7,6,8 And finally, the subroutine itself. A key thing to remember is that the zero-page variable hex_value must already be set with whatever we want
to convert before this subroutine is called.
.proc hex_to_ascii
LDA #$00
LDY #$04
clear:
STA ascii_result,y
DEY
BNE clear
LDX #$4F
loop1:
CLC
ROL hex_value
ROL hex_value+1
BCS calculate
TXA
SEC
SBC #$05
TAX
BPL loop1
RTS
calculate:
CLC
LDY #$04
loop2:
LDA decimal_table,x
ADC #$00
BEQ zero
ADC ascii_result,y
CMP #$0a
BCC notten
SBC #$0A
notten:
STA ascii_result,y
zero:
DEX
DEY
BPL loop2
JMP loop1
.endproc