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
00067 #include "StdAfx.h"
00068 #include "AlphaCPU.h"
00069 #include "cpu_debug.h"
00070
00071 #define IPMAX U64(0x7FFFFFFFFFFFFFFF)
00072 #define IMMAX U64(0x8000000000000000)
00073
00074
00075 #define UF_FRND U64(0x0000008000000000)
00076 #define UF_DRND U64(0x0000000000000080)
00077 #define UF_GRND U64(0x0000000000000400)
00078
00079
00080
00086
00087
00098 u64 CAlphaCPU::vax_ldf(u32 op)
00099 {
00100 u32 exp = F_GETEXP(op);
00101 if(exp != 0)
00102 exp = exp + G_BIAS - F_BIAS;
00103 u64 res = (((u64) (op & F_SIGN)) ? FPR_SIGN : 0) |
00104 (((u64) exp) << FPR_V_EXP) | (((u64) SWAP_VAXF(op &~(F_SIGN | F_EXP))) << F_V_FRAC);
00105
00106
00107 return res;
00108 }
00109
00119 u64 CAlphaCPU::vax_ldg(u64 op)
00120 {
00121 return SWAP_VAXG(op);
00122 }
00123
00134 u32 CAlphaCPU::vax_stf(u64 op)
00135 {
00136 u32 sign = FPR_GETSIGN(op) ? F_SIGN : 0;
00137
00138
00139 u32 exp = FPR_GETEXP(op);
00140 if(exp != 0)
00141 exp = exp + F_BIAS - G_BIAS;
00142 exp = (exp << F_V_EXP) & F_EXP;
00143
00144 u32 frac = (u32) (op >> F_V_FRAC);
00145
00146 u32 res = sign | exp | (SWAP_VAXF(frac) &~(F_SIGN | F_EXP));
00147
00148
00149 return res;
00150 }
00151
00161 u64 CAlphaCPU::vax_stg(u64 op)
00162 {
00163 return SWAP_VAXG(op);
00164 }
00165
00166
00167
00168
00169
00175
00176
00186 int CAlphaCPU::vax_fcmp(u64 s1, u64 s2, u32 ins)
00187 {
00188 UFP a;
00189
00190 UFP b;
00191
00192 vax_unpack(s1, &a, ins);
00193 vax_unpack(s2, &b, ins);
00194 if(s1 == s2)
00195 return 0;
00196 if(a.sign != b.sign)
00197 return(a.sign ? -1 : +1);
00198 return(((s1 < s2) ^ a.sign) ? -1 : +1);
00199 }
00200
00210 u64 CAlphaCPU::vax_cvtif(u64 val, u32 ins, u32 dp)
00211 {
00212 UFP a;
00213
00214 if(val == 0)
00215 return 0;
00216 if(val < 0)
00217 {
00218 a.sign = 1;
00219 val = NEG_Q(val);
00220 }
00221 else
00222 a.sign = 0;
00223 a.exp = 64 + G_BIAS;
00224 a.frac = val;
00225 vax_norm(&a);
00226 return vax_rpack(&a, ins, dp);
00227 }
00228
00240 u64 CAlphaCPU::vax_cvtfi(u64 op, u32 ins)
00241 {
00242 UFP a;
00243 u32 rndm = I_GETFRND(ins);
00244 s32 ubexp;
00245
00246 vax_unpack(op, &a, ins);
00247 ubexp = a.exp - G_BIAS;
00248 if(ubexp < 0)
00249 return 0;
00250 if(ubexp <= UF_V_NM)
00251 {
00252 a.frac = a.frac >> (UF_V_NM - ubexp);
00253 if(rndm)
00254 a.frac = a.frac + 1;
00255 a.frac = a.frac >> 1;
00256 if((a.frac > (a.sign ? IMMAX : IPMAX))
00257 && (ins & I_FTRP_V)) vax_trap(TRAP_IOV, ins);
00258 }
00259 else
00260 {
00261 if(ubexp > (UF_V_NM + 64))
00262 a.frac = 0;
00263 else
00264 a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & X64_QUAD;
00265 if(ins & I_FTRP_V)
00266 vax_trap(TRAP_IOV, ins);
00267 }
00268
00269 return(a.sign ? NEG_Q(a.frac) : a.frac);
00270 }
00271
00283 u64 CAlphaCPU::vax_fadd(u64 s1, u64 s2, u32 ins, u32 dp, bool sub)
00284 {
00285 UFP a;
00286
00287 UFP b;
00288
00289 UFP t;
00290 u32 sticky;
00291 s32 ediff;
00292
00293 vax_unpack(s1, &a, ins);
00294 vax_unpack(s2, &b, ins);
00295 if(sub)
00296 b.sign = b.sign ^ 1;
00297 if(a.exp == 0)
00298 a = b;
00299 else if(b.exp)
00300 {
00301 if((a.exp < b.exp)
00302 || ((a.exp == b.exp) && (a.frac < b.frac)))
00303 {
00304 t = a;
00305 a = b;
00306 b = t;
00307 }
00308
00309 ediff = a.exp - b.exp;
00310 if(a.sign ^ b.sign)
00311 {
00312 if(ediff > 63)
00313 b.frac = 1;
00314 else if(ediff)
00315 {
00316 sticky = ((b.frac << (64 - ediff)) & X64_QUAD) ? 1 : 0;
00317 b.frac = (b.frac >> ediff) | sticky;
00318 }
00319
00320 a.frac = (a.frac - b.frac) & X64_QUAD;
00321 vax_norm(&a);
00322 }
00323 else
00324 {
00325 if(ediff > 63)
00326 b.frac = 0;
00327 else if(ediff)
00328 b.frac = b.frac >> ediff;
00329 a.frac = (a.frac + b.frac) & X64_QUAD;
00330 if(a.frac < b.frac)
00331 {
00332 a.frac = UF_NM | (a.frac >> 1);
00333 a.exp = a.exp + 1;
00334 }
00335 }
00336 }
00337
00338 return vax_rpack(&a, ins, dp);
00339 }
00340
00351 u64 CAlphaCPU::vax_fmul(u64 s1, u64 s2, u32 ins, u32 dp)
00352 {
00353 UFP a;
00354
00355 UFP b;
00356
00357 vax_unpack(s1, &a, ins);
00358 vax_unpack(s2, &b, ins);
00359 if((a.exp == 0) || (b.exp == 0))
00360 return 0;
00361 a.sign = a.sign ^ b.sign;
00362 a.exp = a.exp + b.exp - G_BIAS;
00363 uemul64(a.frac, b.frac, &a.frac);
00364 vax_norm(&a);
00365 return vax_rpack(&a, ins, dp);
00366 }
00367
00382 u64 CAlphaCPU::vax_fdiv(u64 s1, u64 s2, u32 ins, u32 dp)
00383 {
00384 UFP a;
00385
00386 UFP b;
00387
00388 vax_unpack(s1, &a, ins);
00389 vax_unpack(s2, &b, ins);
00390 if(b.exp == 0)
00391 {
00392 vax_trap(TRAP_DZE, ins);
00393 return 0;
00394 }
00395
00396 if(a.exp == 0)
00397 return 0;
00398 a.sign = a.sign ^ b.sign;
00399 a.exp = a.exp - b.exp + G_BIAS + 1;
00400 a.frac = a.frac >> 1;
00401 b.frac = b.frac >> 1;
00402 a.frac = ufdiv64(a.frac, b.frac, 55, NULL);
00403 vax_norm(&a);
00404 return vax_rpack(&a, ins, dp);
00405 }
00406
00416 u64 CAlphaCPU::vax_sqrt(u64 op, u32 ins, u32 dp)
00417 {
00418 UFP b;
00419
00420 vax_unpack(op, &b, ins);
00421 if(b.exp == 0)
00422 return 0;
00423 if(b.sign)
00424 {
00425 vax_trap(TRAP_INV, ins);
00426 return 0;
00427 }
00428
00429 b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS;
00430 b.frac = fsqrt64(b.frac, b.exp);
00431 return vax_rpack(&b, ins, dp);
00432 }
00433
00434
00435
00436
00437
00443
00444
00455 void CAlphaCPU::vax_trap(u64 mask, u32 ins)
00456 {
00457 ARITH_TRAP(mask | ((ins & I_FTRP_S) ? TRAP_SWC : 0), I_GETRC(ins));
00458 }
00459
00472 void CAlphaCPU::vax_unpack(u64 op, UFP* r, u32 ins)
00473 {
00474 r->sign = FPR_GETSIGN(op);
00475 r->exp = FPR_GETEXP(op);
00476 r->frac = FPR_GETFRAC(op);
00477 if(r->exp == 0)
00478 {
00479 if(r->sign != 0)
00480 vax_trap(TRAP_INV, ins);
00481
00482
00483 r->frac = r->sign = 0;
00484 return;
00485 }
00486
00487 r->frac = (r->frac | FPR_HB) << FPR_GUARD;
00488 return;
00489 }
00490
00503 void CAlphaCPU::vax_unpack_d(u64 op, UFP* r, u32 ins)
00504 {
00505 r->sign = FDR_GETSIGN(op);
00506 r->exp = FDR_GETEXP(op);
00507 r->frac = FDR_GETFRAC(op);
00508 if(r->exp == 0)
00509 {
00510 if(op != 0)
00511 vax_trap(TRAP_INV, ins);
00512 r->frac = r->sign = 0;
00513 return;
00514 }
00515
00516 r->exp = r->exp + G_BIAS - D_BIAS;
00517 r->frac = (r->frac | FDR_HB) << FDR_GUARD;
00518 return;
00519 }
00520
00530 void CAlphaCPU::vax_norm(UFP* r)
00531 {
00532 s32 i;
00533 static u64 normmask[5] = {
00534 U64(0xc000000000000000), U64(0xf000000000000000), U64(0xff00000000000000),
00535 U64(0xffff000000000000), U64(0xffffffff00000000) };
00536 static s32 normtab[6] = { 1, 2, 4, 8, 16, 32};
00537
00538 r->frac = r->frac & X64_QUAD;
00539 if(r->frac == 0)
00540 {
00541 r->sign = r->exp = 0;
00542 return;
00543 }
00544
00545 while((r->frac & UF_NM) == 0)
00546 {
00547 for(i = 0; i < 5; i++)
00548 {
00549 if(r->frac & normmask[i])
00550 break;
00551 }
00552
00553 r->frac = r->frac << normtab[i];
00554 r->exp = r->exp - normtab[i];
00555 }
00556
00557 return;
00558 }
00559
00573 u64 CAlphaCPU::vax_rpack(UFP* r, u32 ins, u32 dp)
00574 {
00575 u32 rndm = I_GETFRND(ins);
00576 static const u64 roundbit[2] = { UF_FRND, UF_GRND };
00577 static const s32 expmax[2] = { G_BIAS - F_BIAS + F_M_EXP, G_M_EXP };
00578 static const s32 expmin[2] = { G_BIAS - F_BIAS, 0};
00579
00580 if(r->frac == 0)
00581 return 0;
00582 if(rndm)
00583 {
00584 r->frac = (r->frac + roundbit[dp]) & X64_QUAD;
00585 if((r->frac & UF_NM) == 0)
00586 {
00587 r->frac = (r->frac >> 1) | UF_NM;
00588 r->exp = r->exp + 1;
00589 }
00590 }
00591
00592 if(r->exp > expmax[dp])
00593 {
00594 vax_trap(TRAP_OVF, ins);
00595 r->exp = expmax[dp];
00596 }
00597
00598 if(r->exp <= expmin[dp])
00599 {
00600 if(ins & I_FTRP_V)
00601 vax_trap(TRAP_UNF, ins);
00602 return 0;
00603 }
00604
00605 return(((u64) r->sign) << FPR_V_SIGN) | (((u64) r->exp) << FPR_V_EXP) | ((r->frac >> FPR_GUARD) & FPR_FRAC);
00606 }
00607
00620 u64 CAlphaCPU::vax_rpack_d(UFP* r, u32 ins)
00621 {
00622 if(r->frac == 0)
00623 return 0;
00624 r->exp = r->exp + D_BIAS - G_BIAS;
00625 if(r->exp > FDR_M_EXP)
00626 {
00627 vax_trap(TRAP_OVF, ins);
00628 r->exp = FDR_M_EXP;
00629 }
00630
00631 if(r->exp <= 0)
00632 {
00633 if(ins & I_FTRP_V)
00634 vax_trap(TRAP_UNF, ins);
00635 return 0;
00636 }
00637
00638 return(((u64) r->sign) << FDR_V_SIGN) | (((u64) r->exp) << FDR_V_EXP) | ((r->frac >> FDR_GUARD) & FDR_FRAC);
00639 }
00640
00641