Search code examples
assemblybit-manipulationmasmirvine32

How do I perform bitwise multiplication/division in MASM x86 assembly?


I have been tasked with writing a MASM x86 assembly program which multiplies/divides two 16 bit numbers by bit shifting. What I have so far is:

INCLUDE Irvine32.inc

.data
count BYTE -1
val1  SDWORD  ?  
val2  SDWORD  ?
str1  BYTE "Enter Integer 1 here: ",0 ; 
str2  BYTE "Enter Integer 2 here: ",0
str3  BYTE "The product is: ",0
mval WORD ?
mval2 WORD ?
pval WORD ?

.code
call clrscr
main PROC
    mov dh,10
    mov dl,20
    call Gotoxy
    mov edx, OFFSET str1
    call WriteString
    call ReadInt
    mov mval,ax

    mov dh,12
    mov dl,20
    call Gotoxy
    mov edx, OFFSET str2
    call WriteString
    call ReadInt
    mov mval2,ax

    mov dh, 14
    mov dl, 20
    call Gotoxy
    mov edx, OFFSET str3
    call WriteString
    mov ax,pval
    call WriteInt
    call crlf
    call waitmsg

    mov eax,0
    mov ax,mval2
    mov ecx, 16

    L1:
    shr bx,1
    INC count
    JNC DontAdd

    push ecx
    mov ax,mval
    mov cl,count
    shl dx,cl
    add ax,dx
    pop ecx

    DontAdd:
    LOOP L1
    call waitmsg
    exit
main ENDP
END main

How would I correctly implement bitwise multiplication/division?


Solution

  • You are at a point, where you should work with procedures to keep track of the code. Take a look at this 32-bit example and convert it to 16-bit:

    INCLUDE Irvine32.inc
    
    .data
    
        First       DWORD ?
        Second      DWORD ?
        Result      DWORD ?
        GetFirst    BYTE "1st number: ",0
        GetSecond   BYTE "2nd number: ",0
        Linefeed    BYTE 13, 10, 0
        MulSign     BYTE " * ",0
        DivSign     BYTE " / ",0
        EquSign     BYTE " = ",0
    
    .code
    main PROC
    
        mov edx, OFFSET GetFirst
        call WriteString
        call ReadDec
        mov First, eax
    
        mov edx, OFFSET GetSecond
        call WriteString
        call ReadDec
        mov Second, eax
    
        mov ebx, First
        mov eax, Second
        call BitwiseMultiply
        mov Result, eax
    
        mov eax, First
        call WriteDec
        mov edx, OFFSET MulSign
        call WriteString
        mov eax, Second
        call WriteDec
        mov edx, OFFSET EquSign
        call WriteString
        mov eax, Result
        call WriteDec
        mov edx, OFFSET Linefeed
        call WriteString
    
        mov eax, First
        mov ebx, Second
        call BitwiseDivide
        mov Result, eax
    
        mov eax, First
        call WriteDec
        mov edx, OFFSET DivSign
        call WriteString
        mov eax, Second
        call WriteDec
        mov edx, OFFSET EquSign
        call WriteString
        mov eax, Result
        call WriteDec
        mov edx, OFFSET Linefeed
        call WriteString
    
        exit
    main ENDP
    
    ; Multiply EBX by EAX
    BitwiseMultiply PROC USES EBX ECX EDX
        mov edx, eax            ; EDX: multiplier (EBX: multiplicand)
        xor eax, eax            ; Result will be in EAX - clear it
        bsr ecx, edx            ; ECX = position of the most significant bit
        jz R1                   ; Return with EAX=0 if EDX == 0
    
        L1:
        shr edx, 1              ; Look at the rightmost bit of the multiplier
        jnc @F                  ; Skip addition if this bit == 0
        add eax, ebx            ; Add multiplikand to result
        @@:
        shl ebx, 1              ; Increase multipland for the next round
        sub ecx, 1              ; Decrease loop variable
        jnc L1                  ; Loop if ECX >= 0
    
        R1:
        ret                     ; Result in EAX
    BitwiseMultiply ENDP
    
    ; Divide EAX by EBX
    BitwiseDivide PROC USES ECX EDX ESI
        mov esi, eax            ; ESI: dividend (EBX: divisor)
        xor eax, eax            ; Result (quotient) = 0
        xor edx, edx            ; EDX = 0 (start value)
        mov cl, 32              ; 32 loops
    
        L1:
        shl esi, 1              ; Bit 31 from EAX ...
        rcl edx, 1              ;     ... to Bit 1 of EDX
        cmp ebx, edx            ; Carry, if EDX > Divisor
        ja @F                   ; Skip subtraction if carry==0 and zero==0 (result not zero)
        sub edx, ebx            ; Subtract ...
        stc                     ;     ... and set carry
        @@:
        rcl eax, 1              ; Append carry (0 or 1) to quotient.
        sub cl, 1
        jnz L1                  ; loop while CL > 0
    
        ret                     ; Result in EAX
    BitwiseDivide ENDP
    
    END main