From: John Payson via Scott Dattalo
see
http://www.dattalo.com/technical/software/pic/bcd.txt
for notes on how this works. Plan on a headache. <GRIN>
[ed: quick guess at speed is that about 200 instructions will be executed
and 50 bytes + 7 registers used]
;Takes hex number in NumH:NumL Returns decimal in ;TenK:Thou:Hund:Tens:Ones
;written by John Payson
;input
;=A3*163 + A2*162 + A1*161 + A0*160
;=A3*4096 + A2*256 + A1*16 + A0
NumH EQU AD3M ;A3*16+A2
NumL EQU AD3L ;A1*16+A0
;share variables
;=B4*104 + B3*103 + B2*102 + B1*101 + B0*100
;=B4*10000 + B3*1000 + B2*100 + B1*10 + B0
TenK EQU LOOPER ;B4
Thou EQU D2 ;B3
Hund EQU D1 ;B2
Tens EQU R2 ;B1
Ones EQU R1 ;B0
swapf NumH,w ;w = A2*16+A3
andlw 0x0F ;w = A3 *** PERSONALLY, I'D REPLACE THESE 2
addlw 0xF0 ;w = A3-16 *** LINES WITH "IORLW b'11110000B' " -AW
movwf Thou ;B3 = A3-16
addwf Thou,f ;B3 = 2*(A3-16) = 2A3 - 32
addlw .226 ;w = A3-16 - 30 = A3-46
movwf Hund ;B2 = A3-46
addlw .50 ;w = A3-46 + 50 = A3+4
movwf Ones ;B0 = A3+4
movf NumH,w ;w = A3*16+A2
andlw 0x0F ;w = A2
addwf Hund,f ;B2 = A3-46 + A2 = A3+A2-46
addwf Hund,f ;B2 = A3+A2-46 + A2 = A3+2A2-46
addwf Ones,f ;B0 = A3+4 + A2 = A3+A2+4
addlw .233 ;w = A2 - 23
movwf Tens ;B1 = A2-23
addwf Tens,f ;B1 = 2*(A2-23)
addwf Tens,f ;B1 = 3*(A2-23) = 3A2-69 (Doh! thanks NG)
swapf NumL,w ;w = A0*16+A1
andlw 0x0F ;w = A1
addwf Tens,f ;B1 = 3A2-69 + A1 = 3A2+A1-69 range -69...-9
addwf Ones,f ;B0 = A3+A2+4 + A1 = A3+A2+A1+4 and Carry = 0 (thanks NG)
rlf Tens,f ;B1 = 2*(3A2+A1-69) + C = 6A2+2A1-138 and Carry is now 1 as tens register had to be negitive
rlf Ones,f ;B0 = 2*(A3+A2+A1+4) + C = 2A3+2A2+2A1+9 (+9 not +8 due to the carry from prev line, Thanks NG)
comf Ones,f ;B0 = ~(2A3+2A2+2A1+9) = -2A3-2A2-2A1-10 (ones complement plus 1 is twos complement. Thanks SD)
;;Nikolai Golovchenko [golovchenko at MAIL.RU] says: comf can be regarded like:
;; comf Ones, f
;; incf Ones, f
;; decf Ones, f
;;First two instructions make up negation. So,
;;Ones = -1 * Ones - 1
;; = - 2 * (A3 + A2 + A1) - 9 - 1
;; = - 2 * (A3 + A2 + A1) - 10
rlf Ones,f ;B0 = 2*(-2A3-2A2-2A1-10) = -4A3-4A2-4A1-20
movf NumL,w ;w = A1*16+A0
andlw 0x0F ;w = A0
addwf Ones,f ;B0 = -4A3-4A2-4A1-20 + A0 = A0-4(A3+A2+A1)-20 range -215...-5 Carry=0
rlf Thou,f ;B3 = 2*(2A3 - 32) = 4A3 - 64
movlw 0x07 ;w = 7
movwf TenK ;B4 = 7
;B0 = A0-4(A3+A2+A1)-20 ;-5...-200
;B1 = 6A2+2A1-138 ;-18...-138
;B2 = A3+2A2-46 ;-1...-46
;B3 = 4A3-64 ;-4...-64
;B4 = 7 ;7
; 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 .10 ;w = 10
Lb1: ;do
addwf Ones,f ; B0 += 10
decf Tens,f ; B1 -= 1
btfss 3,0
;skip no carry
goto Lb1 ; while B0 < 0
;jmp carry
Lb2: ;do
addwf Tens,f ; B1 += 10
decf Hund,f ; B2 -= 1
btfss 3,0
goto Lb2 ; while B1 < 0
Lb3: ;do
addwf Hund,f ; B2 += 10
decf Thou,f ; B3 -= 1
btfss 3,0
goto Lb3 ; while B2 < 0
Lb4: ;do
addwf Thou,f ; B3 += 10
decf TenK,f ; B4 -= 1
btfss 3,0
goto Lb4 ; while B3 < 0
retlw 0
Archive:
Comments:
btfss 3,0 by btfss STATUS, C, ACCESS
addwf Ones,f ; B0 += 10
decf Tens,f ; B1 -= 1
btfss 3,0
decf Tens,f ; B1 -= 1
addwf Ones,f ; B0 += 10
btfss STATUS, C, ACCESS
See also:
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.
+
Code:
I reworked the second part of the code (normalizing B0..B4) for a PIC18.
Normalization is done by division and modulo operations which are done by mul.
The modified conversion runs in constant time and it is about 74 cycles faster than John Payson's normalization routine (average based on all conversions from 0..ffff).
It takes about 15-20 more lines of code. There are no additional requirements to the original code (no temporary vars or so). It works for pic18 family featuring the "mul" opcode. Thanks to all contributors and the smart explanation of the original code.
movlw 0x07 ;w = 7
movwf TenK ;B4 = 7
; Now the number needs to be normal-
; ized, but this can all be done with simple byte
; arithmetic.
;**** use original code up to here ****
;**** modified normalization start here ****
comf Ones, w ;w = -(B0+1) ; range (w) 5..199
mullw h'CD'
movf PRODH, w
mullw h'20' ;PRODH = -(B0+1) / 10
incf PRODH, w
subwf Tens ;B1 = B1 - (-(B0+1)/10 + 1) ; range -18..-138 -(1..20) = -19..-158
mullw d'10'
movf PRODL, w
addwf Ones ;B0 = B0 + 10*(-(B0+1)/10 + 1) = B0 mod 10
comf Tens, w ;w = -(B1+1) ; range (w) 18..157
mullw h'CD'
movf PRODH, w
mullw h'20' ;PRODH = -(B1+1) / 10
incf PRODH, w
subwf Hund ;B2 = B2 - (-(B1+1)/10 + 1) ; range -1..-46 -(2..16) = -3..-62
mullw d'10'
movf PRODL, w
addwf Tens ;B1 = B1 + 10*(-(B1+1)/10 + 1) = B1 mod 10
comf Hund, w ;w = -(B2+1) ; range (w) 2..61
mullw h'1A' ;PRODH = -(B2+1) / 10
incf PRODH, w
subwf Thou ;B3 = B3 - (-(B2+1)/10 + 1) ; range -4..-64 -(1..7) = -5..-71
mullw d'10'
movf PRODL, w
addwf Hund ;B2 = B2 + 10*(-(B2+1)/10 + 1) = B2 mod 10
comf Thou, w ;w = -(B3+1) ; range (w) 4..70
mullw h'CD'
movf PRODH, w
mullw h'20' ;PRODH = -(B3+1) / 10
incf PRODH, w
subwf TenK ;B4 = B4 - (-(B3+1)/10 + 1)
mullw d'10'
movf PRODL, w
addwf Thou ;B3 = B3 + 10*(-(B3+1)/10 + 1) = B3 mod 10
return
+
| file: /Techref/microchip/math/radix/b2bu-16b5d.htm, 14KB, , updated: 2020/4/3 12:04, local time: 2025/10/24 13:28,
216.73.216.180,10-8-63-169:LOG IN
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://www.massmind.org/techref/microchip/math/radix/b2bu-16b5d.htm"> PIC Microcontoller Radix Math Method Binary to BCD unpacked 16 bit to 5 digit</A> |
| Did you find what you needed? |
Welcome to massmind.org! |
Welcome to www.massmind.org! |
.