;------------------------------------------------------------------- ; ; Binary-to-BCD. Written by John Payson. ; ; Enter with 16-bit binary number in NumH:NumL. ; Exits with BCD equivalent in TenK:Thou:Hund:Tens:Ones. ; org $0010 ;Start of user files for 16c84 NumH: ds 1 NumL: ds 1 TenK: ds 1 Thou: ds 1 Hund: ds 1 Tens: ds 1 Ones: ds 1 Convert: ; Takes number in NumH:NumL ; Returns decimal in ; TenK:Thou:Hund:Tens:Ones swapf NumH,w andlw $0F ;*** PERSONALLY, I'D REPLACE THESE 2 addlw $F0 ;*** LINES WITH "IORLW 11110000B" -AW movwf Thou addwf Thou,f addlw $E2 movwf Hund addlw $32 movwf Ones movf NumH,w andlw $0F addwf Hund,f addwf Hund,f addwf Ones,f addlw $E9 movwf Tens addwf Tens,f addwf Tens,f swapf NumL,w andlw $0F addwf Tens,f addwf Ones,f rlf Tens,f rlf Ones,f comf Ones,f rlf Ones,f movf NumL,w andlw $0F addwf Ones,f rlf Thou,f movlw $07 movwf TenK ; At this point, the original number is ; equal to TenK*10000+Thou*1000+Hund*100+Tens*10+Ones ; if those entities are regarded as two's compliment ; binary. To be precise, all of them are negative ; except TenK. Now the number needs to be normal- ; ized, but this can all be done with simple byte ; arithmetic. movlw $0A ; Ten Lb1: addwf Ones,f decf Tens,f btfss 3,0 goto Lb1 Lb2: addwf Tens,f decf Hund,f btfss 3,0 goto Lb2 Lb3: addwf Hund,f decf Thou,f btfss 3,0 goto Lb3 Lb4: addwf Thou,f decf TenK,f btfss 3,0 goto Lb4 retlw 0 And according to my analysis: If you have a 4 digit hexadecimal number, it may be written as N = a_3*16^3 + a_2*16^2 + a_1*16 + a_0 where a_i, i=0,1,2,3 are the four hexadecimal digits. If you wish to convert this to decimal, then you need to express N as N = b_4*10^4 + b_3*10^3 + b_2*10^2 + b_1*10 + b_0 Where b_j, j=0,1,2,3,4 are the five decimal digits. The reason there are 5 digits in the decimal representation is because the maximum four digit hexadecimal number (0xffff) requires 5 decimal digits (65535). Now the goal is to find a set of equations that allow the b_j's to be expressed in terms of the a_i's. There are infinitely many ways to do this. Here are two of probably the simplest expressions. First, expand the 16^i's and then collect all coefficients of the 10^j's: N = a_3*4096 + a_2*256 + a_1*16 + a_0 = a_3*4*10^3 + a_2*2*10^2 + (a_3*9 + a_2*5 + a_1)*10 + 6*(a_3 + a_2 + a_1) + a_0 This gives us five equations: b_0 = 6*(a_3 + a_2 + a_1) + a_0 b_1 = a_3*9 + a_2*5 + a_1 b_2 = 2*a_2 b_3 = 4*a_3 b_4 = 0 Which as John says, must be "normalized". Normalization in this context means we need to reduce the b_j's such that 0 <= b_j <= 9 In other words we need to find: c_0 = b_0 mod 10 b_1 = (b_1 + (b_0 - c_0)/10) c_1 = b_1 mod 10 b_2 = (b_2 + (b_1 - c_1)/10) c_2 = b_2 mod 10 b_3 = (b_3 + (b_2 - c_2)/10) c_3 = b_3 mod 10 c_4 = (b_4 + (b_3 - c_3)/10) mod 10 = (b_2 - c_2)/10 Division by 10 can be done quite efficiently (as was shown in another thread several months ago). However, it does require a significant amount of code space compared to say repeated subtractions. Unfortunately, there can be very many subtractions that are required. For example, b_1 could be as large as 15*16, or 240. 10 would have to be subtracted 24 times if you wish to compute 240 mod 10. I presume John realized this inefficiency and thus sought to express N so that repeated subtractions could be used and that the total number of subtractions are minimized. This leads to the next way that N can be expressed: N = a_3*(4100 - 4) + a_2*(260 - 4) + a_1*(20-4) + a_0 = 4*a_3*10^3 + (a_3 + 2*a_2)*10^2 + (6*a_2 + 2*a_1)*10 + a_0 - 4*(a_3 + a_2 + a_1) This gives five new equations for the b_j's. b_0 = a_0 - 4*(a_3 + a_2 + a_1) b_1 = 6*a_2 + 2*a_1 b_2 = a_3 + 2*a_2 b_3 = 4*a_3 b_4 = 0 However, these equations are still not conducive to the repeated subtraction algorithm, at least the way John has done it. In other words, it is possible to pre-condition each of the b_j's so that they are less than zero. Then the repeated subtractions can simultaneously perform the "mod 10" and "/10" operations shown above. Consider the equation b_0 for example, b_0 = a_0 - 4*(a_3 + a_2 + a_1) Since each a_i must satisfy: 0 <= a_i <= 15, then b_0 ranges: -60 <= b_0 <= 15 We can make b_0 negative by subtracting any number greater than 15. A logical choice is 20. This is because if we subtract 20 from b_0, we can add 2 to b_1 to keep the net result the same. The reason we add "2" can be seen: b_1*10 + b_0 = b_1*10 + b_0 + 20 - 20 = (b_1 + 2)*10 + b_0 - 20 Carrying this concept out for the rest of the b_i's we have. b_0 = a_0 - 4*(a_3 + a_2 + a_1) - 20 b_1 = 6*a_2 + 2*a_1 + 2 - 140 = 6*a_2 + 2*a_1 - 138 b_2 = a_3 + 2*a_2 + 14 - 60 = a_3 + 2*a_2 - 46 b_3 = 4*a_3 + 6 - 70 = 4*a_3 - 64 b_4 = 0 + 7 = 7 And if you look at John's code closely, you will see this is how he has expressed the b_j's.