Search code examples
assemblyx86dosmasmx86-16

How to Convert Decimal to Binary in Assembly Language


Im having trouble analyzing this block of code in converting decimal values to binary. Can somebody help explain the lines of text below? This is a working code by the way. I would really appreciate the help, this is for studying purposes. Thanks you!

calc :
    mul multiplier
    mov bl, byte ptr [si]
    mov bh, 00h
    add ax, bx
    inc si
    loop calc

    mov si, offset buf4 + 2
    mov bx, ax
    mov dx, 0000h
    mov ax, 8000h
convert :
    mov cx, 0000h
conv :
    cmp bx, ax
    jb cont3
    sub bx, ax
    inc cx
    jmp conv
cont3 :
    add cl, 30h
    mov byte ptr [si], cl
    inc si
    mov cx, 0002h
    div cx
    cmp ax, 0000h
    jnz convert

    mov byte ptr [si], '$'
    prnstr buf3
    prnstr buf4+2
stop :
    mov ax, 4c00h
    int 21h

The first part of the code was no trouble to understand (Accepting user input and checking if its a valid decimal number). I already added some comments.. the first half of the code looks like this:

prnstr macro msg     ;acts like a function to print string
    mov ah, 09h
    lea dx, msg
    int 21h
    endm

data segment
    buf1 db "Enter a decimal number : $"
    buf2 db 0ah, "Invalid Decimal Number...$"
    buf3 db 0ah, "Equivalent Binary number is : $"
    buf4 db 6
         db 0
         db 6 dup(0)
    multiplier db 0ah
data ends

code segment
    assume cs:code, ds:data
    start :
    mov ax,@data
    mov ds,ax
    mov es, ax   

    prnstr buf1         ;Display

    mov ah, 0ah         ;Get line function
    lea dx, buf4        ;adress of input buffer
    int 21h

    mov si, offset buf1 + 2 ;Load pointer to beginning of structure
    mov cl, byte ptr [si-1] ;determine end of loop?
    mov ch, 00h
    subtract :
    mov al, byte ptr [si]   ;Load 1 byte of buf1 to cl
    cmp al, 30h             ;check if not below 0
    jnb cont1

    jmp stop
 cont1 :
    cmp al, 3ah         ;check if not above 9
    jb cont2
    prnstr buf2         ;Display
    jmp stop
 cont2 :
    sub al, 30h             ;convert ASCII to Decimal number
    mov byte ptr [si], al   ;place bcd form back to pointed character
    prnstr buf2             ;Display
    inc si                  ;next character
    loop subtract           ;repeat until end of string
    mov si, offset buf1 + 2 ;Load pointer to beginning of structure
    mov cl, byte ptr [si-1] ;reset to determine end of loop using si
    mov ch, 00h
    mov ax, 0000h           ;reset ax to 0

    ;...CONTINUE TO calc.....

Solution

  • The calc: loop keeps multiplying by 10 and accumulating, so it appears that it calculates the actual value of the number that was entered in decimal. (It converts the string you entered, say "42", to the number 42.)

    The remaining code converts the number that was calculated to binary. It is written in a kind of unorthodox way, to say the least.

    The instruction mov dx, 0000h clears dx, because further down the div cx instruction divides the dx:ax pair by cx, so if dx was not zero then you would get garbage.

    The ax register starts with the value 08000h which in binary is a 1 followed by 15 0s and in each iteration of the loop it keeps being divided by 2, so on each iteration a new binary digit of 0 enters in from the left side, the 1 binary digit is moved to the right by one position, and a 0 binary digit drops out from the right side.

    The check for ax against zero will stop looping when the 1 binary digit drops out after 16 iterations, leaving ax with all zeros.

    The conv: loop is a very unorthodox way of setting cx to 0 or 1 depending on whether the bit represented by ax is set or cleared in bx. This loop loops at most once, so I think that the jmp conv instruction could be missing, and it could just fell through to the cont2: label.

    Also note that loading 2 into cx and then executing div cx is retarded, you can just shr ax, 1.