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

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

我目前正在做一项作业,我在其中编写了一个子例程,其中 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
;---------------------------------------

您在添加 bx 的另一个移位值时奇怪地使用了 di。你的算法好像是这样的:

  1. 收集值,将它们放入 BX 和 CX。
  2. 当 CX>0 时:
    1. 向右移动 CX。
    2. 如果移位的位是 1,则将 BX 加到 AX 并将 DI(DI 中有零吗?)加到带进位的 DX。
    3. 将 BX 添加到 BX。
  3. Return DX:AX.

您在 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