/*---------------------------------------------------------------------------+ | 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); }