00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00058 #include "StdAfx.h"
00059 #include "AlphaCPU.h"
00060 #include "cpu_debug.h"
00061
00062
00063
00144
00145 #define QNAN U64(0x0008000000000000)
00146 #define CQNAN U64(0xFFF8000000000000)
00147 #define FPZERO U64(0x0000000000000000)
00148 #define FMZERO U64(0x8000000000000000)
00149 #define FPINF U64(0x7FF0000000000000)
00150 #define FMINF U64(0xFFF0000000000000)
00151 #define FPMAX U64(0x7FFFFFFFFFFFFFFF)
00152 #define FMMAX U64(0xFFFFFFFFFFFFFFFF)
00153 #define IPMAX U64(0x7FFFFFFFFFFFFFFF)
00154 #define IMMAX U64(0x8000000000000000)
00155
00156
00157 #define UF_SRND U64(0x0000008000000000)
00158 #define UF_SINF U64(0x000000FFFFFFFFFF)
00159 #define UF_TRND U64(0x0000000000000400)
00160 #define UF_TINF U64(0x00000000000007FF)
00161
00162
00163
00169
00170
00179 u64 CAlphaCPU::ieee_lds(u32 op)
00180 {
00181 u32 exp = S_GETEXP(op);
00182
00183 if(exp == S_NAN)
00184 exp = FPR_NAN;
00185 else if(exp != 0)
00186 exp = exp + T_BIAS - S_BIAS;
00187 return(((u64) (op & S_SIGN)) ? FPR_SIGN : 0) |
00188 (((u64) exp) << FPR_V_EXP) | (((u64) (op &~(S_SIGN | S_EXP))) << S_V_FRAC);
00189 }
00190
00199 u32 CAlphaCPU::ieee_sts(u64 op)
00200 {
00201 u32 sign = FPR_GETSIGN(op) ? S_SIGN : 0;
00202 u32 exp = FPR_GETEXP(op);
00203 if(exp == FPR_NAN)
00204 exp = S_NAN;
00205 else if(exp != 0)
00206 exp = exp + S_BIAS - T_BIAS;
00207 exp = (exp << S_V_EXP) & S_EXP;
00208
00209 u32 frac = ((u32) (op >> S_V_FRAC)) & X64_LONG;
00210
00211 return sign | exp | (frac &~(S_SIGN | S_EXP));
00212 }
00213
00214
00215
00216
00217
00223
00224
00235 u64 CAlphaCPU::ieee_cvtst(u64 op, u32 ins)
00236 {
00237 UFP b;
00238 u32 ftpb;
00239
00240 ftpb = ieee_unpack(op, &b, ins);
00241 if(ftpb == UFT_DENORM)
00242 {
00243
00244
00245 b.exp = b.exp + T_BIAS - S_BIAS;
00246 return ieee_rpack(&b, ins, DT_T);
00247 }
00248 else
00249 return op;
00250 }
00251
00260 u64 CAlphaCPU::ieee_cvtts(u64 op, u32 ins)
00261 {
00262 UFP b;
00263 u32 ftpb;
00264
00265 ftpb = ieee_unpack(op, &b, ins);
00266 if(Q_FINITE(ftpb))
00267 return ieee_rpack(&b, ins, DT_S);
00268 if(ftpb == UFT_NAN)
00269 return(op | QNAN);
00270 if(ftpb == UFT_INF)
00271 return op;
00272 return 0;
00273 }
00274
00275
00276
00277
00278
00284
00285
00301 s32 CAlphaCPU::ieee_fcmp(u64 s1, u64 s2, u32 ins, u32 trap_nan)
00302 {
00303 UFP a;
00304
00305 UFP b;
00306 u32 ftpa;
00307 u32 ftpb;
00308
00309 ftpa = ieee_unpack(s1, &a, ins);
00310 ftpb = ieee_unpack(s2, &b, ins);
00311 if((ftpa == UFT_NAN) || (ftpb == UFT_NAN))
00312 {
00313 if(trap_nan)
00314 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00315 return +1;
00316 }
00317
00318 if(ftpa == UFT_ZERO)
00319 a.sign = 0;
00320 if(ftpb == UFT_ZERO)
00321 b.sign = 0;
00322 if(a.sign != b.sign)
00323 return(a.sign ? -1 : +1);
00324 if(a.exp != b.exp)
00325 return((a.sign ^ (a.exp < b.exp)) ? -1 : +1);
00326 if(a.frac != b.frac)
00327 return((a.sign ^ (a.frac < b.frac)) ? -1 : +1);
00328 return 0;
00329 }
00330
00340 u64 CAlphaCPU::ieee_cvtif(u64 val, u32 ins, u32 dp)
00341 {
00342 UFP a;
00343
00344 if(val == 0)
00345 return 0;
00346 if(((s64)val) < 0)
00347 {
00348 a.sign = 1;
00349 val = NEG_Q(val);
00350 }
00351 else
00352 a.sign = 0;
00353 a.exp = 63 + T_BIAS;
00354 a.frac = val;
00355 ieee_norm(&a);
00356 return ieee_rpack(&a, ins, dp);
00357 }
00358
00373 u64 CAlphaCPU::ieee_cvtfi(u64 op, u32 ins)
00374 {
00375 UFP a;
00376 u64 sticky;
00377 u32 rndm;
00378 u32 ftpa;
00379 u32 ovf = 0;
00380 s32 ubexp;
00381
00382 ftpa = ieee_unpack(op, &a, ins);
00383 if(!Q_FINITE(ftpa))
00384 {
00385 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00386 return 0;
00387 }
00388
00389 if(ftpa == UFT_ZERO)
00390 return 0;
00391 ubexp = a.exp - T_BIAS;
00392 if(ubexp < 0)
00393 {
00394 if(ubexp == -1)
00395 sticky = a.frac;
00396 else
00397 sticky = 1;
00398 a.frac = 0;
00399 }
00400 else if(ubexp <= UF_V_NM)
00401 {
00402 sticky = (a.frac << (64 - (UF_V_NM - ubexp))) & X64_QUAD;
00403 a.frac = a.frac >> (UF_V_NM - ubexp);
00404 }
00405 else
00406 {
00407 if((ubexp - UF_V_NM) > 63)
00408 a.frac = 0;
00409 else
00410 a.frac = (a.frac << (ubexp - UF_V_NM)) & X64_QUAD;
00411 ovf = 1;
00412 sticky = 0;
00413 }
00414
00415 rndm = I_GETFRND(ins);
00416 if(((rndm == I_FRND_N) && (sticky & Q_SIGN))
00417 || ((rndm == I_FRND_P) && !a.sign && sticky)
00418 || ((rndm == I_FRND_M) && a.sign && sticky))
00419 {
00420 a.frac = (a.frac + 1) & X64_QUAD;
00421 if(a.frac == 0)
00422 ovf = 1;
00423 if((rndm == I_FRND_N) && (sticky == Q_SIGN))
00424 a.frac = a.frac &~1;
00425 }
00426
00427 if(a.frac > (a.sign ? IMMAX : IPMAX))
00428 ovf = 1;
00429
00430 if(ovf)
00431 ieee_trap(TRAP_IOV, ins & I_FTRP_V, 0, 0);
00432 if(ovf || sticky)
00433 ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins);
00434 return(a.sign ? NEG_Q(a.frac) : a.frac);
00435 }
00436
00465 u64 CAlphaCPU::ieee_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub)
00466 {
00467 UFP a;
00468
00469 UFP b;
00470
00471 UFP t;
00472 u32 ftpa;
00473 u32 ftpb;
00474 u32 sticky;
00475 s32 ediff;
00476
00477 ftpa = ieee_unpack(s1, &a, ins);
00478 ftpb = ieee_unpack(s2, &b, ins);
00479 if(ftpb == UFT_NAN)
00480 return s2 | QNAN;
00481 if(ftpa == UFT_NAN)
00482 return s1 | QNAN;
00483 if(sub)
00484 b.sign = b.sign ^ 1;
00485 if(ftpb == UFT_INF)
00486 {
00487 if((ftpa == UFT_INF) && (a.sign ^ b.sign))
00488 {
00489 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00490 return CQNAN;
00491 }
00492
00493 return(sub ? (s2 ^ FPR_SIGN) : s2);
00494 }
00495
00496 if(ftpa == UFT_INF)
00497 return s1;
00498 if(ftpa == UFT_ZERO)
00499 a = b;
00500 else if(ftpb != UFT_ZERO)
00501 {
00502 if((a.exp < b.exp)
00503 || ((a.exp == b.exp) && (a.frac < b.frac)))
00504 {
00505 t = a;
00506 a = b;
00507 b = t;
00508 }
00509
00510 ediff = a.exp - b.exp;
00511 if(ediff > 63)
00512 b.frac = 1;
00513 else if(ediff)
00514 {
00515 sticky = ((b.frac << (64 - ediff)) & X64_QUAD) ? 1 : 0;
00516 b.frac = ((b.frac >> ediff) & X64_QUAD) | sticky;
00517 }
00518
00519 if(a.sign ^ b.sign)
00520 {
00521 a.frac = (a.frac - b.frac) & X64_QUAD;
00522 ieee_norm(&a);
00523 }
00524 else
00525 {
00526 a.frac = (a.frac + b.frac) & X64_QUAD;
00527 if(a.frac < b.frac)
00528 {
00529 a.frac = UF_NM | (a.frac >> 1) |
00530 (a.frac & 1);
00531 a.exp = a.exp + 1;
00532 }
00533 }
00534 }
00535
00536 return ieee_rpack(&a, ins, dp);
00537 }
00538
00563 u64 CAlphaCPU::ieee_fmul(u64 s1, u64 s2, u32 ins, u32 dp)
00564 {
00565 UFP a;
00566
00567 UFP b;
00568 u32 ftpa;
00569 u32 ftpb;
00570 u64 resl;
00571
00572 ftpa = ieee_unpack(s1, &a, ins);
00573 ftpb = ieee_unpack(s2, &b, ins);
00574 if(ftpb == UFT_NAN)
00575 return s2 | QNAN;
00576 if(ftpa == UFT_NAN)
00577 return s1 | QNAN;
00578 a.sign = a.sign ^ b.sign;
00579 if((ftpa == UFT_ZERO) || (ftpb == UFT_ZERO))
00580 {
00581 if((ftpa == UFT_INF) || (ftpb == UFT_INF))
00582 {
00583 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00584 return CQNAN;
00585 }
00586
00587 return(a.sign ? FMZERO : FPZERO);
00588 }
00589
00590 if(ftpb == UFT_INF)
00591 return(a.sign ? FMINF : FPINF);
00592 if(ftpa == UFT_INF)
00593 return(a.sign ? FMINF : FPINF);
00594 a.exp = a.exp + b.exp + 1 - T_BIAS;
00595 resl = uemul64(a.frac, b.frac, &a.frac);
00596 ieee_norm(&a);
00597 a.frac = a.frac | (resl ? 1 : 0);
00598 return ieee_rpack(&a, ins, dp);
00599 }
00600
00622 u64 CAlphaCPU::ieee_fdiv(u64 s1, u64 s2, u32 ins, u32 dp)
00623 {
00624 UFP a;
00625
00626 UFP b;
00627 u32 ftpa;
00628 u32 ftpb;
00629 u32 sticky;
00630
00631 ftpa = ieee_unpack(s1, &a, ins);
00632 ftpb = ieee_unpack(s2, &b, ins);
00633 if(ftpb == UFT_NAN)
00634 return s2 | QNAN;
00635 if(ftpa == UFT_NAN)
00636 return s1 | QNAN;
00637 a.sign = a.sign ^ b.sign;
00638 if(ftpb == UFT_INF)
00639 {
00640 if(ftpa == UFT_INF)
00641 {
00642 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00643 return CQNAN;
00644 }
00645
00646 return(a.sign ? FMZERO : FPZERO);
00647 }
00648
00649 if(ftpa == UFT_INF)
00650 {
00651 if(ftpb == UFT_ZERO)
00652 ieee_trap(TRAP_DZE, 1, FPCR_DZED, ins);
00653 return(a.sign ? FMINF : FPINF);
00654 }
00655
00656 if(ftpb == UFT_ZERO)
00657 {
00658 if(ftpa == UFT_ZERO)
00659 {
00660 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00661 return CQNAN;
00662 }
00663
00664 ieee_trap(TRAP_DZE, 1, FPCR_DZED, ins);
00665 return(a.sign ? FMINF : FPINF);
00666 }
00667
00668 if(ftpa == UFT_ZERO)
00669 return(a.sign ? FMZERO : FPZERO);
00670 a.exp = a.exp - b.exp + T_BIAS;
00671 a.frac = a.frac >> 1;
00672 b.frac = b.frac >> 1;
00673 a.frac = ufdiv64(a.frac, b.frac, 55, &sticky);
00674 ieee_norm(&a);
00675 a.frac = a.frac | sticky;
00676 return ieee_rpack(&a, ins, dp);
00677 }
00678
00695 u64 CAlphaCPU::ieee_sqrt(u64 op, u32 ins, u32 dp)
00696 {
00697 u32 ftpb;
00698 UFP b;
00699
00700 ftpb = ieee_unpack(op, &b, ins);
00701 if(ftpb == UFT_NAN)
00702 return op | QNAN;
00703 if((ftpb == UFT_ZERO) || ((ftpb == UFT_INF) && !b.sign))
00704 return op;
00705 if(b.sign)
00706 {
00707 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00708 return CQNAN;
00709 }
00710
00711 b.exp = ((b.exp - T_BIAS) >> 1) + T_BIAS;
00712 b.frac = fsqrt64(b.frac, b.exp);
00713 return ieee_rpack(&b, ins, dp);
00714 }
00715
00716
00717
00718
00719
00725
00726
00740 int CAlphaCPU::ieee_unpack(u64 op, UFP* r, u32 ins)
00741 {
00742 r->sign = FPR_GETSIGN(op);
00743 r->exp = FPR_GETEXP(op);
00744 r->frac = FPR_GETFRAC(op);
00745 if(r->exp == 0)
00746 {
00747 if(r->frac == 0)
00748 return UFT_ZERO;
00749 if(state.fpcr & FPCR_DNZ)
00750 {
00751 r->frac = 0;
00752 return UFT_ZERO;
00753 }
00754
00755 r->frac = r->frac << FPR_GUARD;
00756 ieee_norm(r);
00757 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00758 return UFT_DENORM;
00759 }
00760
00761 if(r->exp == FPR_NAN)
00762 {
00763 if(r->frac == 0)
00764 return UFT_INF;
00765 if(!(r->frac & QNAN))
00766 ieee_trap(TRAP_INV, 1, FPCR_INVD, ins);
00767 return UFT_NAN;
00768 }
00769
00770 r->frac = (r->frac | FPR_HB) << FPR_GUARD;
00771 return UFT_FIN;
00772 }
00773
00783 void CAlphaCPU::ieee_norm(UFP* r)
00784 {
00785 s32 i;
00786 static u64 normmask[5] = {
00787 U64(0xc000000000000000), U64(0xf000000000000000), U64(0xff00000000000000),
00788 U64(0xffff000000000000), U64(0xffffffff00000000) };
00789 static s32 normtab[6] = { 1, 2, 4, 8, 16, 32};
00790
00791 r->frac = r->frac & X64_QUAD;
00792 if(r->frac == 0)
00793 {
00794 r->exp = 0;
00795 return;
00796 }
00797
00798 while((r->frac & UF_NM) == 0)
00799 {
00800 for(i = 0; i < 5; i++)
00801 {
00802 if(r->frac & normmask[i])
00803 break;
00804 }
00805
00806 r->frac = r->frac << normtab[i];
00807 r->exp = r->exp - normtab[i];
00808 }
00809
00810 return;
00811 }
00812
00845 u64 CAlphaCPU::ieee_rpack(UFP* r, u32 ins, u32 dp)
00846 {
00847 static const u64 stdrnd[2] = { UF_SRND, UF_TRND };
00848 static const u64 infrnd[2] = { UF_SINF, UF_TINF };
00849 static const s32 expmax[2] = { T_BIAS - S_BIAS + S_M_EXP - 1, T_M_EXP - 1};
00850 static const s32 expmin[2] = { T_BIAS - S_BIAS, 0};
00851 u64 rndadd;
00852 u64 rndbits;
00853 u64 res;
00854 u64 rndm;
00855
00856 if(r->frac == 0)
00857 return(((u64) r->sign) << FPR_V_SIGN);
00858 rndm = I_GETFRND(ins);
00859 if(rndm == I_FRND_D)
00860 rndm = FPCR_GETFRND(state.fpcr);
00861 rndbits = r->frac & infrnd[dp];
00862 if(rndm == I_FRND_N)
00863 rndadd = stdrnd[dp];
00864 else if(((rndm == I_FRND_P) && !r->sign)
00865 || ((rndm == I_FRND_M) && r->sign))
00866 rndadd = infrnd[dp];
00867 else
00868 rndadd = 0;
00869 r->frac = (r->frac + rndadd) & X64_QUAD;
00870 if((r->frac & UF_NM) == 0)
00871 {
00872 r->frac = (r->frac >> 1) | UF_NM;
00873 r->exp = r->exp + 1;
00874 }
00875
00876 if(rndbits)
00877 ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins);
00878 if(r->exp > expmax[dp])
00879 {
00880 ieee_trap(TRAP_OVF, 1, FPCR_OVFD, ins);
00881 ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins);
00882 if(rndadd)
00883 return(r->sign ? FMINF : FPINF);
00884 return(r->sign ? FMMAX : FPMAX);
00885 }
00886
00887 if(r->exp <= expmin[dp])
00888 {
00889 ieee_trap(TRAP_UNF, ins & I_FTRP_U,
00890 (state.fpcr & FPCR_UNDZ) ? FPCR_UNFD : 0, ins);
00891 ieee_trap(TRAP_INE, Q_SUI(ins), FPCR_INED, ins);
00892 return 0;
00893 }
00894
00895 res = (((u64) r->sign) << FPR_V_SIGN) |
00896 (((u64) r->exp) << FPR_V_EXP) | ((r->frac >> FPR_GUARD) & FPR_FRAC);
00897 if((rndm == I_FRND_N) && (rndbits == stdrnd[dp]))
00898 res = res &~1;
00899 return res;
00900 }
00901
00915 void CAlphaCPU::ieee_trap(u64 trap, u32 instenb, u64 fpcrdsb, u32 ins)
00916 {
00917 u64 real_trap = U64(0x0);
00918
00919 if(!state.fpcr & (trap << 51))
00920 real_trap |= trap << 41;
00921 if((instenb != 0)
00922 && !((ins & I_FTRP_S) && (state.fpcr & fpcrdsb))) real_trap |= trap;
00923 if(real_trap)
00924 ARITH_TRAP(real_trap | ((ins & I_FTRP_S) ? TRAP_SWC : 0), I_GETRC(ins));
00925 return;
00926 }
00927
00928