0

I need to multiply to numbers, but without using the MUL instruction in Assembly 8086.

For example:

mov bx, 2
bx -> bx * 41; code instead this line

Any Help?

Raz Omry
  • 255
  • 1
  • 6
  • 18
  • 4
    41 * 2 = 41 + 41 = 82, 41 * 3 = 41+41+41 = 123 – Michael Petch Oct 27 '17 at 14:36
  • Where are you stuck? Why can't you use the `mul` instruction? What other restrictions do you have? – fuz Oct 27 '17 at 14:37
  • probably a homework assignment to unstick base-10 brains (why cant you use mul). we see this question every semester from many folks...in various forms... – old_timer Oct 27 '17 at 15:13
  • n * 7 = n * 0b111 = n * (0b100 + 0b010 + 0b011) = (n*0b100)+(n*0b010)+n*0b001) = (n<<2)+(n<<1)+(n<<0); all stuff we learned in elementary school. except for shifting which is first semester programming class. n*5 = n*0b101 = (n<<2)+(n<<0) also n+n = n<<1 b = n+n, c = b+b, which makes c = n<<2 and so on. if you can only add and not shift (which we saw that question this week). – old_timer Oct 27 '17 at 15:16
  • (technically shifting works in base 10 as well, like base 2 you just pad with zeros, but you also have to do a multiply which is the difference between the two) – old_timer Oct 27 '17 at 15:18

2 Answers2

1

A simple solution uses repeated additions.

Use one of the numbers as the counter and add that many times the other number to the result.

What's important here is that the result needs to be dimensioned to twice the size of the original numbers. If both numbers are 16-bit, then the result must be 32-bit.

Next it's better to use the smallest of both numbers as the counter. This will reduce the number of iterations.

Also don't forget to not start the loop if the counter is zero. Then obviously the product is zero.

 mov  bx, [Num1]
 mov  cx, [Num2]
 cmp  cx, bx
 jb   ClearResult
 xchg bx, cx        ;Puts smaller number in CX
ClearResult:
 xor  ax, ax        ;Clear 32-bit result
 cwd
 jcxz OK
AddAgain:
 add  ax, bx
 adc  dx, 0
 dec  cx
 jnz  AddAgain
OK:

Here the product is in DX:AX.

Fifoernik
  • 9,779
  • 1
  • 21
  • 27
0

To multiply a variable for a constant, you can, when it is convenient, decompose the constant into powers of 2; for example AX = AX * 320, 320 = 2 ^ 8 + 2 ^ 6. Then make a shift to the left of the variable for each power and a sum. AX = AX * 320 becomes: AX = AX << 8 + AX << 6, but AX << 8 = (AX << 6) << 2. If you want to multiply for a negative constant, you can apply same method but you must negate input before.

As said by Fifoernik, if you want to multiply a 16 bit register for a constant, you may need up to 32 bit result (furthermore you can have negative input-number); all the routines I've written are successfully tested and they are about three time more fast than IMUL (8086 assembly guides of Peter Norton):

Example A; multiply AX for 41:

Function Mul41(Inp:Integer):LongInt; Assembler;

Asm

     Mov   AX,Inp

    {     DX:AX=AX*41; 41=32+8+1.
         BX, CX=TEMP}

{05} CWD             {DX:AX<-INPUT}

{02} Mov   BX,AX
{02} Mov   CX,DX

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<3}

{03} Add   BX,AX
{03} AdC   CX,DX

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<5}

{03} Add   AX,BX
{03} AdC   DX,CX     {DX:AX<-INPUT*(32+8+1)}

{41 CPU clock-cycles}

{128-154 CPU clock-cycles for IMUL RX}

End;

Example B; multiply AX for -41:

Function MulM41(Inp:Integer):LongInt; Assembler;

Asm

     Mov   AX,Inp

    {     DX:AX=AX*-41; 41=32+8+1.
         BX, CX=TEMP}

{05} CWD             {DX:AX<-INPUT}

{03} Not   AX        {Because NEG AX before CWD ...}
{03} Not   DX        {... is wrong for AX=-32768 ...}
{03} Add   AX,1      {... it does a two complement of DX:AX}
{03} AdC   DX,0      {DX:AX<- -INPUT}

{02} Mov   BX,AX
{02} Mov   CX,DX     {CX:BX<- -INPUT}

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<- -INPUT<<3}

{03} Add   BX,AX
{03} AdC   CX,DX     {CX:BX<- -INPUT*(8+1)}

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<- -INPUT<<5}

{03} Add   AX,BX
{03} AdC   DX,CX     {DX:AX<- -INPUT*(32+8+1)}

