3
votes

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
When doubling the bx you need to consider carry into di and you need to double di too. I suppose adc di, di would work. PS: learn to use a debugger so you can step through your code and see where it goes wrong.Jester

1 Answers

3
votes

You are strangely using di when adding another shifted value of bx. Your algorithm seems to be like this:

  1. Gather values, put them into BX and CX.
  2. While CX>0:
    1. Shift CX rightwards.
    2. If shifted bit had a one, add BX to AX and add DI (there's zero in DI?) to DX with carry.
    3. Add BX to BX.
  3. 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