;-------------------------------------------
;Fast binary to decimal conversion (0..999)
;
;Input: NumH:NumL
;Output Hund:Tens_Ones (packed BCD)
;
;
;
;Size: 56 instructions
;Execution time (with return): 57
;
;8-July-2000 by Nikolai Golovchenko
;23-Aug-2001
;Based on 8bit BIN2BCD of Scott Dattalo
;-------------------------------------------
bin2dec999fast
swapf NumL, w ;Add the upper and lower nibbles
addwf NumL, w ;to get the one's digit
andlw 0x0F
skpndc ;Go through a binary to bcd
addlw 0x16 ;conversion for just the one's
skpndc ;digit
addlw 0x06
addlw 0x06
skpdc
addlw -0x06
btfsc NumL, 4 ;bit 4 is a special case
addlw 0x16 - 1 + 0x6
skpdc
addlw -0x06
;now adjust the ten's digit
btfsc NumL, 5 ;2^5 = 32, so add 3 to the ten's
addlw 0x30 ;digit if bit 5 is set
btfsc NumL, 6 ;2^6 = 64, so add 6
addlw 0x60 ;if bit 6 is set
btfsc NumL, 7 ;2^7 = 128, so add 2 (the ten's
addlw 0x20 ;digit) if bit 7 is set
addlw 0x60 ;convert the ten's digit to bcd
clrf Hund
rlf Hund, f ;if there's a carry, then the input
btfss Hund, 0 ;was greater than 99.
addlw -0x60
movwf Tens_Ones
movlw 0x66 ;2^8 = 256, so add 0x56 to Tens_Ones
btfsc NumH, 0
movlw 0x56 + 0x66 ;add 0x66 for decimal adjust
addwf Tens_Ones, f
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f
movlw 0x66 ;2^9 = 512, so add 0x12 to Tens_Ones
btfsc NumH, 1
movlw 0x12 + 0x66
addwf Tens_Ones, f
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f
; btfsc NumL, 7 ;finish with hundreds
; incf Hund, f
; movlw 2
; btfsc NumH, 0
; addwf Hund, f
; movlw 5
; btfsc NumH, 1
; addwf Hund, f; Aug 23, 2001 optimization:
rlf NumL, w ; copy bit 7 to carry
return
rlf NumH, w ; load w with bits 9 to 7
btfsc NumH, 1 ; add b[9]
addlw 1 ;
addwf Hund, f ; add it to hundreds
The algorithm is based on the idea of adding up decimal weights of each
bit. Each bit has a weight (equal to 2^b, b - bit number, 0 to 15), which can
be represented and added in decimal:
bit weight hundreds tens ones
------- ------- ------- ------ -------
0 1 0 0 1
1 2 0 0 2
2 4 0 0 4
3 8 0 0 8
4 16 0 1 6
5 32 0 3 2
6 64 0 6 4
7 128 1 2 8
8 256 2 5 6
9 512 5 1 2
So, if a bit is set, we add the appropriate decimal digits to our
result. But testing each bit would be very inefficient. There are
however ways to optimize this. You can notice a regularity, for
example, in the ones column. Values almost repeat the binary weights
(1,2,4,8,6,2,4,8,6,2). That means that we can separate the binary word
in repeatable strings and add these strings together, which would be
the same if we tested each bit.
First, we need to modify the table to see how to separate the bits in
strings:
bit weight hundreds tens ones
------- ------- ------- ------ -------
0 1 0 0 1
1 2 0 0 2
2 4 0 0 4
3 8 0 0 8
4 16 0 1 1+5
5 32 0 2+1 2
6 64 0 4+2 4
7 128 1 2 8
8 256 2 5 1+5
9 512 4+1 1 2
So, the calculations would be:
ones = b[3:0] + b[7:4] + b[9:8] + 5*(b[4] + b[8])
tens = b[6:4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
hund = b[9:7] + b[9]
However, first two sums may exceed the 0 to 9 range, so we would have
to check for that and propagate the overflow to tens and hundreds.
Let's see what the code does...
; add b[3:0] + b[7:4] for ones
swapf NumL, w ;Add the upper and lower nibbles
addwf NumL, w ;to get the one's digit
andlw 0x0F
; if sum is bigger than 15 (DC is set), add 16 to BCD result
skpndc ;Go through a binary to bcd
addlw 0x16 ;conversion for just the one's
; if lower digit overflowed again, add 16 again
skpndc ;digit
addlw 0x06
; make sure the lower digit is in 0..9 range. If not, do BCD
; correction (add 6)
addlw 0x06
skpdc
addlw -0x06
; add now 5*b[4] to ones accumulator and b[4] to tens, doing the
; BCD correction at the same time
btfsc NumL, 4 ;bit 4 is a special case
addlw 0x16 - 1 + 0x6
skpdc
addlw -0x06
; here we have converted already bits 0 to 4:
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
; --------------- -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; ----
; hund = b[9:7] + b[9]
; now just test bits 5 to 7 and add their decimal weights to
; tens only (bit 7 also affects hundreds). We can add maximum
; 11 to tens digit here, so it will be less than 16 and not overflow.
;now adjust the ten's digit
btfsc NumL, 5 ;2^5 = 32, so add 3 to the ten's
addlw 0x30 ;digit if bit 5 is set
btfsc NumL, 6 ;2^6 = 64, so add 6
addlw 0x60 ;if bit 6 is set
btfsc NumL, 7 ;2^7 = 128, so add 2 (the ten's
addlw 0x20 ;digit) if bit 7 is set
; do decimal correction for tens and propagate carry to hundreds
addlw 0x60 ;convert the ten's digit to bcd
clrf Hund
rlf Hund, f ;if there's a carry, then the input
btfss Hund, 0 ;was greater than 99.
addlw -0x60
movwf Tens_Ones
; Here we are done with bits 5 to 7 (except bit 7 for hundreds):
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
; --------------- -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; -------- ---- ------ ------
; hund = b[9:7] + b[9]
; test bit 8, and add what it contributes to ones and tens
movlw 0x66 ;2^8 = 256, so add 0x56 to Tens_Ones
btfsc NumH, 0
movlw 0x56 + 0x66 ;add 0x66 for decimal adjust
addwf Tens_Ones, f
; do decimal correction
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f
; Here we are done with bit 8:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
; --------------- ----- ------- ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; -------- ---- ------ ------ ------
; hund = b[9:7] + b[9]
; test bit 9 (it adds 2 to ones, 1 to tens, and 5 to hundreds),
; but ignore hundreds yet
movlw 0x66 ;2^9 = 512, so add 0x12 to Tens_Ones
btfsc NumH, 1
movlw 0x12 + 0x66
addwf Tens_Ones, f
skpnc
incf Hund, f
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f
; Now we have a ready result for ones and tens:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
; --------------- ------ ----- ------- ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; -------- ---- ------ ------ ------ -----
; hund = b[9:7] + b[9]
; now just test bits 7, 8, and 9 and add their share to hundreds
; (without any BCD correction, because we assume input value is
; between 0 and 999, so hundreds can't be more than 9)
btfsc NumL, 7 ;finish with hundreds
incf Hund, f
movlw 2
btfsc NumH, 0
addwf Hund, f
movlw 5
btfsc NumH, 1
addwf Hund, f
That's it!
Wait, let's optimize the last few lines...
; hund = b[9:7] + b[9]
rlf NumL, w ; copy bit 7 to carry
rlf NumH, w ; load w with bits 9 to 7
btfsc NumH, 1 ; add b[9]
addlw 1 ;
addwf Hund, f ; add it to hundreds
Questions:
I have not analyzed the code at http://www.piclist.org/techref/microchip/math/radix/b2a-16b3a2-ng.htm, but there seems to be an error somewhere. It works for numbers 0..299, but 300 comes up as "49:". From here on up, there are various points where it works as expected and others where it doesn't. Anyone have a fix?...and later comments:
I put your code back and still have a problem. I used the code you sent, which I compared with that on the website. They appear to be identical except that which you sent has more comments (or perhaps it's just that they are in the code instead of at the bottom).Now, here's something I didn't mention before: I'm running this on an 18c452. I've never had problems with instruction changes before, but appear to be having the problem now. I don't fully understand your code, but looking through it a bit, I see where the comments say "test bit 8," and a little below that is "do decimal correction." The decimal correction includes "incf Hund, f". On the 16 series chips, incf and decf affect only Z while on the 18C they affects C, DC, Z, OC, N. A couple lines down is a skpc and a couple more lines down is a skpdc. These are probably relying on status bits set in the addwf Tens_Ones,f a few lines up, but are, instead getting the status caused by the incf.
I've added some conditional assembly to save away the status and restore it where I've seen the problems. The code now seems to work fine. My modified code is below.
Finally THANKS for contributing your code and providing great support! I hope I can return the favor some day!
Code:
;Fast binary to decimal conversion (0..999)
;
;Input: NumH:NumL
;Output Hund:Tens_Ones (packed BCD)
;
;
;
;Size: 56 instructions
;Execution time (with return): 57
;
;8-July-2000 by Nikolai Golovchenko
;23-Aug-2001
;Based on 8bit BIN2BCD of Scott Dattalo
;-------------------------------------------
cblock
NumH
NumL
Hund
Tens_Ones
endc
ifdef __18C452
cblock
TempStatus ; Deal with instruction set changes from 16c to 18c
endc
endif
bin2dec999fast
; convert
; add b[3:0] + b[7:4] for ones
swapf NumL, w ;Add the upper and lower nibbles
addwf NumL, w ;to get the one's digit
andlw 0x0F
; if sum is bigger than 15 (DC is set), add 16 to BCD result
skpndc ;Go through a binary to bcd
addlw 0x16 ;conversion for just the one's
; if lower digit overflowed again, add 16 again
skpndc ;digit
addlw 0x06
; make sure the lower digit is in 0..9 range. If not, do BCD
; correction (add 6)
addlw 0x06
skpdc
addlw -0x06
; add now 5*b[4] to ones accumulator and b[4] to tens, doing the
; BCD correction at the same time
btfsc NumL, 4 ;bit 4 is a special case
addlw 0x16 - 1 + 0x6
skpdc
addlw -0x06
; here we have converted already bits 0 to 4:
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
; --------------- -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; ----
; hund = b[9:7] + b[9]
; now just test bits 5 to 7 and add their decimal weights to
; tens only (bit 7 also affects hundreds). We can add maximum
; 11 to tens digit here, so it will be less than 16 and not overflow.
;now adjust the ten's digit
btfsc NumL, 5 ;2^5 = 32, so add 3 to the ten's
addlw 0x30 ;digit if bit 5 is set
btfsc NumL, 6 ;2^6 = 64, so add 6
addlw 0x60 ;if bit 6 is set
btfsc NumL, 7 ;2^7 = 128, so add 2 (the ten's
addlw 0x20 ;digit) if bit 7 is set
; do decimal correction for tens and propagate carry to hundreds
addlw 0x60 ;convert the ten's digit to bcd
clrf Hund
rlf Hund, f ;if there's a carry, then the input
btfss Hund, 0 ;was greater than 99.
addlw -0x60
movwf Tens_Ones
; Here we are done with bits 5 to 7 (except bit 7 for hundreds):
; ones = b[3:0] + b[7:4] + b[9:8] + 5*b[4] + 5*b[8]
; --------------- -------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; -------- ---- ------ ------
; hund = b[9:7] + b[9]
; test bit 8, and add what it contributes to ones and tens
movlw 0x66 ;2^8 = 256, so add 0x56 to Tens_Ones
btfsc NumH, 0
movlw 0x56 + 0x66 ;add 0x66 for decimal adjust
addwf Tens_Ones, f
; do decimal correction
ifdef __18C452
movff status, tempstatus ; Save status so incf doesn't mess up C and DC
endif
skpnc
incf Hund, f
ifdef __18C452
movff tempstatus,status ; Restore the status
endif
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f
; Here we are done with bit 8:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
; --------------- ----- ------- ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; -------- ---- ------ ------ ------
; hund = b[9:7] + b[9]
; test bit 9 (it adds 2 to ones, 1 to tens, and 5 to hundreds),
; but ignore hundreds yet
movlw 0x66 ;2^9 = 512, so add 0x12 to Tens_Ones
btfsc NumH, 1
movlw 0x12 + 0x66
addwf Tens_Ones, f
ifdef __18C452
movff status, tempstatus ; Save so incf doesn't mess up C and DC
endif
skpnc
incf Hund, f
ifdef __18C452
movff tempstatus,status ; Restore saved status
endif
clrw
skpc
iorlw 0x60
skpdc
iorlw 0x06
subwf Tens_Ones, f
; Now we have a ready result for ones and tens:
; ones = b[3:0] + b[7:4] + 2*b[9] + b[8] + 5*b[4] + 5*b[8]
; --------------- ------ ----- ------- ------
; tens = 2*b[6:5] + b[4] + b[6:5] + 2*b[7] + 5*b[8] + b[9]
; -------- ---- ------ ------ ------ -----
; hund = b[9:7] + b[9]
; now just test bits 7, 8, and 9 and add their share to hundreds
; (without any BCD correction, because we assume input value is
; between 0 and 999, so hundreds can't be more than 9)
; btfsc NumL, 7 ;finish with hundreds
; incf Hund, f
; movlw 2
; btfsc NumH, 0
; addwf Hund, f
; movlw 5
; btfsc NumH, 1
; addwf Hund, f
;That's it!
;Wait, let's optimize the last few lines...
; hund = b[9:7] + b[9]
rlf NumL, w ; copy bit 7 to carry
rlf NumH, w ; load w with bits 9 to 7
btfsc NumH, 1 ; add b[9]
addlw 1 ;
addwf Hund, f ; add it to hundreds
return
Do you acknowledge that it is correct time to get the business loans, which would realize your dreams.+
See also:
| file: /Techref/microchip/math/radix/b2a-16b3a2-ng.htm, 25KB, , updated: 2012/1/24 10:00, local time: 2013/5/24 05:18,
owner: NG--944,
50.19.155.235:LOG IN |
| ©2013 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://piclist.com/techref/microchip/math/radix/b2a-16b3a2-ng.htm"> PIC Microcontoller Radix Math Method Binary to ASCII, 16 bit to 3digits (0..999) FAST</A> |
| Did you find what you needed? |
|
o List host: MIT, Site host massmind.org, Top posters @20130524 RussellMc, IVP, Bob Blick, alan.b.pearce, John Gardner, veegee, Sean Breheny, Isaac Marino Bavaresco, Carl Denk, Josh Koffman, * Page Editors: James Newton, David Cary, and YOU! * Roman Black of Black Robotics donates from sales of Linistep stepper controller kits. * Ashley Roll of Digital Nemesis donates from sales of RCL-1 RS232 to TTL converters. * Monthly Subscribers: None at this time. on-going support is MOST appreciated! * Contributors: Richard Seriani, Sr. |
Welcome to piclist.com! |
.