home *** CD-ROM | disk | FTP | other *** search
- #include "emu.h"
- #include "const.h"
-
- extern "C" void djshld(void *);
- extern "C" void djshrd(void *);
-
- extern void normalize(reg& r);
-
- void r_uadd(reg& a, reg& b, reg& s) // signs ignored
- {
- reg t;
- int dif = a.exp - b.exp;
- if (!dif) dif = a.sigh - b.sigh;
- if (!dif) dif = a.sigl - b.sigl;
- if (dif > 0)
- {
- r_mov(a, s);
- r_mov(b, t);
- }
- else
- {
- r_mov(b, s);
- r_mov(a, t);
- }
- if (s.exp - t.exp > 64)
- return;
- while (t.exp < s.exp)
- {
- t.exp ++;
- djshrd(&t.sigl);
- }
- unsigned short *ss, *ts;
- unsigned long tmp;
- ss = (unsigned short *)&s.sigl;
- ts = (unsigned short *)&t.sigl;
- tmp = 0;
- for (int i=4; i>0; i--)
- {
- tmp += (unsigned long)*ss + (unsigned long)*ts;
- *ss = tmp;
- ss++;
- ts++;
- tmp >>= 16;
- }
- if (tmp)
- {
- djshrd(&s.sigl);
- s.exp++;
- s.sigh |= 0x80000000;
- }
- if (!(s.sigh | s.sigl))
- {
- s.exp = 0;
- s.tag = TW_Z;
- }
- else
- {
- while (!(s.sigh & 0x80000000))
- {
- if (s.exp == 0)
- return;
- djshld(&s.sigl);
- s.exp--;
- }
- }
- }
-
- void r_usub(reg& a, reg& b, reg& d) // a > b
- {
- reg t;
- r_mov(a, d);
- r_mov(b, t);
-
- if (d.exp - t.exp > 64)
- return;
- while (t.exp < d.exp)
- {
- t.exp ++;
- djshrd(&t.sigl);
- }
- unsigned short *ss, *ts;
- long tmp;
- ss = (unsigned short *)&d.sigl;
- ts = (unsigned short *)&t.sigl;
- tmp = 0;
- for (int i=4; i>0; i--)
- {
- tmp += (long)*ss - (long)*ts;
- *ss = tmp;
- ss++;
- ts++;
- tmp >>= 16;
- }
- if (!(d.sigh | d.sigl))
- {
- d.exp = 0;
- d.tag = TW_Z;
- }
- else
- {
- while (!(d.sigh & 0x80000000))
- {
- if (d.exp == 0)
- return;
- djshld(&d.sigl);
- d.exp--;
- }
- }
- }
-
- void r_add(reg& a, reg& b, reg& s)
- {
- char old_sign;
- if (a.tag == TW_Z)
- return r_mov(b, s);
- if (b.tag == TW_Z)
- return r_mov(a, s);
- if (a.tag == TW_S)
- return r_mov(a, s);
- if (b.tag == TW_S)
- return r_mov(b, s);
-
- switch (a.sign*2 + b.sign)
- {
- case 0: // P + P
- case 3: // N + N
- r_uadd(a, b, s);
- s.sign = a.sign;
- break;
- case 1: // P + N
- old_sign = b.sign;
- b.sign ^= SIGN_POS^SIGN_NEG;
- r_sub(a, b, s);
- b.sign = old_sign;
- break;
- case 2: // N + P
- old_sign = a.sign;
- a.sign ^= SIGN_POS^SIGN_NEG;
- r_sub(b, a, s);
- a.sign = old_sign;
- break;
- }
- }
-
- void r_sub(reg& a, reg& b, reg& d)
- {
- if (b.tag == TW_Z)
- return r_mov(a, d);
- if (a.tag == TW_Z)
- {
- r_mov(b, d);
- d.sign ^= SIGN_POS^SIGN_NEG;
- return;
- }
- if (a.tag == TW_S)
- return r_mov(a, d);
- if (b.tag == TW_S)
- {
- r_mov(b, d);
- d.sign ^= SIGN_POS^SIGN_NEG;
- return;
- }
-
- int mdif;
- mdif = a.exp - b.exp;
- if (!mdif)
- mdif = a.sigh - b.sigh;
- if (!mdif)
- mdif = a.sigl - b.sigl;
-
- switch (a.sign*2 + b.sign)
- {
- case 0: // P - P
- case 3: // N - N
- if (mdif > 0)
- {
- r_usub(a, b, d);
- d.sign = a.sign;
- }
- else
- {
- r_usub(b, a, d);
- d.sign = a.sign ^ SIGN_POS^SIGN_NEG;
- }
- break;
- case 1: // P - N
- r_uadd(a, b, d);
- d.sign = SIGN_POS;
- break;
- case 2: // N - P
- r_uadd(a, b, d);
- d.sign = SIGN_NEG;
- break;
- }
- }
-
- void r_mul(reg& a, reg& b, reg& s)
- {
- if (a.tag == TW_Z)
- {
- r_mov(CONST_Z, s);
- }
- else if (b.tag == TW_Z)
- {
- r_mov(CONST_Z, s);
- }
- else if (a.tag == TW_S)
- {
- r_mov(a, s);
- }
- else if (b.tag == TW_S)
- {
- r_mov(b, s);
- }
- else
- {
- unsigned short sl[9], carry[10];
- unsigned short *as = (unsigned short *)(&a.sigl);
- unsigned short *bs = (unsigned short *)(&b.sigl);
- unsigned long l, sum;
- int ai, bi;
- for (ai=0; ai<8; ai++)
- sl[ai] = carry[ai] = 0;
- for (ai = 0; ai < 4; ai++)
- for (bi = 0; bi < 4; bi++)
- {
- l = as[ai] * bs[bi];
-
- sum = sl[ai+bi] + (l & 0xffff);
- sl[ai+bi] = sum & 0xffff;
-
- sum = sl[ai+bi+1] + (l>>16) + (sum>>16);
- sl[ai+bi+1] = sum & 0xffff;
-
- carry[ai+bi+2] += sum>>16;
- }
- for (ai=0; ai<8; ai++)
- {
- if (carry[ai])
- {
- sum = sl[ai] + carry[ai];
- sl[ai] = sum & 0xffff;
- carry[ai+1] += sum>>16;
- }
- }
- s.sigl = *(long *)(sl+4);
- s.sigh = *(long *)(sl+6);
- s.exp = a.exp + b.exp - EXP_BIAS + 1;
- s.tag = TW_V;
- }
- if (a.sign == b.sign)
- s.sign = SIGN_POS;
- else
- s.sign = SIGN_NEG;
- normalize(s);
- }
-
- void r_div(reg& a, reg& b, reg& q)
- {
- if (a.tag == TW_S)
- {
- if (val_same(a, CONST_PINF))
- r_mov(a, q);
- else if (val_same(a, CONST_NINF))
- r_mov(a, q);
- }
- else if (b.tag == TW_S)
- {
- if (val_same(b, CONST_PINF))
- r_mov(CONST_Z, q);
- else if (val_same(b, CONST_NINF))
- r_mov(CONST_Z, q);
- }
- else if (a.tag == TW_Z)
- {
- r_mov(a, q);
- }
- else if (b.tag == TW_Z)
- {
- exception(EX_Z);
- }
- else
- {
- q.exp = a.exp - b.exp + EXP_BIAS;
- if (q.exp > EXP_MAX)
- r_mov(CONST_PINF, q);
- else if (q.exp <= 0)
- r_mov(CONST_Z, q);
- else
- {
- unsigned long long al, bl, ql, f;
- int i;
- al = *(unsigned long long *)(&a.sigl);
- bl = *(unsigned long long *)(&b.sigl);
- ql = 0;
- f = (unsigned long long)1 << 63;
- for (i=0; i<64; i++)
- {
- if (al >= bl)
- {
- al -= bl;
- ql += f;
- }
- bl >>= 1;
- f >>= 1;
- }
- *(unsigned long long *)(&q.sigl) = ql;
- q.tag = TW_V;
- }
- }
- if (a.sign == b.sign)
- q.sign = SIGN_POS;
- else
- q.sign = SIGN_NEG;
- normalize(q);
- }
-