{53 CPU clock-cycles}

{128-154 CPU clock-cycles for IMUL RX}

End;

Example 1B; multiply AX for 320:

Function Mul320(Inp:Integer):LongInt; Assembler;

Asm

     Mov   AX,Inp

    {     DX:AX=AX*320; 320=256+64.
         BX, CX=TEMP}

{02} ShL   AX,1
{03} SBB   DX,DX
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<6}

{02} Mov   BX,AX
{02} Mov   CX,DX     {CX:BX<-INPUT<<6}

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<8}

{03} Add   AX,BX
{03} AdC   DX,CX     {DX:AX<-INPUT*(256+64)}

{43 CPU clock-cycles}

{128-154 CPU clock-cycles for IMUL RX}

End;

Example 2B; multiply AX for 200:

Function Mul200(Inp:Integer):LongInt; Assembler;

Asm

     Mov   AX,Inp

    {     DX:AX=AX*200; 200=128+64+8.
         BX, CX=TEMP}

{02} ShL   AX,1
{03} SBB   DX,DX
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<3}

{02} Mov   BX,AX
{02} Mov   CX,DX     {CX:BX<-INPUT<<3}

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<6}

{03} Add   BX,AX
{03} AdC   CX,DX     {CX:BX<-INPUT*(64+8)}

{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<7}

{03} Add   AX,BX
{03} AdC   DX,CX     {DX:AX<-INPUT*(128+64+8)}

{45 CPU clock-cycles}

{128-154 CPU clock-cycles for IMUL RX}

End;

Example 3B; multiply AX for 100:

Function Mul100(Inp:Integer):LongInt; Assembler;

Asm

     Mov   AX,Inp

    {     DX:AX=AX*100; 100=64+32+4.
         BX, CX=TEMP}

{02} ShL   AX,1
{03} SBB   DX,DX
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<2}

{02} Mov   BX,AX
{02} Mov   CX,DX     {CX:BX<-INPUT<<2}

{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1
{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<5}

{03} Add   BX,AX
{03} AdC   CX,DX     {CX:BX<-INPUT*(32+4)}

{02} ShL   AX,1
{02} RCL   DX,1      {DX:AX<-INPUT<<6}

{03} Add   AX,BX
{03} AdC   DX,CX     {DX:AX<-INPUT*(64+32+4)}

{41 CPU clock-cycles}

{128-154 CPU clock-cycles for IMUL RX}

End;

If you don't need a 32 bit result (only for positive numbers):

Example 1; multiply AX for 320:

{    AX=AX*320; 320=256+64.
 BX, CL=TEMP}

 Mov   CL,6
 ShL   AX,CL {AX<-INPUT<<6}

 Mov   BX,AX

 Mov   CL,2
 ShL   AX,CL {AX<-INPUT<<8}

 Add   AX,BX {AX<-AX*(256+64)}

Example 2; multiply AX for 200:

{    AX=AX*200; 200=128+64+8.
 BX, CL=TEMP}

 Mov   CL,3
 ShL   AX,CL {AX<-INPUT<<3}

 Mov   BX,AX

 ShL   AX,CL {AX<-INPUT<<6}

 Add   BX,AX

 ShL   AX,1  {AX<-INPUT<<7}

 Add   AX,BX {AX<-AX*(128+64+8)}

Example 3; multiply AX for 100:

{    AX=AX*100; 100=64+32+4.
 BX, CL=TEMP}

 Mov   CL,2
 ShL   AX,CL {AX<-INPUT<<2}

 Mov   BX,AX

 Mov   CL,3
 ShL   AX,CL {AX<-INPUT<<5}

 Add   BX,AX

 ShL   AX,1  {AX<-INPUT<<6}

 Add   AX,BX {AX<-AX*(64+32+4)}
Paolo Fassin
  • 361
  • 2
  • 11
  • Why don't you number your examples successively? "1,2,3" – Fifoernik Oct 28 '17 at 13:36
  • The second example is wrong! 128 is 2^7 and so just 1 additional shift is needed, not the 2 that you wrote. – Fifoernik Oct 28 '17 at 13:37
  • There's one problem that remains. What will happen when the number in `AX` is __not a very small__ number? (Say AX=210 in the 1st example) The shift operation will overflow without complaining, yielding a wrong product. That's why I wrote in my answer _"the result needs to be dimensioned to twice the size of the original numbers"_. – Fifoernik Oct 28 '17 at 13:53
  • Ok. But this new version should be fine (save at least 67 CPU cycles compared to `MUL RX`). – Paolo Fassin Oct 28 '17 at 22:15