BCD to HEX in assembly

Thread Starter

Jefecito20

Joined Apr 26, 2010
6
I'm not sure this is the correct forum for this, but since I'm not a member of any other technical forums I thought I'd give it a shot anyway.

I'm writing a program to convert 2-digit BCD number to HEX number is assembly (using Turbo Assembler/TASM). So far this is the code I've written, but it's giving wrong outputs. Can anyone find what is wrong with it?

Rich (BB code):
.model small
.stack 100

.data
msg1 db 10,13,"Enter the 2 digit BCD number: $"
msg2 db 10,13,"The equivalent HEX number is: $"
no db ?

.code
        main proc
        mov ax,@data
        mov ds,ax

        lea dx,msg1
        mov ah,9
        int 21h

        mov ah,1
        int 21h
        sub al,30h
        sub dl,10
        mul dl
        mov no,al
        mov ah,1
        int 21h
        cmp al,0dh
        je exit

        sub al,30h
        add no,al

        lea dx,msg2
        mov al,9
        int 21h

        mov al,no
        and al,0f0h
        mov cl,4
        shr al,cl
        mov dl,al
        cmp dl,9
        jg alpha1
        add dl,30h
        jmp next

alpha1: add dl,37h

next:   mov ah,2
        int 21h

        mov al,no
        and al,0fh
        mov dl,al
        cmp dl,9
        jg alpha2
        add dl,30h
        jmp next2

alpha2: add dl,37h

next2:  mov ah,2
        int 21h
        jmp exit1

exit:   lea dx,msg2
        mov ah,9
        int 21h

        mov al,no
        mov cl,10
        mov ah,0
        div cl
        mov dl,al
        add dl,30h
        mov ah,2
        int 21h

exit1:  mov ah,4ch
        int 21h
        main endp
        end main
 

311499

Joined Apr 29, 2010
5
The only bugs I could find were:
"sub dl,10" (should be MOV DL, 10)
"mov al,9" (should be MOV AH, 9)
Rich (BB code):
.model small
.stack 100    ;did you mean 100h?

.data
msg1 db 10,13,"Enter the 2 digit BCD number: $"
msg2 db 10,13,"The equivalent HEX number is: $"
no db ?

.code
        main proc
        mov ax,@data
        mov ds,ax

        lea dx,msg1
        mov ah,9
        int 21h

        mov ah,1
        int 21h
        sub al,30h    ;you can also use "AND AL, 0FH"
        MOV DL, 10    ;not "sub dl,10"
        mul dl
        mov no,al
        mov ah,1
        int 21h
        cmp al,0dh
        je exit

        sub al,30h    ;you can also use "AND AL, 0FH"
        add no,al

        lea dx,msg2
        MOV AH, 9    ;not "mov al,9"
        int 21h

        mov al,no    ;you can move the variable directly into DL also
;        and al,0f0h    ;not required as the SHR below deletes bits 3..0
        mov cl,4
        shr al,cl
        mov dl,al
        cmp dl,9
        jg alpha1    ;instead of "jg" you can use JA (preferred for unsigned numbers)
        add dl,30h    ;you can also use "OR DL, 30H" (I don't know if it's any faster
    ;though)
        jmp next

alpha1: add dl,37h

next:   mov ah,2
        int 21h

        mov al,no    ;you can move the variable directly into DL also
        and al,0fh
        mov dl,al
        cmp dl,9
        jg alpha2    ;JA preferred for unsigned numbers (by me at least)
        add dl,30h
        jmp next2

alpha2: add dl,37h

next2:  mov ah,2
        int 21h
        jmp exit1

exit:   lea dx,msg2
        mov ah,9
        int 21h

        mov al,no
        mov cl,10
        mov ah,0    ;"XOR AH, AH" is also possible and useful with words/dwords as it
    ;makes the instruction shorter, e.g., "XOR BX, BX" instead of "MOV BX, 0".
    ;Additionally, you can use CBW here (a one-byte instruction) as bit 7 is clear in AL
    ;(CBW stands for "convert byte to word". It reads AL and sets AH to either 0 or 0FFH,
    ;depending on the setting of bit 7 in AL. CBW is for signed numbers primarily but it
    ;can replace an "XOR AH, AH" or a "MOV AH, 0FFH", provided you know how bit 7 is set
    ;in AL).
        div cl
        mov dl,al    ;you can use "XCHG DX, AX" to make the ins one byte shorter
        add dl,30h    ;"OR DL, 30H" can also be used (somehow I think it's faster)
        mov ah,2
        int 21h

exit1:  mov ah,4ch
        int 21h
        main endp
        end main
;"JMP SHORT" can be used in many cases to replace a "jmp" (one byte shorter)
This is my tested rewrite of the program:
Rich (BB code):
.MODEL SMALL
.STACK 00100H

.DATA

MSG1 DB 00DH, 00AH, "Enter the 2 digit BCD number: $"
MSG2 DB 00DH, 00AH, "The equivalent HEX number is: $"

NR DB 10

.CODE

    MAIN PROC
MOV AX, @DATA
MOV DS, AX
LEA DX, [MSG1]
MOV AH, 009H
INT 021H
MOV AH, 001H
INT 021H
AND AL, 00FH
MUL BYTE PTR [NR]
MOV [NR], AL
MOV AH, 001H
INT 021H
CMP AL, 00DH
JE EXIT
AND AL, 00FH
ADD [NR], AL
LEA DX, [MSG2]
MOV AH, 009H
INT 021H
MOV DL, [NR]
PUSH DX
MOV CL, 004H
SHR DL, CL
OR DL, 030H
MOV AH, 002H
INT 021H
POP DX
AND DL, 00FH
OR DL, 030H
CMP DL, 03AH
JB NEXT
ADD DL, 007H
    NEXT:
MOV AH, 002H
INT 021H
JMP SHORT EXIT1
    EXIT:
LEA DX, [MSG2]
MOV AH, 009H
INT 021H
MOV AL, [NR]
CBW
MOV CL, 10
DIV CL
XCHG DX, AX
OR DL, 030H
MOV AH, 002H
INT 021H
    EXIT1:
MOV AH, 04CH
INT 021H
MAIN ENDP

END MAIN
A useful way for printing hex digits is one that uses the XLAT instruction:
Rich (BB code):
    WRHEX24:    ;WRITE 24 BIT NUMBER IN DL:AX
PUSH AX
MOV AL, DL
CALL WRHEXB
POP AX
    WRHEXW:    ;WRITE 16 BIT NUMBER IN AX
PUSH AX
MOV AL, AH
CALL WRHEXB
POP AX
    WRHEXB:    ;WRITE 8 BIT NUMBER IN AL
PUSH AX
SHR AL, 004H
CALL WRHEXN
POP AX
    WRHEXN:    ;WRITE 4 BIT NUMBER IN LOW BITS OF AL
PUSH AX
PUSH BX
MOV BX, OFFSET HEXCH
AND AL, 00FH
SEGCS XLAT
CALL PRINTCH
POP BX
POP AX
RET

    PRINTCH:    ;PRINT CHARACTER IN AL
PUSH AX
PUSH DX
MOV DL, AL
MOV AH, 002H
INT 021H
POP DX
POP AX
RET

HEXCH DB "0123456789ABCDEF"
The above is a fragment of a protected mode program I wrote, with
the procedure PRINTCH adapted for DOS (using INT 21H).

Have fun!
 
Top