2015-07-21 59 views
3

我目前工作的一個任務,在那裏我寫一個子程序,其中2張無符號數相乘得到,並在DX產生一個結果:AX對。但我不能使用mul,imul,div和idiv的說明。當我運行我的代碼時,下半部分(AX寄存器)總是正確的,但DX寄存器不是。任何人都可以指出我正確的方向,我做錯了什麼?乘兩個16位無符號值,而無需使用乘法和除法指令[8086大會]

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

當加倍「bx」時,您需要考慮進入「di」,並且您還需要將di加倍。我想'adc di,di'會起作用。 PS:學會使用一個調試器,這樣你可以瀏覽你的代碼,看看它出錯的地方。 – Jester

回答

3

添加另一個當你使用奇怪轉移dibx值。你的算法似乎是這樣的:

  1. 收集值,把它們放入BX和CX。
  2. 雖然CX> 0:
    1. CX向右偏移。
    2. 如果移位有一個,則將BX添加到AX,並將DI(DI中有零)添加到帶有進位的DX中。
    3. 將BX添加到BX。
  3. 返回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 
+0

非常感謝您的幫助Vesper!那是確切的問題,而且一個快速而簡單的修復幫助我的代碼通過了所有的測試用例。 – CadetFayed

+0

它總是更好地使用'測試CX,cx'代替'或CX,cx'([性能以及人類可讀性(https://stackoverflow.com/questions/33721204/test-whether-a-register -is-零與-CMP-REG-0-VS-或-REG-REG/33724806#33724806))。此外,'shl bx,1'會更有​​效,因爲'add bx,bx',但'shl'對人類來說更加清晰。 –

+0

另外,如果您爲最終迭代複製循環體,則可以使用shift的ZF結果作爲循環出口檢查。 (也就是'shr cx,1' /'jnz loopp'設置爲下一次迭代,或者從最後一位可能存在非零CF溢出循環)。 –