Searching \ for 'Optimized binary to BCD Conversion' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page:
Search entire site for: 'Optimized binary to BCD Conversion'.

Truncated match.
PICList Thread
'Optimized binary to BCD Conversion'
1999\09\06@154913 by Jason Sachs

I'm getting tired of searching for such a useful
PIC subroutine and finding lots of mediocre code.

-------------- CONTEST --------------

What's the fewest # of instruction cycles required to
convert a 16-bit, 24-bit, or 32-bit binary number
to packed BCD on a PIC16Cxxx?

Constraints: code, when written as a subroutine,
 must fit into 256 bytes or less of program memory,
 unless it's elegant enough to justify the extra

Entry guidelines:
 * submit one .asm file that assembles under MPLAB
 * claim worst-case execution time in instructions
 * claim # of program memory bytes required
 * credit source if you borrowed parts of someone else's code
 * explain how it works

Prize: minor fame, satisfaction, etc.
(sorry if you were expecting $$!)


I've got a routine that converts 16- and 24-bit binary
to packed BCD, based on Mike Keitz's "b2bcd" posted
here last year. (msg forwarded at end)

 Program memory requirements: 81 words
 Execution time: 285 instr. for 16-bit
                 553 instr. for 24-bit

 This is also extensible to higher length #'s, and
 can also preserve the binary # used as an input
 with a 1-instruction per bit penalty. (i.e. a 24-bit
 "no-clobber" routine takes 577 instr.) A 32-bit
 extension to this would take slightly less than 900

 This code shifts in bits from the binary number,
 one at a time, and multiplies the resulting packed BCD
 number by 2 using a decimal adjust macro. (In other words,
 at the end of N loop iterations, the contents of the BCD memory
 is exactly equal to the result of converting the upper N
 bits of the binary input to packed BCD.)

 I get about a 50% speedup by separating
 the main loop into blocks of 8 bits. In other words,
 let's say I've got the number 12345678. (0xBC614E)

 The first 8 bits shifted in are only going to involve
 one byte of this number (0xBC) and, when this is
 converted to decimal, will result in, at most, the number
 0x00000255. The upper two bytes are going to stay 0's,
 so I don't need to involve them at all. The next byte
 is always between 0 and 2, so it needs to be involved
 in the bit-shifting process, but doesn't need to be
 decimal-adjusted since the upper 4 bits are always 0.

 Similarly for other bytes. The upper byte never needs
 a full decimal adjust, at most just the lower nybble,
 since it never overflows (otherwise you didn't leave
 enough space for the result!).

 This saves a lot of shifting around and adjusting zeros,
 though it lengthens the code quite a bit. (Without this
 optimization, I've got a 41-word routine that converts
 24-bit binary in 849 instructions.)

 (I'm curious if there are different approaches that work
 at similar speeds.)

 Program follows.

       include ""
       RADIX dec

#define ifzero  btfsc   STATUS, Z
#define ifnzero btfss   STATUS, Z
#define ifdcarry btfsc  STATUS, DC
#define ifndcarry btfss STATUS, DC
#define ifbit0  btfss
#define ifbit1  btfsc

;; bcd and bin are organized MSB first, so that
;; they can be used with MPLAB's Watch window
;; as a multibyte number.

cblock 0x20
#define nbit8   0
#define nbit16  1
#define nbit24  2

       org 0x0
       goto start


#define num (12345678)
       movlw   low (num >> 16)
       movwf   bin2
       movlw   low (num >> 8)
       movwf   bin1
       movlw   low (num)
       movwf   bin0
#undefine num

       call    bin24tobcd

#define num (54321)
       movlw   low (num >> 8)
       movwf   bin2
       movlw   low (num)
       movwf   bin1
#undefine num

       call    bin16tobcd

       goto    after16

;;;;;;;;;;;;;;;;;;;;; subroutines ;;;;;;;;;;;;;;;;;;;;;;;;;

