Search code examples
assemblyx86x86-16

how make a multiplication in assembly x8086 but without mul command


I need to make a program how pick two number between 0 and 9 and multiply they but I can only use SHL, SHR or ROR,ROL commands

;I find this code here on stackoverflow but a don´t really undusted 
    ; ax = x
    mov bl, al     ; bx = x
    shl bl, 3      ; bx = 8 * x
    add al, bl     ; ax = 9 * x
    shl bl, 2      ; bx = 32 * x
    add al, bl     ; ax = 41 * x

Solution

  • Performing multiplication without using the mul instruction is clear enough, but saying you can only use shl, shr, rol, and ror instructions is not sufficient to solve this task.
    As an example see the below subroutine that manages to multiply without the use of the mul instruction:

    ; IN (al=first number [0,9], ah=second number [0,9]) OUT (ax=product [0,81])
    SmallMul:
      mov [$+6], al ; This overwrites the default operand of AAD
      mov al, 0
      aad          ; -> AX is product
      ret
    

    and using add and sub it is possible to make this program ?

    Yes, using repeated addition and as long as you don't expect to only use add and sub because you'll always need at least some branching instruction to create a loop. And even if you would avoid creating a loop by means of unrolling, you would still have to test and branch on some exit condition.

    example: 5 * 3  -->  0 + 5 + 5 + 5
                          <--- 3x --->
    
    ; IN (al=first number [0,9], bl=second number [0,9]) OUT (cl=product [0,81])
    SmallMul:
        sub  cl, cl  ; Sets CL=0
    .a: add  cl, al
        sub  bl, 1
        jnz  .a      ; Jumps BL-1 times (possibly 255 times!)
        ret
    
    • If ever the second number in BL were zero, then this simple code will fail! then this simple code will be very inefficiently iterating 256 times! Nonetheless, it will produce the correct result (which is 0)
    • As an optimization we can choose the smallest of the two numbers to control the loop. Less iterations is a good thing.
    ; IN (al=first number [0,9], bl=second number [0,9]) OUT (cl=product [0,81])
    SmallMul:
        sub  cl, cl  ; Sets CL=0
        cmp  bl, al
        jbe  .b
        xchg bl, al
        jmp  .b
    .a: add  cl, al
    .b: sub  bl, 1
        jns  .a      ; Jumps BL times
        ret
    

    A simple version of the shift and add algorithm:

    ; IN (al=first number [0,9], bl=second number [0,9]) OUT (cl=product [0,81])
    SmallMul:
        sub  cl, cl  ; Sets CL=0
        jmp  .c
    .a: add  cl, al
    .b: shl  al, 1   ; Doubles AL, same as `ADD AL, AL`
    .c: shr  bl, 1   ; Halves BL
        jc   .a      ; Shifted out a 1 bit, so go ADD
        jnz  .b      ; Jumps for as long as BL has non-zero bits
        ret
    
    • There's no problem with the second number in BL being zero.
    • As an optimization we can choose the smallest of the two numbers to control the loop. Less iterations is a good thing.
    ; IN (al=first number [0,9], bl=second number [0,9]) OUT (cl=product [0,81])
    SmallMul:
        sub  cl, cl  ; Sets CL=0
        cmp  bl, al
        jbe  .c
        xchg bl, al
        jmp  .c
    .a: add  cl, al
    .b: shl  al, 1   ; Doubles AL, same as `ADD AL, AL`
    .c: shr  bl, 1   ; Halves BL
        jc   .a      ; Shifted out a 1 bit, so go ADD
        jnz  .b      ; Jumps for as long as BL has non-zero bits
        ret