Jump to content
  • entries
    17
  • comments
    28
  • views
    32,103

Hex to Decimal (0-65535)


Omegamatrix

2,200 views

Continuing with my Hex to Decimal routines, I have written one for 16 bit numbers. :)

 

This routine is really geared toward a NES. The NES has no decimal mode. I think most of the time programmers will just break their scores out into multiple bytes (one for each digit), and then handle rollover cases for greater than 9, and less than 0.

 

Here we are dealing with the case where they do want to use just 2 bytes of ram to hold a score. The idea is to take 16 bit number and convert it back into the 5 temporary digits used for the score. The desired outcome is to be really quick (not spending 100's and 100's of cycles), while also not spending gobs and gobs of rom. Of course, a routine that is quick and short is desired in almost any situation. ;)

 

My routine takes 263 bytes, and does the job in 156 to 168 cycles. Stats are below:

;--------------------------------
;0-9999 conversion stats
;--------------------------------
;cycles          occurances
;156 - $0860 -->  2,144
;157 - 0
;158 - 0
;159 - $16C0 -->  5,824
;160 - 0
;161 - 0
;162 - $07F0 -->  2,032
;163 - 0
;164 - 0
;165 - 0
;166 - 0
;167 - 0
;168 - 0
;average execution is 158.97 cycles
;--------------------------------
;0-65535 conversion stats
;--------------------------------
;cycles          occurances
;156 - $1738 -->  5,944
;157 - 0
;158 - 0
;159 - $9528 --> 38,184
;160 - 0
;161 - 0
;162 - $2A30 --> 10,800
;163 - 0
;164 - 0
;165 - $1F18 -->  7,960
;166 - 0
;167 - 0
;168 - $0A58 -->  2,648
;average execution is 160.31 cycles
 

I like it when the best case and worse case execution times are close together. Here 0-9999 conversion gets done in 156-162 cycles, and 0-65535 gets done in 156-168 cycles. Both are pretty good.

 

Finally the routine:

CONVERT_TO_ASCII = 0
  IF CONVERT_TO_ASCII
ASCII_OFFSET = $30
  ELSE
ASCII_OFFSET = $00
  ENDIF

Times256_Low:
    .byte $00,$38,$0C,$44,$18,$50,$24,$5C
    .byte $30,$04,$3C,$10,$48,$1C,$54,$28
Times256_Med:
    .byte $00,$02,$05,$07,$0A,$0C,$0F,$11
    .byte $14,$17,$19,$1C,$1E,$21,$23,$26
Times16_Low:
    .byte $00
Times4096_Low:
    .byte $00
Times4096_Med:
    .byte $00
Times4096_High:
    .byte $00 + ASCII_OFFSET
    .byte $10,$60,$28,$00 + ASCII_OFFSET   ; interlaced tables, this allows less shifts to be made...
    .byte $20,$5C,$51,$00 + ASCII_OFFSET
    .byte $30,$58,$16,$01 + ASCII_OFFSET
    .byte $40,$54,$3F,$01 + ASCII_OFFSET
    .byte $50,$50,$04,$02 + ASCII_OFFSET
    .byte $60,$4C,$2D,$02 + ASCII_OFFSET
    .byte $0C,$48,$56,$02 + ASCII_OFFSET
    .byte $1C,$44,$1B,$03 + ASCII_OFFSET
    .byte $2C,$40,$44,$03 + ASCII_OFFSET
    .byte $3C,$3C,$09,$04 + ASCII_OFFSET
    .byte $4C,$38,$32,$04 + ASCII_OFFSET
    .byte $5C,$34,$5B,$04 + ASCII_OFFSET
    .byte $08,$30,$20,$05 + ASCII_OFFSET
    .byte $18,$2C,$49,$05 + ASCII_OFFSET
    .byte $28,$28,$0E,$06 + ASCII_OFFSET
ShiftedBcdTab
    .byte $00,$01,$02,$03,$04,$08,$09,$0A,$0B,$0C
    .byte $10,$11,$12,$13,$14,$18,$19,$1A,$1B,$1C
    .byte $20,$21,$22,$23,$24,$28,$29,$2A,$2B,$2C
    .byte $30,$31,$32,$33,$34,$38,$39,$3A,$3B,$3C
    .byte $40,$41,$42,$43,$44,$48,$49,$4A,$4B,$4C

StartHexToDec:
    lda    hexHigh               ;3  @3
    and    #$F0                  ;2  @5
    lsr                          ;2  @7
    lsr                          ;2  @9    carry is clear, shifting just 2 times instead of 4,
    tay                          ;2  @11   since interlaced tables are used.
    lda    hexHigh               ;3  @14
    and    #$0F                  ;2  @16
    tax                          ;2  @18
    lda    Times4096_High,Y      ;4  @22
    sta    decTenThousands       ;3  @25
    lda    Times4096_Low,Y       ;4  @29
    adc    Times256_Low,X        ;4  @33
    sta    temp                  ;3  @36
    lda    Times4096_Med,Y       ;4  @40
    adc    Times256_Med,X        ;4  @44
    tay                          ;2  @46
    lda    hexLow                ;3  @49
    and    #$F0                  ;2  @51
    lsr                          ;2  @53
    lsr                          ;2  @55
    tax                          ;2  @57
    tya                          ;2  @59
    cpx    #13*4                 ;2  @61   times 4 due to interlaced table
    adc    #0                    ;2  @63
    cpx    #7*4                  ;2  @65
    adc    #0                    ;2  @67
    tay                          ;2  @69   medByte
    lda    hexLow                ;3  @72
    and    #$0F                  ;2  @74
    adc    Times16_Low,X         ;4  @78
    adc    temp                  ;3  @81
    bcs    .sub100               ;2³ @83/84
    cmp    #100                  ;2  @85
    bcc    .skip1                ;2³ @87/88
.sub100:
    sbc    #100                  ;2  @89
    iny                          ;2  @91
.skip1:
    cmp    #100                  ;2  @93
    bcc    .skip2                ;2³ @95/96
    sbc    #100                  ;2  @97
    iny                          ;2  @99
.skip2:
    lsr                          ;2  @101
    tax                          ;2  @103
    lda    ShiftedBcdTab,X       ;4  @107
    tax                          ;2  @109
    rol                          ;2  @111
    and    #$0F                  ;2  @113
  IF CONVERT_TO_ASCII
    ora    #ASCII_OFFSET         ;2
  ENDIF
    sta    decOnes               ;3  @116
    txa                          ;2  @118
    lsr                          ;2  @120
    lsr                          ;2  @122
    lsr                          ;2  @124
  IF CONVERT_TO_ASCII
    ora    #ASCII_OFFSET         ;2
  ENDIF
    sta    decTens               ;3  @127
    tya                          ;2  @129
    cmp    #100                  ;2  @131
    bcc    .skip3                ;2³ @133/134
    sbc    #100                  ;2  @135
    inc    decTenThousands       ;5  @140
.skip3:
    lsr                          ;2  @142
    tay                          ;2  @144
    lda    ShiftedBcdTab,Y       ;4  @148
    tay                          ;2  @150
    rol                          ;2  @152
    and    #$0F                  ;2  @154
  IF CONVERT_TO_ASCII
    ora    #ASCII_OFFSET         ;2
  ENDIF
    sta    decHundreds           ;3  @157
    tya                          ;2  @159
    lsr                          ;2  @161
    lsr                          ;2  @163
    lsr                          ;2  @165
  IF CONVERT_TO_ASCII
    ora    #ASCII_OFFSET         ;2
  ENDIF
    sta    decThousands          ;3  @168
 

ASCII output can be built into the routine at a cost of 8 more bytes and 8 more cycles.

 

 

Test rom and source below. Note this rom is for the 2600, not the NES. The screen stays black for several seconds while it is running, and then a green passed screen appears.

 

HexToDec(16bit).zip

 

blogentry-7074-0-40407700-1402188591_thumb.png

 

 

 

 

0 Comments


Recommended Comments

There are no comments to display.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...