;; bin[X]tobcd: convert binary to packed BCD
;; Attempt at optimization by J Sachs, 9/6/99
;;  input: binary # in bin[2:0]
;;            bin2  bin1  bin0
;;    16-bit: MSB   LSB
;;    24-bit  MSB    B    LSB
;;    (example: 12345678 = 0xbc614e
;;      -> bin2 = 0xbc, bin1 = 0x61, bin0 = 0x4e)
;;  input clobbered by this routine.
;;  (#define NOCLOBBER preserves input, at expense of extra
;;   code execution time, 1 instruction per bit.)
;;  output: packed BCD # in bcd[3:0]
;;            bcd3  bcd2  bcd1  bcd0
;;    16-bit:  00    0A    BC    DE
;;    24-bit:  AB    CD    EF    GH
;;    (example: 0x12345678 is encoded
;;      -> bcd3 = 0x12, bcd2 = 0x34, bcd1 = 0x56, bcd0 = 0x78)

;; uncomment following line to preserve input
;; #define NOCLOBBER

       movlw   (1 << nbit24)
       goto    bintobcd
       movlw   (1 << nbit16)
       movwf   nbit
       clrf    bcd             ;clear result to all 0.
       clrf    bcd2
       clrf    bcd1
       clrf    bcd0

;;;;;;; BCD adjust-prior-to-multiply-by-two routine from Mike Keitz
;;;;;;; converted to macro here. (7 instructions looks like optimum.)
;;;;;;; Also added a half-byte adjust macro. (4 instructions optimum?)

;;; BCD adjust.
bcdadj  macro reg
       movlw   h'33'
       addwf   reg,f          ;Add to low and high nybbles
       btfsc   reg,3
       andlw   h'f0'           ;Low result >7 . OK (take the 3 out)
       btfsc   reg,7
       andlw   h'0f'           ;Hi > 7 OK.
       subwf   reg,f          ;any results <=7, subtract back.

;;; BCD half-adjust (lower-nybble only)
bcdhadj macro reg
       movlw   3
       addwf   reg,f           ; Add 3.
       ifbit0  reg,3           ; result yields <= 7?
                               ;  original # was 0-4! undo!
       subwf   reg,f           ; otherwise, original # was
                               ;  5-9, we should add 3.

       ;; Shift in leftmost 8 bits.
       ;; Bytes involved: bin2, bcd0, bcd1
       ;; Max # is 0x0255 -> bcd1 adjustment unneeded.
       movlw   8
       movwf   tmpi
       rlf     bin2,w          ; preload carry if byte needs preserving.
       rlf     bin2,f
       rlf     bcd0,f
       rlf     bcd1,f
       decfsz  tmpi,f            ; loop until index 0.
       goto    btobcd01

       ;; 8 bits completed.

       ;; Shift in next 8 bits.
       ;; Bytes involved: bin1, bcd0, bcd1, bcd2
       ;; Max # is 0x065535 -> bcd2 adjustment unneeded.
       movlw   8
       movwf   tmpi
       rlf     bin1,w          ; preload carry if byte needs preserving.
       rlf     bin1,f
       rlf     bcd0,f
       rlf     bcd1,f
       rlf     bcd2,f
       decfsz  tmpi,f            ; loop until index 0.
       goto    btobcd02

       ifbit1  nbit, nbit16
       ;; 16 bits completed.

       ;; Shift in next 8 bits.
       ;; Bytes involved: bin0, bcd0, bcd1, bcd2, bcd3
       ;; Max # is 0x16777215 -> bcd3 needs only a half-adjust
       movlw   8
       movwf   tmpi
       rlf     bin0,w          ; preload carry if byte needs preserving.
       rlf     bin0,f
       rlf     bcd0,f
       rlf     bcd1,f
       rlf     bcd2,f
       rlf     bcd3,f
       decfsz  tmpi,f            ; loop until index 0.
       goto    btobcd03


> {Original Message removed}

1999\09\06@173825 by Mike Keitz

picon face
On Mon, 6 Sep 1999 15:42:10 -0400 Jason Sachs <spam_OUTjsachsTakeThisOuTspamDEKARESEARCH.COM>
> I've got a routine that converts 16- and 24-bit binary
> to packed BCD, based on Mike Keitz's "b2bcd" posted
> here last year. (msg forwarded at end)

I see you've alrady found my entry.  I like the BCD multiply by 2 method
especially as the numbers get larger.  It is probably the best for speed.
Methods based on division may save space if you already have a division
routine in the program for some other purpose and can reuse it.

Get the Internet just the way you want it.
Free software, free e-mail, and free Internet access for a month!
Try Juno Web: dl.

More... (looser matching)
- Last day of these posts
- In 1999 , 2000 only
- Today
- New search...