问题
I'm currently working on an assignment, where I write a subroutine where 2 unsigned numbers get multiplied and yield a result in the DX:AX pair. But i cannot use the instructions mul, imul, div, and idiv. 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
;---------------------------------------
回答1:
You are strangely using di when adding another shifted value of bx. Your algorithm seems to be like this:
- Gather values, put them into BX and CX.
- While CX>0:
- Shift CX rightwards.
- If shifted bit had a one, add BX to AX and add DI (there's zero in DI?) to DX with carry.
- Add BX to BX.
- Return DX:AX.
You are missing a left-shift of DI:BX after each right shift of CX. You are shifting only BX (and I'd use shl bx,1 instead of add bx,bx) while DI remains at zero, therefore when BX exceeds 16 bits, you lose bits that should go to DX. To remedy, use rotate through carry against 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
来源:https://stackoverflow.com/questions/31541537/multiply-two-unsigned-16-bit-values-without-using-multiply-or-divide-instructio