Binary coded decimal
Original here
No idea if this sort of thing has been posted before, but I wrote this for displaying scores in 2048
and figured it might be useful to somebody.

One method for display numbers that take more than 16 bits is to convert it to Binary Coded Decimal
first, and display the result. BCD works by using four bits to store each decimal (base 10) digit of
a number. The following code can convert a number to BCD, and display it. It's currently written to
convert a 24 bit number to a 10 digit BCD number, but can be modified to support anything really. It
is memory ineffecient, because it uses one byte for each digit rather than storing two digits per
byte. This is useful though because it makes the display routine simpler.

Conversion to BCD

This routine converts a little endian value to a little endian BCD value

Code:
``` ;Converts a 24 bit unsigned int pointed to by HL to BCD ;Convert to BCD with double dabble method, see http://en.wikipedia.org/wiki/Double_dabble ;Handles up to a 10 digit number ;Input: HL - pointer to number ;Output: bcdScratch - stores BCD number. NUM_DIGITS = 10 NUM_SRC_BYTES = 3 .var NUM_DIGITS, bcdScratch .var NUM_SRC_BYTES, bcdSource ConvertToBCD:     ld de,bcdSource     ld bc,NUM_SRC_BYTES     ldir     ld ix,bcdSource     xor a     ld hl,bcdScratch     ld b,NUM_DIGITS _zeroScratch:     ld (hl),a     inc hl     djnz _zeroScratch     ld b,NUM_SRC_BYTES * 8     _bcdConvLp:         ;Do increment         ld c,NUM_DIGITS         ld hl,bcdScratch         ;Iterate through each BCD digit.         ;If digit > 4, add 3         _bcdIncLp:             ld a,(hl)             cp 5             jr c,{@}             add a,3             @:             ld (hl),a             inc hl             dec c             jr nz,_bcdIncLp         ;Shift SRC bits         sla (ix)         .for _off, 1, NUM_SRC_BYTES - 1             rl (ix + _off)         .loop         ld c,NUM_DIGITS         ld hl,bcdScratch         _bcdShiftLp:             ld a,(hl)             rla             bit 4,a             jr z,{@}             and %1111 ;Mask out high bits, since we only want the lower 4 bits for the digit             scf       ;Set carry if bit 4 set             @:             ld (hl),a             inc hl             dec c             jr nz,_bcdShiftLp         djnz _bcdConvLp     ret ```

Displaying BCD

Displaying BCD is quite simple, since each digit is stored within its own byte. You can simply add
the char code for '0' to the value to get the text char you want. This routine displays an unsigned

Code:
``` ;Displays the BCD value at HL ;1 byte per digit NUM_DIGITS = 10 DispBCD:     ld de,NUM_DIGITS - 1     add hl,de ;Go to end     ;Skip leading zeroes, except if the value IS zero     ld b,NUM_DIGITS - 1 _skipLeadingZeroes:     ld a,(hl)     or a     jr nz,{@}     dec hl     djnz _skipLeadingZeroes @:     inc b ;B = num digits to display _dispBCDDigits:     ld a,(hl)     add a,'0'     push hl     push bc     ;Replace this with anything that takes a char code in 'A' and displays it     b_call(_VPutMap)     pop bc     pop hl     dec hl     djnz _dispBCDDigits     ret ```

In case anyone was wondering, no, this is not a heavily optimized routine. I tried to make it at least somewhat clear what the code was doing rather than hyper-optimize it.
This is fantastic! It is extremely helpful for displaying sprite data as well. Great resource!
I have a routine that converts a number in E:HL into a string in decimal. It zero-pads it to a fixed size, 7 digits I think. It writes the string to IX. I believe that, despite the subfunction names divf and div, it doesn't actually do true division, but instead subtracts repeatedly, until the selected digit is zero. It should be fairly fast, at least faster than any routine using a general-purpose divide. At a glance, I can't tell if it's any faster than your algorithm. At any rate, this is highly dependent on the exact value being converted; it's considerably faster for a number containing lots of zero than for a number containing lots of nines.

Code:
``` Str24: ; Converts a 24-bit number into a string. ; Created in Mimas, from PLET source code. http://www.ticalc.org/archives/files/fileinfo/445/44581.html ; Inputs: ;  - E:HL: 24-bit unsigned number. ;    Well, I think it's EHL. High byte might be a different register. ;  - IX: Ptr to location to write string. Will be 8 bytes long: 7 digits and 1 null. ; Output: ;  - String written to IX, null-terminated. ;    If the input number was greater than 9999999, the first digit will be A-G. ;    Saves on having to do another loop iteration for the case that you have a number greater than 9999999. ;    It's easy enough to properly support 8-digit numbers by adding another iteration. ;    (And removing the A-G code.) ; Destroys: ;  - AF ;  - BC ;  - DE ;  - HL ;  - IX    ld   a, e    ld   c, 0F0h    ld   de, 0BDC0h    call   .divf    ld   c, 0FEh    ld   de, 7960h    call   .divf ; INC  C    ld   c, 0FFh    ld   de, 0D8F0h    call   .divf ; LD   C,\$FF    ld   de, 0FC18h    call   .div    ld   de, 0FF9Ch    call   .div    ld   e, 0F6h    call   .div    ld   e, d .div:    ld   b, 2Fh @:    inc   b    add   hl, de    jr   c, @B    sbc   hl, de    ld   (ix + 0), b    inc   ix    ld   (ix + 0), 0    ret .divf:    ld   b, 2Fh @:    inc   b    add   hl, de    adc   a, c    jr   c, @B    sbc   hl, de    sbc   a, c    ld   c, a    ld   a, b    cp   3Ah    jr   c, @F    add   a, 7    ld   b, a @:    ld   a, c    ld   (ix + 0), b    inc   ix    ld   (ix + 0), 0    ret ```

Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

»
» All times are GMT - 5 Hours

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum