line

Jake's Electronics

a place to document

line

Binary to BCD

It is often necessary to need to use binary coded decimal in programs. But the questions is how can we take a binary number and covert in to BCD efficiently. Well, the three methods below show how to convert up to a 16 bit binary number into 4 bit binary coded decimal stored in 5 separate registers.

For example, consider the number B'00001010 11111111' (2815). After processing the original number, the BCD data will be held in the following resulting registers. Label address' have been assigned to the registers for understandability.

  • TENS_THOUS - B'00000000' (0)
  • THOUS - B'00000010' (2)
  • HUNS - B'00001000' (8)
  • TENS - B'00000001' (1)
  • ONES - B'00000101' (5)

Each of the three methods have advantages and disadvantages. The most notable being execution cycles verse program memory. The double dabble method uses an almost fixed instruction cycle count with little variation but requires more than twice as much program memory. The decrement increment method has the advantage of low program memory space, but as the number to convert gets larger, the execution time sky-rockets. Before I explain each of the methods, here is a comparison table with respect to the program memory requirement verse the execution cycles. See below for an explanation of each method along with source code.

8 Bit Variation

Dummy Number DEC & BIN Method Program Memory Execution Cycles
1 (1 bit) B'00000001' Method 1 - Decrement & Increment 16 17
Method 2 - Double Dabble (Using Indirect Addressing) 34 304
Method 3 - Double Dabble (Without Indirect Addressing) 38 192
15 (4 bit) B'00001111' Method 1 - Decrement & Increment 16 104
Method 2 - Double Dabble (Using Indirect Addressing) 34 304
Method 3 - Double Dabble (Without Indirect Addressing) 38 193
63 (6 bit) B'00111111' Method 1 - Decrement & Increment 16 407
Method 2 - Double Dabble (Using Indirect Addressing) 34 304
Method 3 - Double Dabble (Without Indirect Addressing) 38 194
255 (8 bit) B'11111111' Method 1 - Decrement & Increment 16 1,622
Method 2 - Double Dabble (Using Indirect Addressing) 34 304
Method 3 - Double Dabble (Without Indirect Addressing) 38 196
 

16 Bit Variation

Dummy Number DEC & BIN Method Program Memory Execution Cycles
1 (1 bit) B'00000000 00000001' Method 1 - Decrement & Increment 27 24
Method 2 - Double Dabble (Using Indirect Addressing) 44 909
Method 3 - Double Dabble (Without Indirect Addressing) 59 609
15 (4 bit) B'00000000 00001111' Method 1 - Decrement & Increment 27 111
Method 2 - Double Dabble (Using Indirect Addressing) 44 909
Method 3 - Double Dabble (Without Indirect Addressing) 59 610
63 (6 bit) B'00000000 00111111' Method 1 - Decrement & Increment 27 414
Method 2 - Double Dabble (Using Indirect Addressing) 44 909
Method 3 - Double Dabble (Without Indirect Addressing) 59 611
255 (8 bit) B'00000000 11111111' Method 1 - Decrement & Increment 27 1,629
Method 2 - Double Dabble (Using Indirect Addressing) 44 909
Method 3 - Double Dabble (Without Indirect Addressing) 59 613
1023 (10 bit) B'00000011 11111111' Method 1 - Decrement & Increment 27 6,501
Method 2 - Double Dabble (Using Indirect Addressing) 44 909
Method 3 - Double Dabble (Without Indirect Addressing) 59 616
65535 (16 bit) B'11111111 11111111' Method 1 - Decrement & Increment 27 415,575
Method 2 - Double Dabble (Using Indirect Addressing) 44 909
Method 3 - Double Dabble (Without Indirect Addressing) 59 626

Method 1 - Decrement & Increment

How It Works:

This method is one I came up with prior to learning about the Double Dabble algorithm. It is very basic in concept and works by decrementing the original number and incrementing a register called ONES. With every overflow from 9 to 10, the ONES register is reset and a register called TENS is incremented. You can start to understand the simplicity of this method and realise that it doesn't take much code alteration to adapt the routine to smaller or larger numbers.

Pro's

  • Uses the most basic instructions and will work on any device
  • Very low program memory used (see table above)

Con's

  • Processing time varies significantly (see table above)
  • Extensive processing time for large numbers (>8 bit) (see table above)

Source Code: 8 Bit Variation

To use this code, add the General Purpose Register labels to the Constant Block. Copy from 'BIN_TO_BCD_8BIT' routine to the bottom and paste in your program. Don't forget to add a RETURN at the bottom if using as a sub-routine. Finally, load your binary number to be converted into BIN_TO_BCD_LO and call BIN_TO_BCD_8BIT.

CBLOCK H'20'
COUNT1

BIN_TO_BCD_LO

HUNS
TENS
ONES

ENDC



LOAD_DUMMY_NUMBER
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_LO
        
BIN_TO_BCD_8BIT
        INCF    BIN_TO_BCD_LO           ; Pre-load low byte register + 1
        CLRF    HUNS                    ; HUNS = 0000 0000
        MOVLW   D'246'                  ; Move decimal '246' to W
        
RESET_TENS
        MOVWF   TENS                    ; TENS GPR = 1111 0101
RESET_ONES
        MOVWF   ONES                    ; ONES GPR = 1111 0101

DEC_ORIGINAL        
        DECFSZ  BIN_TO_BCD_LO, F        ; Decrement BIN_TO_BCD_LO register
        GOTO    INC_RESULT              ; Not 0, GOTO INC_RESULT
        GOTO    ADJUST_RESULT           ; Is 0, done, GOTO ADJUST_RESULT

INC_RESULT        
        INCFSZ  ONES, F                 ; Increment ONES register, skip if 0 (overflow)
        GOTO    DEC_ORIGINAL            ; Not 0, repeat decrement of original number
        INCFSZ  TENS, F                 ; Is 0, Increment TENS register skip if 0
        GOTO    RESET_ONES              ; Not 0, repeat decrement of original number & reset the ONES register to D'246'
        INCF    HUNS, F                 ; TENS overflowed, Increment HUNS skip if 0
        GOTO    RESET_TENS              ; Not 0, repeat decrement of original number & reset the ONES and TENS registers to D'246'
        
ADJUST_RESULT        
        SUBWF   TENS, F                 ; W still holds D'246 so subtract it from TENS register to determine how many 'TENS' (0-9)
        SUBWF   ONES, F                 ; W still holds D'246 so subtract it from ONES register to determine how many 'ONES' (0-9)
        

Source Code: 16 Bit Variation

CBLOCK H'20'
COUNT1

BIN_TO_BCD_HI
BIN_TO_BCD_LO

TENS_THOUS
THOUS
HUNS
TENS
ONES

ENDC



LOAD_DUMMY_NUMBER
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_HI
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_LO
        
BIN_TO_BCD_16BIT
        INCF    BIN_TO_BCD_LO           ; Pre-load low byte register + 1
        INCF    BIN_TO_BCD_HI           ; Pre-load high byte register + 1
        CLRF    TENS_THOUS              ; TENS_THOUS = 0000 0000
        MOVLW   D'246'                  ; Move decimal '246' to W

RESET_THOUS
        MOVWF   THOUS                   ; THOUS GPR = 1111 0101
RESET_HUNS
        MOVWF   HUNS                    ; HUNS GPR = 1111 0101
RESET_TENS
        MOVWF   TENS                    ; TENS GPR = 1111 0101
RESET_ONES
        MOVWF   ONES                    ; ONES GPR = 1111 0101

DEC_ORIGINAL        
        DECFSZ  BIN_TO_BCD_LO, F        ; Decrement BIN_TO_BCD_LO register
        GOTO    INC_RESULT              ; Not 0, GOTO INC_RESULT
        DECFSZ  BIN_TO_BCD_HI, F        ; Decrement BIN_TO_BCD_HI register
        GOTO    INC_RESULT              ; Not 0, skip next instruction
        GOTO    ADJUST_RESULT           ; Is 0, done, GOTO ADJUST_RESULT

INC_RESULT        
        INCFSZ  ONES, F                 ; Increment ONES register, skip if 0 (overflow)
        GOTO    DEC_ORIGINAL            ; Not 0, repeat decrement of original number
        INCFSZ  TENS, F                 ; Is 0, Increment TENS register skip if 0
        GOTO    RESET_ONES              ; Not 0, repeat decrement of original number & reset the ONES register to D'246'
        INCFSZ  HUNS, F                 ; TENS overflowed, Increment HUNS skip if 0
        GOTO    RESET_TENS              ; Not 0, repeat decrement of original number & reset the ONES and TENS registers to D'246'
        INCFSZ  THOUS, F                ; HUNS overflowed, Increment THOUS
        GOTO    RESET_HUNS              ; Not 0, repeat decrement of original number & reset the ONES, TENS & HUNS registers to D'246'
        INCF    TENS_THOUS, F           ; THOUS overflowed, Increment TENS_THOUS
        GOTO    RESET_THOUS             ; Repeat decrement of original number & reset the ONES, TENS & HUNS & THOUS registers to D'246'
        
ADJUST_RESULT        
        SUBWF   THOUS, F                ; W still holds D'246 so subtract it from THOUS register to determine how many 'THOUS' (0-9)
        SUBWF   HUNS, F                 ; W still holds D'246 so subtract it from HUNS register to determine how many 'HUNS' (0-9)
        SUBWF   TENS, F                 ; W still holds D'246 so subtract it from TENS register to determine how many 'TENS' (0-9)
        SUBWF   ONES, F                 ; W still holds D'246 so subtract it from ONES register to determine how many 'ONES' (0-9)
        

Method 2 & 3 - Double Dabble

How It Works:

This method is one I came across while searching the net for a better way to convert binary to BCD. I won't go into depth here because there are many pages that explain how it works but basically it uses a smart shift and add system. One place to check out how it works is wikipedia.

Method 2 & 3 are almost the same, the only difference being one uses indirect addressing and the other doesn't. Depending on which device you select for your project/system may determine which method you use. Although something to note, even though the non indirect addressing method uses slightly more program memory space it processes roughly 30% faster. See the pro's and con's for each method below.

Method 2 - Double Dabble (Using Indirect Addressing)

Pro's

  • Relatively low program memory used (see table above)
  • Process time is constant no matter what the number (see table above)

Con's

  • Can only be used on devices with indirect addressing
  • Process's slower that the non indirect addressing method (see table above)

Source Code: 8 Bit Variation

To use this code, add the General Purpose Register labels to the Constant Block. Copy from 'BINARY_TO_PACKED_BCD' routine to the bottom and paste in your program. Don't forget to add a RETURN at the bottom if using as a sub-routine. Finally, load your binary number to be converted into BIN_TO_BCD_LO and call BINARY_TO_PACKED_BCD.

CBLOCK H'20'
COUNT1

BIN_TO_BCD_LO

HUNS
TENS
ONES

ENDC



LOAD_DUMMY_NUMBER
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_LO
        
BINARY_TO_PACKED_BCD
  ; 8 Bit Double Dabble Algorithm to obtain 3 x 4-bit BCD numbers, packed into 2 separate 8-bit registers (ONE & HUNS)
        CLRF    ONES                    ; Clear packed BCD registers
        CLRF    HUNS                    ; 

        MOVLW   D'8'                    ; Set countdown register (RLF must be repeated x times where x = binary number length, although binary number must be left justified in BIN_TO_BCD_LO if less than 8 bits)
        MOVWF   COUNT1                  ; Store in GPR labelled COUNT1

BIN2BCD_LOOP
  ; Loop rotate file registers and decrement count register
        BCF     STATUS, C               ; Clear carry flag for RLF

        RLF     BIN_TO_BCD_LO, F        ; Shift all registers 1 bit left using the carry bit of the status register to carry the MSB off the end of one register into the LSB of the next register
        RLF     ONES, F                 ;
        RLF     HUNS, F                 ;

        DECF    COUNT1, F               ; Decrement countdown register
        BTFSC   STATUS, Z               ; What that the last time OR is zero flag set?
        GOTO    UNPACK_BCD              ; Yes, move on to unpacking the result registers. No, skip this instruction and continue
        
LOAD_FOR_BCD_TEST 
  ; Test prospective BCD digits. If >=5, add 3 (as per double dabble algorithm)
        MOVLW   ONES                    ; Move ONES register address to W
        MOVWF   FSR                     ; Store ONES register address in File Select Register
        CALL    ADJUST_BCD_DIGITS       ; Call ADJUST_BCD_DIGITS to check if prospective BCD register is equal to or greater than 5
       
        MOVLW   HUNS                    ; Test and adjust second packed BCD byte
        MOVWF   FSR                     ; 
        CALL    ADJUST_BCD_DIGITS       ; 
        
        GOTO    BIN2BCD_LOOP            ; Finish test and adjust, go back and continue rotating
        
ADJUST_BCD_DIGITS
        MOVLW   0X03                    ;       (I refer to ONES in the description below but it is what ever is loaded into the FSR prior the calling sub routine)
        ADDWF   INDF, W                 ; Add 3 with the contents of ONES register, store in W
        MOVWF   TENS                    ; Store in TENS. TENS IS ONLY USED AS A TEMPORARY STORAGE REGISTER HERE AS IT IS NOT CURRENTLY BEING USED AND TO SAVE ON GPR USEAGE. SUBSTITE TENS WITH 'TEMP' TO SAVE CONFUSION
        BTFSC   TENS, 3                 ; Test TENS register to check if more than 7. If the ONES register had 5 or greater, the TENS register will have 8 or greater after the addition
        MOVWF   INDF                    ; If ONES was equal to or greater than 5, adjust ONES by adding 3. W register still holds ONES + 3 so MOVe W to F
        
        MOVLW   0X30                    ; Repeat for upper nibble of FSR in question
        ADDWF   INDF, W                 ; 
        MOVWF   TENS                    ; 
        BTFSC   TENS, 7                 ; 
        MOVWF   INDF                    ; 
        RETURN                          ;
        
UNPACK_BCD
  ; Unpack the 2 result registers into 3 separate registers each holding the 4 bit BCD number in the lower 4 bits and masking the upper 4 bits
        SWAPF   ONES, W                 ; Swap nibbles of ONES register so that BCD for tens number is in the lower 4 bits, store in W register leaving original register unchanged
        ANDLW   B'00001111'             ; Mask upper nibble so all that is left is the tens BCD number in the lower 4 bits
        MOVWF   TENS                    ; Store result in TENS
        
        MOVLW   B'00001111'             ; Mask upper nibbles of ONES it only contain BCD in lower 4 bits (no need to mask upper nibble of HUNS as the upper 4 bits are never altered)
        ANDWF   ONES, F                 ; 
        

Source Code: 16 Bit Variation

CBLOCK H'20'
COUNT1

BIN_TO_BCD_HI
BIN_TO_BCD_LO

TENS_THOUS
THOUS
HUNS
TENS
ONES

ENDC



LOAD_DUMMY_NUMBER
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_HI
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_LO
        
BINARY_TO_PACKED_BCD
  ; 16 Bit Double Dabble Algorithm to obtain 5 x 4-bit BCD numbers, packed into 3 separate 8-bit registers
        CLRF    ONES                    ; Clear packed BCD registers
        CLRF    HUNS                    ;               
        CLRF    TENS_THOUS              ; 

        MOVLW   D'16'                   ; Set countdown register (RLF must be repeated x times where x = binary number length, although binary number must be left justified in BIN_TO_BCD_LO:BIN_TO_BCD_HI if less than 16 bits)
        MOVWF   COUNT1                  ; Store in GPR labelled COUNT1

BIN2BCD_LOOP
  ; Loop rotate file registers and decrement count register
        BCF     STATUS, C               ; Clear carry flag for RLF

        RLF     BIN_TO_BCD_LO, F        ; Shift all registers 1 bit left using the carry bit of the status register to carry the MSB off the end of one register into the LSB of the next register
        RLF     BIN_TO_BCD_HI, F        ;
        RLF     ONES, F                 ;
        RLF     HUNS, F                 ;
        RLF     TENS_THOUS, F           ;

        DECF    COUNT1, F               ; Decrement countdown register
        BTFSC   STATUS, Z               ; What that the last time OR is zero flag set?
        GOTO    UNPACK_BCD              ; Yes, move on to unpacking the result registers. No, skip this instruction and continue
        
LOAD_FOR_BCD_TEST 
  ; Test prospective BCD digits. If >=5, add 3 (as per double dabble algorithm)
        MOVLW   ONES                    ; Move ONES register address to W
        MOVWF   FSR                     ; Store ONES register address in File Select Register
        CALL    ADJUST_BCD_DIGITS       ; Call ADJUST_BCD_DIGITS to check if prospective BCD register is equal to or greater than 5
       
        MOVLW   HUNS                    ; Test and adjust second packed BCD byte
        MOVWF   FSR                     ; 
        CALL    ADJUST_BCD_DIGITS       ; 
        
        MOVLW   TENS_THOUS              ; Test and adjust third packed BCD byte
        MOVWF   FSR                     ; 
        CALL    ADJUST_BCD_DIGITS       ; 
        
        GOTO    BIN2BCD_LOOP            ; Finish test and adjust, go back and continue rotating
        
ADJUST_BCD_DIGITS
        MOVLW   0X03                    ;       (I refer to ONES in the description below but it is what ever is loaded into the FSR prior the calling sub routine)
        ADDWF   INDF, W                 ; Add 3 with the contents of ONES register, store in W
        MOVWF   TENS                    ; Store in TENS. TENS IS ONLY USED AS A TEMPORARY STORAGE REGISTER HERE AS IT IS NOT CURRENTLY BEING USED AND TO SAVE ON GPR USEAGE. SUBSTITE TENS WITH 'TEMP' TO SAVE CONFUSION
        BTFSC   TENS, 3                 ; Test TENS register to check if more than 7. If the ONES register had 5 or greater, the TENS register will have 8 or greater after the addition
        MOVWF   INDF                    ; If ONES was equal to or greater than 5, adjust ONES by adding 3. W register still holds ONES + 3 so MOVe W to F
        
        MOVLW   0X30                    ; Repeat for upper nibble of FSR in question
        ADDWF   INDF, W                 ; 
        MOVWF   TENS                    ; 
        BTFSC   TENS, 7                 ; 
        MOVWF   INDF                    ; 
        RETURN                          ;
        
UNPACK_BCD
  ; Unpack the 3 result registers into 5 separate registers each holding the 4 bit BCD number in the lower 4 bits and masking the upper 4 bits
        SWAPF   ONES, W                 ; Swap nibbles of ONES register so that BCD for tens number is in the lower 4 bits, store in W register leaving original register unchanged
        ANDLW   B'00001111'             ; Mask upper nibble so all that is left is the tens BCD number in the lower 4 bits
        MOVWF   TENS                    ; Store result in TENS
        
        SWAPF   HUNS, W                 ; Repeat for HUNS register
        ANDLW   B'00001111'             ; 
        MOVWF   THOUS                   ; 
        
        MOVLW   B'00001111'             ; Mask upper nibbles of ONES and HUNS so they only contain BCD in lower 4 bits
        ANDWF   ONES, F                 ; 
        ANDWF   HUNS, F                 ;
        

Method 3 - Double Dabble (No Indirect Addressing)

Pro's

  • Fairly constant and low process time (see table above)
  • Works on most devices

Con's

  • Take up the most program memory space of the 3 methods (see table above)

Source Code: 8 Bit Variation

To use this code, add the General Purpose Register labels to the Constant Block. Copy from 'BINARY_TO_PACKED_BCD' routine to the bottom and paste in your program. Don't forget to add a RETURN at the bottom if using as a sub-routine. Finally, load your binary number to be converted into BIN_TO_BCD_LO and call BINARY_TO_PACKED_BCD.

CBLOCK H'20'
COUNT1

BIN_TO_BCD_LO

HUNS
TENS
ONES

ENDC



LOAD_DUMMY_NUMBER
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_LO
        
BINARY_TO_PACKED_BCD
  ; 8 Bit Double Dabble Algorithm to obtain 3 x 4-bit BCD numbers, packed into 2 separate 8-bit registers (ONE & HUNS)
        CLRF    ONES                    ; Clear packed BCD registers
        CLRF    HUNS                    ; 

        MOVLW   D'8'                    ; Set countdown register (RLF must be repeated x times where x = binary number length, although binary number must be left justified in BIN_TO_BCD_LO if less than 8 bits)
        MOVWF   COUNT1                  ; Store in GPR labelled COUNT1

BIN2BCD_LOOP
  ; Loop rotate file registers and decrement count register
        BCF     STATUS, C               ; Clear carry flag for RLF

        RLF     BIN_TO_BCD_LO, F        ; Shift all registers 1 bit left using the carry bit of the status register to carry the MSB off the end of one register into the LSB of the next register
        RLF     ONES, F                 ;
        RLF     HUNS, F                 ;

        DECF    COUNT1, F               ; Decrement countdown register
        BTFSC   STATUS, Z               ; What that the last time OR is zero flag set?
        GOTO    UNPACK_BCD              ; Yes, move on to unpacking the result registers. No, skip this instruction and continue
        
  ; Test prospective BCD digits. If >=5, add 3 (as per double dabble algorithm)
TEST_DIGIT_0  ; (xxxxxxxx xxxx1111)
        MOVLW   B'00001111'             ; Move 00001111 to W register
        ANDWF   ONES, W                 ; Use to mask upper nibble of ONES, store result in W register
        SUBLW   0X04                    ; Subtract W from decimal 4
        BTFSC   STATUS, C               ; Test carry bit of status register to check if W < 5
        GOTO    TEST_DIGIT_1            ; Digit 0 < 5, do not add 3
        MOVLW   0X03                    ; Digit 0 >=5, add 3 to digit 0
        ADDWF   ONES, F                 ; There is never a digit carry

TEST_DIGIT_1  ; (xxxxxxxx 1111xxxx)
        MOVLW   B'11110000'             ; Check next digit using similar method above
        ANDWF   ONES, W                 ;
        SUBLW   0X40                    ;
        BTFSC   STATUS, C               ;
        GOTO    TEST_DIGIT_2            ; 
        MOVLW   0X30                    ; 
        ADDWF   ONES, F                 ;

TEST_DIGIT_2  ; (xxxx1111 xxxxxxxx)
        MOVLW   B'00001111'             ; Check next digit using similar method above
        ANDWF   HUNS, W                 ;
        SUBLW   0X04                    ;
        BTFSC   STATUS, C               ;
        GOTO    BIN2BCD_LOOP            ; 
        MOVLW   0X03                    ; 
        ADDWF   HUNS, F                 ; 

        GOTO    BIN2BCD_LOOP            ; Digit 4 <5, finished checking and adjusting digits, loop again
        
UNPACK_BCD
  ; Unpack the 2 result registers into 3 separate registers each holding the 4 bit BCD number in the lower 4 bits and masking the upper 4 bits
        SWAPF   ONES, W                 ; Swap nibbles of ONES register so that BCD for tens number is in the lower 4 bits, store in W register leaving original register unchanged
        ANDLW   B'00001111'             ; Mask upper nibble so all that is left is the tens BCD number in the lower 4 bits
        MOVWF   TENS                    ; Store result in TENS
        
        MOVLW   B'00001111'             ; Mask upper nibbles of ONES it only contain BCD in lower 4 bits (no need to mask upper nibble of HUNS as the upper 4 bits are never altered)
        ANDWF   ONES, F                 ; 
        

Source Code: 16 Bit Variation

CBLOCK H'20'
COUNT1

BIN_TO_BCD_HI
BIN_TO_BCD_LO

TENS_THOUS
THOUS
HUNS
TENS
ONES

ENDC



LOAD_DUMMY_NUMBER
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_HI
        MOVLW   B'11111111'
        MOVWF   BIN_TO_BCD_LO
        
BINARY_TO_PACKED_BCD
  ; 16 Bit Double Dabble Algorithm to obtain 5 x 4-bit BCD numbers, packed into 3 separate 8-bit registers
        CLRF    ONES                    ; Clear packed BCD registers
        CLRF    HUNS                    ;               
        CLRF    TENS_THOUS              ; 

        MOVLW   D'16'                   ; Set countdown register (RLF must be repeated x times where x = binary number length, although binary number must be left justified in BIN_TO_BCD_LO:BIN_TO_BCD_HI if less than 16 bits)
        MOVWF   COUNT1                  ; Store in GPR labelled COUNT1

BIN2BCD_LOOP
  ; Loop rotate file registers and decrement count register
        BCF     STATUS, C               ; Clear carry flag for RLF

        RLF     BIN_TO_BCD_LO, F        ; Shift all registers 1 bit left using the carry bit of the status register to carry the MSB off the end of one register into the LSB of the next register
        RLF     BIN_TO_BCD_HI, F        ;
        RLF     ONES, F                 ;
        RLF     HUNS, F                 ;
        RLF     TENS_THOUS, F           ;

        DECF    COUNT1, F               ; Decrement countdown register
        BTFSC   STATUS, Z               ; What that the last time OR is zero flag set?
        GOTO    UNPACK_BCD              ; Yes, move on to unpacking the result registers. No, skip this instruction and continue
        
  ; Test prospective BCD digits. If >=5, add 3 (as per double dabble algorithm)
TEST_DIGIT_0  ; (xxxxxxxx xxxxxxxx xxxx1111)
        MOVLW   B'00001111'             ; Move 00001111 to W register
        ANDWF   ONES, W                 ; Use to mask upper nibble of ONES, store result in W register
        SUBLW   0X04                    ; Subtract W from decimal 4
        BTFSC   STATUS, C               ; Test carry bit of status register to check if W < 5
        GOTO    TEST_DIGIT_1            ; Digit 0 < 5, do not add 3
        MOVLW   0X03                    ; Digit 0 >=5, add 3 to digit 0
        ADDWF   ONES, F                 ; There is never a digit carry

TEST_DIGIT_1  ; (xxxxxxxx xxxxxxxx 1111xxxx)
        MOVLW   B'11110000'             ; Check next digit using similar method above
        ANDWF   ONES, W                 ;
        SUBLW   0X40                    ;
        BTFSC   STATUS, C               ;
        GOTO    TEST_DIGIT_2            ; 
        MOVLW   0X30                    ; 
        ADDWF   ONES, F                 ;

TEST_DIGIT_2  ; (xxxxxxxx xxxx1111 xxxxxxxx)
        MOVLW   B'00001111'             ; Check next digit using similar method above
        ANDWF   HUNS, W                 ;
        SUBLW   0X04                    ;
        BTFSC   STATUS, C               ;
        GOTO    TEST_DIGIT_3            ; 
        MOVLW   0X03                    ; 
        ADDWF   HUNS, F                 ; 

TEST_DIGIT_3  ; (xxxxxxxx 1111xxxx xxxxxxxx)
        MOVLW   B'11110000'             ; Check next digit using similar method above
        ANDWF   HUNS, W                 ;
        SUBLW   0X40                    ;
        BTFSC   STATUS, C               ;
        GOTO    TEST_DIGIT_4            ; 
        MOVLW   0X30                    ; 
        ADDWF   HUNS, F                 ;

TEST_DIGIT_4  ; (xxxx1111 xxxxxxxx xxxxxxxx)
        MOVLW   B'00001111'             ; Check next digit using similar method above
        ANDWF   TENS_THOUS, W           ;
        SUBLW   0X40                    ;
        BTFSC   STATUS, C               ;
        GOTO    BIN2BCD_LOOP            ; 
        MOVLW   0X03                    ; 
        ADDWF   TENS_THOUS, F           ; 

        GOTO    BIN2BCD_LOOP            ; Digit 4 <5, finished checking and adjusting digits, loop again
        
UNPACK_BCD
  ; Unpack the 3 result registers into 5 separate registers each holding the 4 bit BCD number in the lower 4 bits and masking the upper 4 bits
        SWAPF   ONES, W                 ; Swap nibbles of ONES register so that BCD for tens number is in the lower 4 bits, store in W register leaving original register unchanged
        ANDLW   B'00001111'             ; Mask upper nibble so all that is left is the tens BCD number in the lower 4 bits
        MOVWF   TENS                    ; Store result in TENS
        
        SWAPF   HUNS, W                 ; Repeat for HUNS register
        ANDLW   B'00001111'             ; 
        MOVWF   THOUS                   ; 
        
        MOVLW   B'00001111'             ; Mask upper nibbles of ONES and HUNS so they only contain BCD in lower 4 bits
        ANDWF   ONES, F                 ; 
        ANDWF   HUNS, F                 ;
        

line