|
here's a routine I cooked up a while ago that can take either an 8-bit or 16-bit number and output decimal versions into memory (one decimal digit per byte of memory, which could then be added with the tile # of the "0" to be put on-screen). it even counts up the number of significant digits, which you could use when writing to the screen (so 16 wouldn't be written as 016 or 00016).
it works by looking at each bit and if set, performing a decimal math operation "by hand" using a table of decimal values.
anyhow, I just thought I'd throw this out there for you to use if you'd like, or if you have any suggestions on how to optimize it or make it less "hackish", I'm definetely open to them. I've used this before, and it works.
here goes:
hex2dec_d4: .db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3 hex2dec_d3: .db 0,0,0,0,0,0,0,0,0,0,1,2,4,8,6,2 hex2dec_d2: .db 0,0,0,0,0,0,0,1,2,5,0,0,0,1,3,7 hex2dec_d1: .db 0,0,0,0,1,3,6,2,5,1,2,4,9,9,8,6 hex2dec_d0: .db 1,2,4,8,6,2,4,8,6,2,4,8,6,2,4,8
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; HEX2DEC8 / HEX2DEC16 ; ; ; ; Converts hex numbers to decimal and counts digits. ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; HEX2DEC8 (converts 8-bit hex to 3-digit decimal) ; ; ; ; In: A (number to be converted) ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; HEX2DEC16 (converts 16-bit hex to 5-digit decimal) ; ; ; ; In: A (low byte of number to be converted) ; ; X (high byte ") ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; ; Out: OUT.0 - OUT.4 (the converted number) ; ; DIGITS (digit count; 1 = 1-digit, etc) ; ; ; ; Modifies: A, X, IN.0, IN.1, OUT.0 - OUT.4 ; ; ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
hex2dec8: ldx #0 hex2dec16: sta IN.0 stx IN.1 ldx #0 stx OUT.0 stx OUT.1 stx OUT.2 stx OUT.3 stx OUT.4
do_hex2dec: lsr IN.1 ror IN.0 bcc hex2dec_no_add lda OUT.0 adc hex2dec_d0,x cmp #10 bcs no_d0_carry sec sbc #10 inc OUT.1 no_d0_carry: sta OUT.0 lda OUT.1 adc hex2dec_d1,x cmp #10 bcs no_d1_carry sec sbc #10 inc OUT.2 no_d1_carry: sta OUT.1 lda OUT.2 adc hex2dec_d2,x cmp #10 bcs no_d2_carry sec sbc #10 inc OUT.3 no_d2_carry: sta OUT.2 lda OUT.3 adc hex2dec_d3,x cmp #10 bcs no_d3_carry sec sbc #10 inc OUT.3 no_d3_carry: sta OUT.3 lda OUT.4 adc hex2dec_d4,x sta OUT.4 hex2dec_no_add: inx cpx #5 bne do_hex2dec
digit_count: dex cpx #$FF bne digit_count_continue ldx #1 jmp digit_count_finished digit_count_continue: lda OUT.0,x beq digit_count digit_count_finished: stx DIGITS rts
I copied-and-pasted it right out of some code I wrote, I only edited out the "<"s which NESASM seems to require for zero-page addressing (otherwise it'll use 16-bit addressing in the assembled code... go figure).
The DIGITS-counting routine will return 1 if the resulting number was all zeroes, so at least the one "0" will be printed.
note that the decimal number is output backwards (eg., for a number "123", OUT.0 = 3, OUT.1 = 2, OUT.2 = 1, OUT.3 = 0, OUT.4 = 0), so to read it, you'd do something like this:
print_decimal: ldx DIGITS print_decimal_2: lda OUT.0 - 1,x adc #PATTERN_TABLE_TILE_OF_NUMBER_ZERO sta $2007 dex bne print_decimal_2 rts
That could be modified to align numbers to the right by explicitly doing 'LDX #5' and then writing a blank tile if X>DIGITS, but I don't feel like doing that now. :)
The whole routine could be modified to do even larger numbers (24-bit hex to 8-digit decimal, for example), but it'd be even more hackish; plus, some of the branches may be too long, which would require taking out the body of the code and moving it elsewhere, and JSRing to it or something.
Anyhow, that's that. Any thoughts?
...just another vision... Studios
|