模拟乘除法指令
最近我给一个mcu 写编译器的时候,因为这个mcu 是不支持乘除指令,因此我就写了一个模拟的函数,当然在这里我用的8086 的 asm 描述算法的核心思想,并在vc6.0 编译通过验证。mulchar()是无符号的8位乘法,mulsignedchar()是有符号的8位乘法,divchar() 是无符号的8位除法。
理论依据:<<计算机组成原理>> 李文兵 清华大学出版社
代码如下:
// testfload.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <math.h>
#include <process.h>
unsigned mulchar(unsigned char a, unsigned char b);
short mulsignedchar(char a, char b);
unsigned short divchar(unsigned char a, unsigned char b);
int main(int argc, char* argv[])
{
int i =0 ;
int j = 0;
int k = 0;
unsigned short div = divchar(128, 1);
unsigned char shang = div & 0xff;
unsigned char rest = (div >> 8) & 0xff;
// unsigned char
for (i = 0 ; i <= 255; i++)
{
for (j = 0; j <= 255; j++)
{
unsigned short c = (short)i * j;
unsigned short c1 = mulchar(i, j);
printf ("%d * %d = %hx, %hx\n", i, j, c, c1);
if (c != c1)
{
k++;
__asm
{
int 3
}
}
}
}
system("PAUSE");
// signed char
for (i = -128 ; i <= 127; i++)
{
for (j = -128; j <= 127; j++)
{
short c = (char)i * j;
short c1 = mulsignedchar(i, j);
printf ("%d * %d = %hd, %hd\n", i, j, c, c1);
if (c != c1)
{
k++;
__asm
{
int 3
}
}
}
}
for (i = 1; i <= 255; i++)
{
for (j = 1; j <= 255; j++)
{
unsigned char c = i / j;
unsigned char s = i % j;
unsigned short cc = divchar(i, j);
unsigned char c1 = cc & 0xff;
unsigned char s1 = (cc >> 8) & 0xff;
printf("%u / %u = %u---%u=====rest %u----%u\n", i, j, c, c1, s, s1);
if (c != c1 || s1 != s)
{
__asm
{
int 3
}
}
}
}
printf("errors %d\n", k);
return 0;
}
short mulsignedchar(char a, char b)
{
int asign = a & 0x80;
int bsign = b & 0x80;
int nsign = asign ^ bsign;
unsigned char mula = a, mulb = b;
if (asign)
{
mula = -a;
}
if (bsign)
{
mulb = -b;
}
int result = mulchar(mula, mulb);
if (nsign)
{
result = - result;
}
return result;
}
unsigned mulchar(unsigned char a, unsigned char b)
{
unsigned char aSign = 0;
unsigned char aSignHigh = 0;
unsigned char flag = 0;
unsigned char anSignEx = 0;
unsigned char anSignExHigh = 0;
unsigned char a2SignEx = 0;
unsigned char a2SignExHigh = 0;
unsigned char tempB = b;
unsigned char ResultHigh = 0;
unsigned char ResultHighH = 0;
unsigned char a2 = 0;
unsigned char an = 0;
unsigned short result = 0;
__asm
{
// clear
mov eax, 0
mov ebx, 0
mov ecx, 0
mov edx, 0
mov ResultHigh, al
mov ResultHighH,al
// backup a
mov al, a
mov an, al
// extern a sign
cbw // don't use because unsigned multiplication
//cmp XYflag, 0
//jnz directjmp
mov ah, 0
;directjmp:
mov aSign, ah
mov aSignHigh, ah
// move 2a sign
mov a2SignEx, ah
mov a2SignExHigh, ah
// calculate 2a
mov Ah, 0
shl al, 1
rcl a2SignEx, 1
rcl a2SignExHigh, 1
mov a2, al
// extern an sign
mov al, a
xor ah, ah
mov bx, 0
sub bx, ax
mov anSignEx, bh
mov an, bl
mov anSignExHigh, bh
// loop count
mov ch, 0x4
// calculate last 2 bits
mov bl, b
and bl, 0x3
loopstart:
cmp flag, 0x0
jz directcheck2bit
// clear flag
mov flag, 0x0
inc bl
cmp bl, 0x3
jbe directcheck2bit
// set flag
mov flag, 1
and bl, 0x3
directcheck2bit:
cmp bl, 0x00
jz labelto00state
cmp bl, 0x01
jz labelto01state
cmp bl, 0x02
jz labelto02state
// 03 state
add dh, an
mov bh, anSignEx
adc ResultHigh, bh
mov bh, anSignExHigh
adc ResultHighH, bh
// shift
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift again
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// set flag
mov flag, 0x1
// shift operand b
mov bl, tempB
mov cl, 0x2
SHR bl, cl
mov tempB, bl
and bl, 0x3
DecCount:
dec ch
jnz loopstart
jmp result_xy
labelto00state:
// shift
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift again
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift operand b
mov bl, tempB
mov cl, 0x2
SHR bl, cl
mov tempB, bl
and bl, 0x3
jmp DecCount
labelto01state:
add dh, a
mov bh, aSign
adc ResultHigh, bh
adc ResultHighH, bh
// shift
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift again
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift
mov bl, tempB
mov cl, 0x2
SHR bl, cl
mov tempB, bl
and bl, 0x3
jmp DecCount
labelto02state:
add dh, a2
mov bh, a2SignEx
adc ResultHigh, bh
mov bh, a2SignExHigh
adc ResultHighH, bh
// shift
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift again
SAR ResultHighH, 1
RCR ResultHigh, 1
RCR dx, 1
// shift
mov bl, tempB
mov cl, 0x2
SHR bl, cl
mov tempB, bl
and bl, 0x3
jmp DecCount
result_xy:
cmp flag, 0
jz Operandblasttime
add dh, a
Operandblasttime:
mov result, dx
}
return result;
}
unsigned short divchar(unsigned char a, unsigned char b)
{
unsigned char result = 0;
unsigned char rest = 0;
unsigned char restsign = 0;
unsigned char bn = 0;
unsigned char bnsign = 0;
unsigned char rest2 = 0;
unsigned char rest2sign = 0;
__asm
{
mov cx, 0
cmp b, 0
jnz nextprocess
int 0 // div exception
nextprocess:
mov al, a
cmp al, b
jb returnresult
// start division
mov al, a
mov rest, al
mov restsign, 0
// calculate the -b to bn
mov al, b
mov bl, 0
sub bl, al
mov al, 0
sbb al, 0
mov bnsign, al
mov bn, bl
//loop
loopStart:
mov al, rest
cmp al, b
jb loopexit
mov al, rest
sub al, b
mov rest , al
mov bl, restsign
sbb bl, 0
mov restsign, bl
inc cl
//mov bl, restsign
and bl, 0x80
jz nonaddY
mov al, rest
add al, b
mov rest, al
mov bl, restsign
adc bl, 0
mov restsign, bl
nonaddY:
jmp loopStart
returnresult:
mov al , a
mov rest, al
loopexit:
mov result, cl
}
unsigned short nR = rest;
nR <<= 8;
nR |= result;
return nR;
}