Bochs/bochs/fpu/reg_u_mul.c
2003-05-15 16:11:29 +00:00

101 lines
2.7 KiB
C

/*---------------------------------------------------------------------------+
| reg_u_mul.c |
| $Id: reg_u_mul.c,v 1.5 2003-05-15 16:11:29 sshwarts Exp $
| |
| Core multiplication routine |
| |
| Copyright (C) 1992,1993,1995,1997,1999 |
| W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia |
| E-mail billm@melbpc.org.au |
| |
| |
+---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------+
| Basic multiplication routine. |
| Does not check the resulting exponent for overflow/underflow |
| |
| Internal working is at approx 128 bits. |
| Result is rounded to nearest 53 or 64 bits, using "nearest or even". |
+---------------------------------------------------------------------------*/
#include "exception.h"
#include "fpu_emu.h"
#include "control_w.h"
int FPU_u_mul(const FPU_REG *a, const FPU_REG *b, FPU_REG *c, u16 cw,
u_char sign, int expon)
{
u64 mu, ml, mi;
u32 lh, ll, th, tl;
#ifdef PARANOID
if (! (a->sigh & 0x80000000) || ! (b->sigh & 0x80000000))
{
EXCEPTION(EX_INTERNAL|0x205);
}
#endif
ml = a->sigl;
ml *= b->sigl;
ll = ml;
lh = ml >> 32;
mu = a->sigh;
mu *= b->sigh;
mi = a->sigh;
mi *= b->sigl;
tl = mi;
th = mi >> 32;
lh += tl;
if (tl > lh)
mu ++;
mu += th;
mi = a->sigl;
mi *= b->sigh;
tl = mi;
th = mi >> 32;
lh += tl;
if (tl > lh)
mu ++;
mu += th;
ml = lh;
ml <<= 32;
ml += ll;
expon -= EXP_BIAS-1;
if (expon <= EXP_WAY_UNDER)
expon = EXP_WAY_UNDER;
/* if the addition of signed 16-bit values overflowed, substitute
the maximum positive exponent to force FPU_round to produce overflow */
if (expon > 0x7FFE)
expon = 0x7FFE;
c->exp = expon;
if (! (mu & BX_CONST64(0x8000000000000000)))
{
mu <<= 1;
if (ml & BX_CONST64(0x8000000000000000))
mu |= 1;
ml <<= 1;
c->exp --;
}
ll = ml;
lh = ml >> 32;
if (ll)
lh |= 1;
c->sigl = mu;
c->sigh = mu >> 32;
return FPU_round(c, lh, 0, cw, sign);
}