user5894146
user5894146

Reputation: 91

16-Bit Multiplication In Assembly?

So I am using C++ with assembly to do 16-bit signed multiplication.

I know that for 16-bits, the multiplicand is AX and the multiplier is either a register or memory operand 16 bit with the product being stored in EDX:EAX which is twice the size of operands.

I am a beginner so I tried first with 8 bit signed multiplication in which it works:

#include "stdafx.h"
#include <stdio.h>

int main()
{
    char X, Y;
    short Z;
    _asm
    {
        MOV X, 5
        MOV Y, 11

        MOV AL, X
        MOV BL, Y
        IMUL BL

        MOV Z, AX

    }

    printf("The result times is = %i", Z);



    getchar();
    //system("pause");
    return 0;
}

but I'm unsure why the following code wouldn't work for 16 bit instead.

#include "stdafx.h"
#include <stdio.h>

int main()
{
    short X, Y;
    int Z;
    _asm
    {
            MOV X, 5
            MOV Y, 11

            MOV AX, X
            MOV BX, Y
            IMUL BX

            MOV Z, [DX::AX]

    }

    printf("The result times is = %i", Z);



    getchar();
    //system("pause");
    return 0;
}

Upvotes: 4

Views: 4892

Answers (1)

Johan
Johan

Reputation: 76567

The reason it doesn't work is that the instruction MOV Z, [DX::AX] does not exist.

You are correct that the result will be stored in DX:AX, but to store the result of those two registers in a memory location you'll have to do two stores.

lea ecx,z        //load the address of z into cx
mov [ecx],ax     //8086 is little endian, so store the lower bytes first.
mov [ecx+2],dx   //store the high bytes 

I must say that I'm appalled to see 16-bit assembly. The 386 was introduced in 1985, so you are about 30 years behind the times.

The way to multiply two 16 bit values is:

movsx eax, word ptr x        //sign extension prevents partial register writes
movsx edx, word ptr y        //use movzx if you want to do an unsigned mul
imul eax,edx                 //multiply, but only store result in EAX.
mov z,eax                    //save result in one go.

Use of 16 bit registers in x86 leads to very slow code, because the processor is not optimized for this mode of operation. Sometimes 16 bit code can be many times slower than normal code.
The below code will run much, much faster than the above.

  1. It does not suffer from stalls due to partial register writes.
  2. It does not perform operations on partial registers.
  3. It does not use two writes (one of which is unaligned) where a single write would suffice.

You also don't have to be aware of the subtleties of little endian in the last example.
You should avoid using the 16-bit registers at all costs.
The equivalent 32-bit code is almost always much faster.
The only exception if writing 16-bit values to memory if you are unable to combine two 16-bit writes into one 32-bit.

Upvotes: 1

Related Questions