Multiply two unsigned 16-bit values ​​without using the multiply or divide instructions [8086 Assembly]

I am currently working on an assignment where I write a subroutine where 2 unsigned numbers are multiplied and give the result in a DX: AX pair. But I cannot use the mul, imul, div and idiv statements. When I run my code, the bottom half (the AX register) is always correct, but the DX register is not. Can anyone point me in the right direction as to what I am doing wrong?

;-----------------------------------------------------------
;
; Program:  MULTIPLY
;
; Function: Multiplies two 16 bit unsigned values ...
;           .... duplicating the MUL instruction
;
; Input:    The two values to be multiplied are passed on the stack
;           The code conforms to the C/C++ calling sequence
;
; Output:   The 32 bit result is returned in the dx:ax pair
;           Registers required by C/C++ need to be saved and restored
;
; Owner:    Andrew F.
;
; Changes:  Date        Reason
;           ------------------
;           07/20/2013  Original version
;
;
;---------------------------------------
         .model    small
         .8086
         public    _multiply

         .data
;---------------------------------------
; Multiply data
;---------------------------------------


         .code
;---------------------------------------
; Multiply code
;---------------------------------------
_multiply:                             
         push      bp                  ; save bp
         mov       bp,sp               ; anchor bp into the stack
         mov       ax,[bp+4]           ; load multiplicand from the stack
         mov       dx,[bp+6]           ; load multiplier   from the stack

    push    bx
    push    cx
    push    di
;---------------------------------------
; copy ax to cx, and dx to bx
;---------------------------------------  
    mov cx,ax       ;using bx and cx as my inputs
    mov bx,dx
;---------------------------------------
; Check for zeros, zero out ax and dx
;---------------------------------------  
start:
    xor   ax,ax         ; check for multiplication by zero
    mov   dx,ax         ; and zero out ax and dx
    mov   di,cx     ; 
    or    di,bx         ; 
    jz    done      ;
    mov   di,ax         ; DI used for reg,reg adc
;---------------------------------------
; loop / multiply algorithm
;---------------------------------------  
loopp:
    shr   cx,1          ; divide by two, bottom bit moved to carry flag
    jnc   skipAddToResult   ;no carry -> just add to result
    add   ax,bx     ;add bx to ax 
    adc   dx,di         ;add the carry to dx

skipAddToResult:
    add   bx,bx         ;double bx current value
    or    cx,cx         ; zero check
    jnz   loopp     ; if cx isnt zero, loop again


;---------------------------------------
; Restore register values, return
;---------------------------------------  
done:
     pop       di           ;restore di
     pop       cx           ;restore cx
     pop       bx           ;restore bx

         pop       bp                  ; restore bp
         ret                           ; return with result in dx:ax
                                       ;
         end                           ; end source code
;---------------------------------------

      

+3


source to share


1 answer


You are using strangely di

when adding another shifted value bx

. Your algorithm looks like this:

  • Collect the values, put them in BX and CX.
  • While CX> 0:
    • Shift CX to the right.
    • If the shifted bit has one, add BX to AX and add DI (zero to DI?) To DX with carry.
    • Add BX to BX.
  • Return DX: AX.


You are missing a left shift DI: BX after each right shift CX. You only move BX (and I would use shl bx,1

instead add bx,bx

) and DI stayed at zero, so when BX is over 16 bits, you lose a bit that should go to DX. To fix it, use rotation through translation with DI.

loopp:
    shr   cx,1          ; divide by two, bottom bit moved to carry flag
    jnc   skipAddToResult   ;no carry -> just add to result
    add   ax,bx     ;add bx to ax 
    adc   dx,di         ;add the carry to dx

skipAddToResult:
    shl   bx,1         ;double bx current value
    rcl   di,1         ; and put overflow bits to DI
                       ; this together doubles the number in DI:BX
    or    cx,cx         ; zero check
    jnz   loopp     ; if cx isnt zero, loop again

      

+3


source







All Articles