Email: Password: Remember Me | Create Account (Free)

Back to Subject List

Thread Closed: Issue successfully resolved

???
09/12/04 16:11
Read: times


 
Msg Score: +2
 +2 Informative
 -2 Gimmee Code
 +2 Good Answer/Helpful
#77273 - RE: Quesiton about bin to dec
Responding to: ???'s previous message
Conversion of wide numbers in binary format to an ASCII decimal representation is a question that comes up often on this forum. I choose to add to the available pool of information by offering a specific solution to the problem posed by WONF CHI FAI by showing some standard 8051 assembly language code that can convert 40-bit (5 byte numbers) into a decimal ASCII string. You can see the code below. Alternately you may link to it in a separate WEB page by clicking this link: http://www.8052.com/users/mkaras/CVT_DEC.A51

I want to direct attention to some nice code that one member here, Graham Cole, has posted at http://www.programmersheaven.com/zone5/cat.../32144.htm . I extended his fast 32-bit divide routine to make the 40-bit routine used in the code I present below.

Michael Karas

;
;
; This program permits conversion of a 40-bit number to decimal 
; for display.
;
$NOMOD51
$INCLUDE(REG51FX.INC)               ; register definitions compatible 
                                    ; with standard Intel architecture FX cpu

ASCII   EQU     '0'                 ; set to the offset to add to each result digit
                                    ; use zero for decimal binary digits
                                    ; use '0' for decimal ascii digits

        USING   0                   ; use register block 0

;***************************************************
; INTERNAL DATA BIT DEFINITIONS, locations 20H-2FH
;---------------------------------------------------

BSEG    AT      00

TEMPB:
        DBIT    1                   ; temporary bit number

;***************************************************
; INTERNAL DATA BYTE DEFINITIONS
;---------------------------------------------------

;internal data area variables.
;
DSEG    AT      30H                 ; word locations are HIGH:LOW

BITS40:
        DS      5                   ; the 5 byte (40 bit number to convert)

        DS      11                  ; make memory dump nice
RESULT:
        DS      15                  ; result buffer string

STACK:
        DS      20                  ; reserve 20 bytes of space
RAM_END:
        DS      1                   ; end of allocated RAM marker

;***************************************************
; INTERRUPT VECTOR DEFINITIONS
;---------------------------------------------------

CSEG    AT      0000H               ; reset vector
        JMP     PWR_UP              ; power-on entry point

CSEG    AT      0003H               ; intr 0 vector
        CLR     EX0                 ; external int 0 not used
        RETI

CSEG    AT      000BH               ; timer 0 vector
        RETI                        ; not used

CSEG    AT      0013H               ; intr 1 vector
        CLR     EX1                 ; external int 1 not used
        RETI

CSEG    AT      001BH               ; timer 1 vector
        RETI                        ; not used

CSEG    AT      0023H               ; UART vector
        CLR     ES                  ; serial port int not used
        RETI

;***************************************************
; BASE OF CODE AREA
;---------------------------------------------------

CSEG    AT      040H
        DB      'Copyright (C) Carousel Design 2004',0

;***************************************************
; NAME: DIV_BY_10
;   This routine divides a five byte number in RAM
;   @R0 by 10 and leaves the quotient at same
;   location and returns the remainder in A
;
; Note: This routine is an adapted version of
;   code from one of Graham Cole's submissions at
;	www.programmersheaven.com. I changed his 32-bit
;   divide by 1->16 to a fixed 40-bit divide by 10
;---------------------------------------------------

DIV_BY_10:
        PUSH    B                   ; save entry B register
        MOV     B, R0               ; save the entry pointer R0 value
        PUSH    B
        MOV     B, R2               ; save entry R2 value
        PUSH    B
        MOV     B, R3               ; save entry R3 value
        PUSH    B
;
        MOV     A, @R0              ; get the MS byte of dividend and divide
        MOV     B, #10              ; it by the divisor of 10.
        DIV     AB
        MOV     @R0, A              ; store result of division as quotient.
;
        MOV     A, B                ; save the remainder (which must be in 
        SWAP    A                   ; the range 0...9) shifted four bits
        MOV     B,A                 ; to the left.
;
        INC     R0                  ; point to next byte of the number
        MOV     R2, #4              ; load loop counter.
;
DIV_BY_10_LOOP:
        MOV     A, @R0              ; get the MS nibble of the 
        SWAP    A                   ; dividend into the accumulator.
        ANL     A, #0x0F
        ORL     A, B                ; or in remainder from last iteration.
;
        MOV     B, #10              ; divide MS nibble by the divisor of 10
        DIV     AB
        SWAP    A                   ; save partial result (which must be 
        MOV     R3, A               ; in the range 0...9) shifted 4 bits.
;
        MOV     A, B                ; read remainder (which must be in
        SWAP    A                   ; the range 0...9) and shift 4 bits left.
;
        XCHD    A, @R0              ; get next nibble of the dividend into acc
;
        MOV     B, #10              ; divide by the divisor of 10.
        DIV     AB
        ORL     A, R3               ; or in the previously saved partial result.
        MOV     @R0, A              ; save the MSB of the quotient ready
                                    ; to be returned.
;
        MOV     A, B                ; save remainder
        SWAP    A                   ; shifted 4 bits left
        MOV     B, A                ; in B.
;
        INC     R0                  ; increment the pointer through number buffer
        DJNZ    R2, DIV_BY_10_LOOP  ; decrement number of bytes we are working across
                                        
        SWAP    A                   ; final remainder is in upper nibble
;
        POP     B
        MOV     R3, B               ; restore original R3
        POP     B
        MOV     R2, B               ; restore original R2
        POP     B
        MOV     R0, B               ; restore the original R0
        POP     B                   ; restore entry B
        RET

