AlphaCPU_vaxfloat.cpp

Go to the documentation of this file.
00001 /* ES40 emulator.
00002  * Copyright (C) 2007-2008 by the ES40 Emulator Project
00003  *
00004  * WWW    : http://sourceforge.net/projects/es40
00005  * E-mail : camiel@camicom.com
00006  * 
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  * 
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  * 
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00020  * 
00021  * Although this is not required, the author would appreciate being notified of, 
00022  * and receiving any modifications you may make to the source code that might serve
00023  * the general public.
00024  */
00025 
00067 #include "StdAfx.h"
00068 #include "AlphaCPU.h"
00069 #include "cpu_debug.h"
00070 
00071 #define IPMAX U64(0x7FFFFFFFFFFFFFFF)   /* plus MAX (int) */
00072 #define IMMAX U64(0x8000000000000000)   /* minus MAX (int) */
00073 
00074 /* Unpacked rounding constants */
00075 #define UF_FRND U64(0x0000008000000000) /* F round */
00076 #define UF_DRND U64(0x0000000000000080) /* D round */
00077 #define UF_GRND U64(0x0000000000000400) /* G round */
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;  /* zero? */
00103   u64 res = (((u64) (op & F_SIGN)) ? FPR_SIGN : 0) |  /* finite non-zero */
00104   (((u64) exp) << FPR_V_EXP) | (((u64) SWAP_VAXF(op &~(F_SIGN | F_EXP))) << F_V_FRAC);
00105 
00106   //printf("vax_ldf: %08x -> %016" LL "x.\n", op, res);
00107   return res;
00108 }
00109 
00119 u64 CAlphaCPU::vax_ldg(u64 op)
00120 {
00121   return SWAP_VAXG(op); /* swizzle bits */
00122 }
00123 
00134 u32 CAlphaCPU::vax_stf(u64 op)
00135 {
00136   u32 sign = FPR_GETSIGN(op) ? F_SIGN : 0;
00137 
00138   //u32 exp = ((u32) (op >> (FPR_V_EXP - F_V_EXP))) & F_EXP;
00139   u32 exp = FPR_GETEXP(op);
00140   if(exp != 0)
00141     exp = exp + F_BIAS - G_BIAS;  /* zero? */
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   //printf("vax_stf: %016" LL "x -> %08x.\n", op, res);
00149   return res;
00150 }
00151 
00161 u64 CAlphaCPU::vax_stg(u64 op)
00162 {
00163   return SWAP_VAXG(op); /* swizzle bits */
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; /* equal? */
00196   if(a.sign != b.sign)
00197     return(a.sign ? -1 : +1); /* opp signs? */
00198   return(((s1 < s2) ^ a.sign) ? -1 : +1); /* like signs */
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;   /* 0? return +0 */
00216   if(val < 0)
00217   {             /* < 0? */
00218     a.sign = 1; /* set sign */
00219     val = NEG_Q(val);
00220   } /* |val| */
00221   else
00222     a.sign = 0;
00223   a.exp = 64 + G_BIAS;            /* set exp */
00224   a.frac = val;                   /* set frac */
00225   vax_norm(&a);                   /* normalize */
00226   return vax_rpack(&a, ins, dp);  /* round and pack */
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; /* unbiased exp */
00248   if(ubexp < 0)
00249     return 0; /* zero or too small? */
00250   if(ubexp <= UF_V_NM)
00251   {           /* in range? */
00252     a.frac = a.frac >> (UF_V_NM - ubexp); /* leave rnd bit */
00253     if(rndm)
00254       a.frac = a.frac + 1;  /* not chopped, round */
00255     a.frac = a.frac >> 1;   /* now justified */
00256     if((a.frac > (a.sign ? IMMAX : IPMAX))  /* out of range? */
00257      && (ins & I_FTRP_V)) /* trap enabled? */vax_trap(TRAP_IOV, ins);
00258   } /* set overflow */
00259   else
00260   {
00261     if(ubexp > (UF_V_NM + 64))
00262       a.frac = 0; /* out of range */
00263     else
00264       a.frac = (a.frac << (ubexp - UF_V_NM - 1)) & X64_QUAD;  /* no rnd bit */
00265     if(ins & I_FTRP_V)  /* trap enabled? */
00266       vax_trap(TRAP_IOV, ins);
00267   } /* set overflow */
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;  /* sub? invert b sign */
00297   if(a.exp == 0)
00298     a = b;        /* s1 = 0? */
00299   else if(b.exp)  /* s2 != 0? */
00300   {
00301     if((a.exp < b.exp)      /* |s1| < |s2|? swap */
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;  /* exp diff */
00310     if(a.sign ^ b.sign)     /* eff sub? */
00311     {
00312       if(ediff > 63)
00313         b.frac = 1;         /* >63? retain sticky */
00314       else if(ediff)        /* [1,63]? shift */
00315       {
00316         sticky = ((b.frac << (64 - ediff)) & X64_QUAD) ? 1 : 0; /* lost bits */
00317         b.frac = (b.frac >> ediff) | sticky;
00318       }
00319 
00320       a.frac = (a.frac - b.frac) & X64_QUAD;  /* subtract fractions */
00321       vax_norm(&a); /* normalize */
00322     }
00323     else            /* eff add */
00324     {
00325       if(ediff > 63)
00326         b.frac = 0; /* >63? b disappears */
00327       else if(ediff)
00328         b.frac = b.frac >> ediff; /* denormalize */
00329       a.frac = (a.frac + b.frac) & X64_QUAD;  /* add frac */
00330       if(a.frac < b.frac) /* chk for carry */
00331       {
00332         a.frac = UF_NM | (a.frac >> 1); /* shift in carry */
00333         a.exp = a.exp + 1;  /* skip norm */
00334       }
00335     }
00336   } /* end else if */
00337 
00338   return vax_rpack(&a, ins, dp);  /* round and pack */
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; /* zero argument? */
00361   a.sign = a.sign ^ b.sign;         /* sign of result */
00362   a.exp = a.exp + b.exp - G_BIAS;   /* add exponents */
00363   uemul64(a.frac, b.frac, &a.frac); /* mpy fractions */
00364   vax_norm(&a); /* normalize */
00365   return vax_rpack(&a, ins, dp);  /* round and pack */
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   { /* divr = 0? */
00392     vax_trap(TRAP_DZE, ins);  /* dze trap */
00393     return 0;
00394   }
00395 
00396   if(a.exp == 0)
00397     return 0; /* divd = 0? */
00398   a.sign = a.sign ^ b.sign;           /* result sign */
00399   a.exp = a.exp - b.exp + G_BIAS + 1; /* unbiased exp */
00400   a.frac = a.frac >> 1; /* allow 1 bit left */
00401   b.frac = b.frac >> 1;
00402   a.frac = ufdiv64(a.frac, b.frac, 55, NULL); /* divide */
00403   vax_norm(&a); /* normalize */
00404   return vax_rpack(&a, ins, dp);  /* round and pack */
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; /* zero? */
00423   if(b.sign)
00424   {           /* minus? */
00425     vax_trap(TRAP_INV, ins);  /* invalid operand */
00426     return 0;
00427   }
00428 
00429   b.exp = ((b.exp + 1 - G_BIAS) >> 1) + G_BIAS; /* result exponent */
00430   b.frac = fsqrt64(b.frac, b.exp);  /* result fraction */
00431   return vax_rpack(&b, ins, dp);    /* round and pack */
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);  /* get sign */
00475   r->exp = FPR_GETEXP(op);    /* get exponent */
00476   r->frac = FPR_GETFRAC(op);  /* get fraction */
00477   if(r->exp == 0)     /* exp = 0? */
00478   {
00479     if(r->sign != 0)  /* rsvd op? */
00480       vax_trap(TRAP_INV, ins);
00481 
00482     // zero
00483     r->frac = r->sign = 0;
00484     return;
00485   }
00486 
00487   r->frac = (r->frac | FPR_HB) << FPR_GUARD;  /* ins hidden bit, guard */
00488   return;
00489 }
00490 
00503 void CAlphaCPU::vax_unpack_d(u64 op, UFP* r, u32 ins)
00504 {
00505   r->sign = FDR_GETSIGN(op);  /* get sign */
00506   r->exp = FDR_GETEXP(op);    /* get exponent */
00507   r->frac = FDR_GETFRAC(op);  /* get fraction */
00508   if(r->exp == 0) /* exp = 0? */
00509   {
00510     if(op != 0)   /* rsvd op? */
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;          /* change to G bias */
00517   r->frac = (r->frac | FDR_HB) << FDR_GUARD;  /* ins hidden bit, 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   { /* if fraction = 0 */
00541     r->sign = r->exp = 0; /* result is 0 */
00542     return;
00543   }
00544 
00545   while((r->frac & UF_NM) == 0)
00546   {   /* normalized? */
00547     for(i = 0; i < 5; i++)
00548     { /* find first 1 */
00549       if(r->frac & normmask[i])
00550         break;
00551     }
00552 
00553     r->frac = r->frac << normtab[i];  /* shift frac */
00554     r->exp = r->exp - normtab[i];
00555   } /* decr exp */
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; /* result 0? */
00582   if(rndm)
00583   {           /* round? */
00584     r->frac = (r->frac + roundbit[dp]) & X64_QUAD;  /* add round bit */
00585     if((r->frac & UF_NM) == 0)
00586     { /* carry out? */
00587       r->frac = (r->frac >> 1) | UF_NM; /* renormalize */
00588       r->exp = r->exp + 1;
00589     }
00590   }
00591 
00592   if(r->exp > expmax[dp])
00593   { /* ovflo? */
00594     vax_trap(TRAP_OVF, ins);  /* set trap */
00595     r->exp = expmax[dp];
00596   } /* return max */
00597 
00598   if(r->exp <= expmin[dp])
00599   { /* underflow? */
00600     if(ins & I_FTRP_V)
00601       vax_trap(TRAP_UNF, ins);  /* enabled? set trap */
00602     return 0;
00603   } /* underflow to 0 */
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; /* result 0? */
00624   r->exp = r->exp + D_BIAS - G_BIAS;  /* rebias */
00625   if(r->exp > FDR_M_EXP)
00626   { /* ovflo? */
00627     vax_trap(TRAP_OVF, ins);  /* set trap */
00628     r->exp = FDR_M_EXP;
00629   } /* return max */
00630 
00631   if(r->exp <= 0)
00632   { /* underflow? */
00633     if(ins & I_FTRP_V)
00634       vax_trap(TRAP_UNF, ins);  /* enabled? set trap */
00635     return 0;
00636   } /* underflow to 0 */
00637 
00638   return(((u64) r->sign) << FDR_V_SIGN) | (((u64) r->exp) << FDR_V_EXP) | ((r->frac >> FDR_GUARD) & FDR_FRAC);
00639 }
00640 
00641 //\}

SourceForge.net Logo
Project space on SourceForge.net