将两个无符号16位值相乘,而不使用乘法或除法指令[8086汇编]

时间:2015-07-21 14:11:38

标签: assembly x86 masm x86-16

我正在进行一项任务,在那里我写了一个子程序,其中2个无符号数被乘以并在DX:AX对中产生结果。但我不能使用mul,imul,div和idiv的指令。当我运行我的代码时,下半部分(AX寄存器)总是正确的,但DX寄存器不是。任何人都可以指出我正确的方向,我做错了吗?

;-----------------------------------------------------------
;
; 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
;---------------------------------------

1 个答案:

答案 0 :(得分:3)

添加di的其他移位值时,您奇怪地使用bx。你的算法似乎是这样的:

  1. 收集值,将它们放入BX和CX。
  2. 当CX> 0时:
    1. 向右移动CX。
    2. 如果移位了一个,将BX添加到AX并将DI(在DI中为零)添加到带有进位的DX。
    3. 将BX添加到BX。
  3. 返回DX:AX。
  4. 在每次右移CX后,你都错过了DI:BX的左移。您正在仅移动BX(并且我使用shl bx,1而不是add bx,bx)而DI保持为零,因此当BX超过16位时,您将丢失应该转到DX的位。为了解决问题,请使用旋转进行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