packed decimal to ascii assembly

Dalton Conley picture Dalton Conley · Nov 9, 2010 · Viewed 8.3k times · Source

I'm trying to convert packed decimal numbers into ascii strings. Here is my understanding thus far:

The following:

bcd BYTE 34h

Should convert to the decimal number 34 after being "unpacked". Now I'm not sure on the best way of doing this. If I convert this hexadecimal number to binary it is as follows...

0011 0100 

Now, if I have my procedure print out each 4bit binary value at a time, then it should print the ascii string of numbers, correct? So if I go through a loop, grab the first 4 bit binary number, print its actual value out, its going to print 3.. then do the same, its going to print 4.

So, here is my general idea:

Take an 8bit value "34h", mov it into AH and AL. In AH, clear the second half of the bits using the follow:

and ah, 11110000b

and in AL, clear the first half of the bits using the following:

and al, 00001111b

So AH = 0110b or 3 And AL = 0100b or 4, then print these out accordingly..

Is this a good approach? Or am I going about completely incorrect or way over thinking it?

EDIT: Here is my final solution with original value of 12345678h. Thanks to all who helped!

;-----------------------------------------------------------------------------
PackedToAsc PROC USES eax ebx edx ecx esi
; This function displays a packed decimal value in its "ascii" form
; i.e. 12345678h would display decimal, 12345678 in decimal form
; 
; Requires ECX = SIZEOF packed decimal
;          ESI to be pointing to the packed decimal
;-----------------------------------------------------------------------------
mov edx, [esi]              ; temp store our offset
mov eax, 0                  ; clear eax
mov ebx, 0                  ; clear ebx

L1: rol edx, 8              ; rotate left 8 bits to avoid little endian 
    mov [esi], edx          ; mov our temp back to the actual value

    mov al, BYTE PTR [esi]  ; al = 12h  0001 0010
    mov bl, BYTE PTR [esi]  ; bl = 12h  0001 0010
    shr al, 4               ; al = 0000 0001
    and bl, 00001111b;      ; bl = 0000 0010
    add al, 48              ; convert to ascii
    call WriteChar          ; display al
    mov al, bl
    add al, 48              ; convert to ascii
    call WriteChar          ; display bl
    loop L1

    call Crlf
ret
PackedToAsc END

P

Answer

slashmais picture slashmais · Nov 9, 2010

BCD uses only the digits 0 thru 9.
An unpacked BCD digit uses the lower nibble of an entire byte and to convert it to ASCII you add 48.
The number 34h is 52 decimal and will be represented as an unpacked BCD as 00000101 and 00000010
(Changed to avoid confusion when using built-in instructions) When it is packed: 01010010 == BCD packed 52

To unpack it, you can do as you have done, but you need to shift AH right to place the value in the lo-nibble. To convert to ASCII just add 48.

[edit]

MASM (=> ALL instructions, Linux included) that runs on 80x86 processors uses the little-endian scheme. CPUs such as Motorola 68000 (Apple Mac) and RISC uses big-endian.

When you store a number as BCD, the least significant byte is at the lowest address thru to the most-significant at the highest, e.g.:

my_unpacked_bcd  DB 4,3,2,1 ; this is the decimal number 1234
my_packed_bcd    DW 3412h  ; this defines the same number as packed

Packed BCD depends on what you want to do with it. If you want to ADD, MUL, DIV, SUB you must present the values as required by these instructions. Also remember to add zero-bytes to start and end of your digits to hold carries.