;***************************************************
; NAME: CHK_FOR_0
;   This routine checks the five byte number @R0
;   for being zero/non-zero. The result is returned
;   in A. A=0 if number is zero.
;---------------------------------------------------

CHK_FOR_0:
        PUSH    B
        MOV     B, R0               ; save entry pointer
        PUSH    B
        MOV     B, R2               ; preserve R2   
;
        CLR     A                   ; start out with a zero value marker
        MOV     R2, #5              ; test a 5 byte number
CHK_FOR_0_LOOP:
        ORL     A, @R0              ; just or each byte into A
        INC     R0                  ; advance to next byte
        DJNZ    R2, CHK_FOR_0_LOOP  ; decrement the byte counter
;
        MOV     R2, B               ; restore R2 value
        POP     B
        MOV     R0, B               ; restore the entry pointer
        POP     B
        RET                         ; exit A as final or of all 5 bytes

;***************************************************
;NAME: CVT_TO_DEC
;   This routine converts the 5 byte number @R0 
;   to a decimal representation of the number 
;   at the buffer @R1. The ASCII decimal digits are
;   ordered in the result buffer from high to 
;   low order with leading zeros stripped off
;
;   The caller must ensure that the buffer at R1
;   has enough room for the maximal result decimal string 
;   plus one spot for the trailing null byte. 40-bit
;   numbers can represent up to 13 decimal digits so
;   the buffer should have at least 14 bytes of space
;---------------------------------------------------

CVT_TO_DEC:
        MOV     A, R2               ; save entry R2 value
        PUSH    ACC
        MOV     A, R0               ; save the entry pointers
        PUSH    ACC
        MOV     A, R1               
        PUSH    ACC
;
        MOV     A, #14              ; offset R1 to the end of buffer
        ADD     A, R1
        MOV     R1, A
        MOV     R2, #0              ; setup converted digit counter
;
CVT_TO_DEC_1:                       ; loop to divide by 10 till quotent goes to zero
        CALL    DIV_BY_10           ; get next result digit
        ADD     A, #ASCII           ; add on the desired type of digit offset
        MOV     @R1, A              ; save the decimal ascii digit
        DEC     R1                  ; decrement the digit pointer
        INC     R2                  ; count the digit just stored
        CALL    CHK_FOR_0           ; check for remainder all zeros
        JNZ     CVT_TO_DEC_1        ; convert till completed
;
        POP     ACC                 ; get a copy of the pointer to out buffer
        PUSH    ACC
        MOV     R0, A
        INC     R1                  ; adjust back to last stored digit
CVT_TO_DEC2:                    
        MOV     A, @R1              ; copy the result to head of buffer
        MOV     @R0, A
        INC     R0                  ; bump the copy pointers
        INC     R1
        DJNZ    R2, CVT_TO_DEC2
        MOV     A, #0               ; put a trailing null onto buffer
        MOV     @R0, A
;
        POP     ACC
        MOV     R1, A               ; restore entry R1 pointer
        POP     ACC
        MOV     R0, A               ; restore entry R0 pointer
        POP     ACC
        MOV     R2, A               ; restore the entry R2 value
        RET     

;***************************************************
; MAIN PROGRAM INITIALIZATION
;---------------------------------------------------

PWR_UP:
        MOV     SP, #STACK          ; set stack pointer
;
MAIN_LOOP:
;;      MOV     BITS40+0, #10011001B    ; initialize a 40 bit number from High to Low 
;;      MOV     BITS40+1, #10011001B    ; 1001100110011001100110011001100110011001B is
;;      MOV     BITS40+2, #10011001B    ; same as: 
;;      MOV     BITS40+3, #10011001B    ; 659706976665 in decimal
;;      MOV     BITS40+4, #10011001B     
;
;;      MOV     BITS40+0, #11111111B    ; initialize a 40 bit number from High to Low 
;;      MOV     BITS40+1, #11111111B    ; 1111111111111111111111111111111111111111B is
;;      MOV     BITS40+2, #11111111B    ; same as: 
;;      MOV     BITS40+3, #11111111B    ; 1099511627775 in decimal
;;      MOV     BITS40+4, #11111111B     
;
;;      MOV     BITS40+0, #00000000B    ; initialize a 40 bit number from High to Low 
;;      MOV     BITS40+1, #00000000B    ; 0000000000000000000000000000000000000001B is
;;      MOV     BITS40+2, #00000000B    ; same as: 
;;      MOV     BITS40+3, #00000000B    ; 1 in decimal
;;      MOV     BITS40+4, #00000001B     
;
        MOV     BITS40+0, #00011111B    ; initialize a 40 bit number from High to Low 
        MOV     BITS40+1, #01110001B    ; 0001111101110001111110110000010011001011B is
        MOV     BITS40+2, #11111011B    ; same as: 
        MOV     BITS40+3, #00000100B    ; 135056262347 in decimal
        MOV     BITS40+4, #11001011B     
;
        MOV     R0, #BITS40         ; convert the 40-bit number
        MOV     R1, #RESULT
        CALL    CVT_TO_DEC
;
        JMP     MAIN_LOOP           ; go wait for next tick time
    

        END



List of 5 messages in thread
TopicAuthorDate
Quesiton about bin to dec            01/01/70 00:00      
   RE: Quesiton about bin to dec            01/01/70 00:00      
   RE: Quesiton about bin to dec            01/01/70 00:00      
   RE: Quesiton about bin to dec            01/01/70 00:00      
      RE: Quesiton about bin to dec            01/01/70 00:00      

Back to Subject List