Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / n2 / lib / cpu / src / N2_Fpu.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: N2_Fpu.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
#include "N2_Fpu.h"
#include "N2_Strand.h"
N2_Fpu::FloatTrapType N2_Fpu::fpu_postprocess( Instr instr, SS_Strand* s, NumberType src_fpop, NumberType src2_fpop, int Er, NumberType rd_fpop, Precision dest_type, uint64_t *rd_dp_value, uint32_t *rd_sp_value ) /*{{{*/
{
int tem; // Trap Enable Mask
int fef; // Floating Exception Flags
int eft; // Enabled floating traps
int cexc = EXC_NONE;
uint64_t fsr_ns; // floating point status register non-standard
uint64_t gsr_im; // GSR register interval arithmetic mode
FloatTrapType ftt = FTT_NOTRAP;
bool rd_sign; // result sign
uint64_t rnd_mode = (uint64_t)float_rounding_mode; // rounding mode
bool guzr = false; // gross underflow zero result
bool ur = false; // underflow result
bool gor = false; // generated overflow result
bool fpop_subnormal = false; // is fp operation need to be subnormally handled
bool src1_subnorm = false; // source one subnormal
bool src2_subnorm = false; // source two subnormal
bool rd_subnorm = false; // result subnormal
bool rd_positive = false; // sign of the result
bool src1_zero = false; // source one zero
bool src2_zero = false; // source two zero
bool rd_zero = false;
bool src1_nan = false;
bool src2_nan = false;
bool rd_small_norm = false;
int eguf; // exponent gross underflow limit
int emax; // maximum exponent value
fef = float_exception_flags;
tem = s->fsr.tem();
fsr_ns = s->fsr.ns();
gsr_im = s->gsr.im();
if ( (src_fpop == FP_OP_PSUBNORMAL) || (src_fpop == FP_OP_NSUBNORMAL) )
src1_subnorm = true;
if ( (src2_fpop == FP_OP_PSUBNORMAL) || (src2_fpop == FP_OP_NSUBNORMAL) )
src2_subnorm = true;
if ( (rd_fpop == FP_OP_PZERO) || (rd_fpop == FP_OP_NZERO) )
rd_zero = true;
if ( (rd_fpop == FP_OP_PSUBNORMAL) || (rd_fpop == FP_OP_NSUBNORMAL) ||
( ((fef & EXC_UNDERFLOW) == EXC_UNDERFLOW) &&
((fef & EXC_INEXACT) == EXC_INEXACT) &&
(rd_zero) ) )
rd_subnorm = true;
if ( (rd_fpop == FP_OP_PSUBNORMAL) || (rd_fpop == FP_OP_PZERO) )
rd_positive = true;
if ( (src_fpop == FP_OP_PZERO) || (src_fpop == FP_OP_NZERO) )
src1_zero = true;
if ( (src2_fpop == FP_OP_PZERO) || (src2_fpop == FP_OP_NZERO) )
src2_zero = true;
if ( (src_fpop == FP_OP_QNAN) || (src_fpop == FP_OP_SNAN) )
src1_nan = true;
if ( (src2_fpop == FP_OP_QNAN) || (src2_fpop == FP_OP_SNAN) )
src2_nan = true;
if ( (src1_subnorm) || (src2_subnorm) || (rd_subnorm) )
fpop_subnormal = true;
switch (dest_type) {
case SP_TYPE: emax = SP_EMAX; eguf = SP_EGUF; break;
case DP_TYPE: emax = DP_EMAX; eguf = DP_EGUF; break;
default:
break;
}
if ( fpop_subnormal ) {
// In Standard Mode deal with the subnormals
if ((fsr_ns == 0) || (gsr_im == 1)) {
if ( src1_subnorm || src2_subnorm) {
switch (instr) {
case FADDS:
case FADDD:
case FSUBS:
case FSUBD:
if ( (!src1_nan) && (src_fpop != FP_OP_INF) &&
(!src2_nan) && (src2_fpop != FP_OP_INF))
ftt = FTT_UNFINISHED_FPOP;
break;
case FMULS:
case FMULD:
if ( (!src1_nan) && (src_fpop != FP_OP_INF) && (src1_zero != true) &&
(!src2_nan) && (src2_fpop != FP_OP_INF) && (src2_zero != true) ) {
// Emax(P) > Er > EGUF(P)
// Er <= EGUF(P) & Signr=0 & RND=RP
// Er <= EGUF(P) & Signr=1 & RND=RM
if (((emax > Er) && (Er > eguf)) ||
( (Er <= eguf) && (rd_positive == true) && (rnd_mode == ROUND_UP) ) ||
( (Er <= eguf) && (rd_positive == false) && (rnd_mode == ROUND_DOWN) ) ) {
ftt = FTT_UNFINISHED_FPOP;
} else {
guzr = true;
}
}
break;
case FDIVS:
case FDIVD:
if ( (!src1_nan) && (src_fpop != FP_OP_INF) && (!src1_zero) &&
(!src2_nan) && (src2_fpop != FP_OP_INF) && (!src2_zero) ) {
// Er <= EGUF(P) & Signr=0 & RND=RP
// Er <= EGUF(P) & Signr=1 & RND=RM
if ( Er < emax ) {
if ( ((emax > Er) && (Er > eguf)) ||
( (Er <= eguf) && (rd_positive == true) && (rnd_mode == ROUND_UP) ) ||
( (Er <= eguf) && (rd_positive == false) && (rnd_mode == ROUND_DOWN) ) ) {
ftt = FTT_UNFINISHED_FPOP;
} else {
guzr = true;
}
} else {
gor = true;
}
}
break;
case FSMULD:
// if (!(OP_NaN or OP_inf or OP_0))
if ( (!src1_nan) && (src_fpop != FP_OP_INF) && (src1_zero != true) &&
(!src2_nan) && (src2_fpop != FP_OP_INF) && (src2_zero != true) ) {
ftt= FTT_UNFINISHED_FPOP;
}
break;
case FSQRTS:
case FSQRTD:
// if (! (OP_NaN or OP_inf))
if ( (!src2_nan) && (src2_fpop != FP_OP_INF) )
{
if (src2_fpop == FP_OP_NSUBNORMAL)
{
fef = EXC_INVALID; // set FSR.NV
if ( (fef & tem & EXC_INVALID) == EXC_INVALID ) {
ftt = FTT_IEEE_754_EXCEPTION; // generate invalid exception
}
(*rd_dp_value) = QNAN_64;
(*rd_sp_value) = QNAN_32;
} else {
ftt = FTT_UNFINISHED_FPOP;
}
}
break;
case FSTOX:
case FDTOX:
case FSTOI:
case FDTOI:
case FSTOD:
// if (! (OP_NaN or OP_inf))
if ( (!src2_nan) && (src2_fpop != FP_OP_INF) ) {
ftt= FTT_UNFINISHED_FPOP;
}
break;
case FDTOS:
if ( (!src2_nan) && (src2_fpop != FP_OP_INF) ) {
if ( ( (rd_positive == true) && (rnd_mode == ROUND_UP) ) ||
( (rd_positive == false) && (rnd_mode == ROUND_DOWN) ) ) {
ftt = FTT_UNFINISHED_FPOP;
} else {
guzr = true;
}
}
break;
default:
break;
}
} else if ( ( (src_fpop == FP_OP_NORMAL) && (src2_fpop == FP_OP_NORMAL) ) ||
( (src_fpop == FP_OP_NONE) && (src2_fpop == FP_OP_NORMAL) ) ) {
switch (instr) {
case FADDS:
case FADDD:
case FSUBS:
case FSUBD:
ftt = FTT_UNFINISHED_FPOP;
break;
case FMULS:
case FMULD:
case FDIVS:
case FDIVD:
{
int Erb = 0;
// Check whether there is a difference between softfloat's underflow and
// if a number is subnormal, pzero or nzero
bool sf_uf = ( (fef & EXC_UNDERFLOW) == EXC_UNDERFLOW);
bool fgu_uf = rd_subnorm || (rd_fpop == FP_OP_PZERO) || (rd_fpop == FP_OP_PZERO);
if (sf_uf == true) {
Erb = Er + 1;
} else {
Erb = Er;
}
if ( Er < emax ) {
if ( ( rd_subnorm && (Er > eguf) ) || // (sf_uf && (Er > eguf)) //(1 > Erb) && (Er > EGUF(P))
( (Er <= eguf) &&
(rd_positive == true) &&
(rnd_mode == ROUND_UP) ) || // Er <= EGUF(P) & Signr=0 & RND=RP
( (Er <= eguf) &&
(rd_positive == false) &&
(rnd_mode == ROUND_DOWN) ) ) { // Er <= EGUF(P) & Signr=1 & RND=RM
// generate unfinished trap
ftt = FTT_UNFINISHED_FPOP;
} else {
// generate gross underflow zero result
guzr = true;
}
} else {
// generate gross overflow result
gor = true;
}
break;
}
case FDTOS:
{
if ( ( (1 > Er) && (Er > eguf)) || // 1 > Er > EGUF(P)
( (Er <= eguf) &&
(rd_positive == true) &&
(rnd_mode == ROUND_UP) ) || // Er <= EGUF(P) & Signr=0 & RND=RP
( (Er <= eguf) &&
(rd_positive == false) &&
(rnd_mode == ROUND_DOWN) ) ) { // Er <= EGUF(P) & Signr=1 & RND=RM
ftt = FTT_UNFINISHED_FPOP;
} else {
// generate gross underflow zero result
guzr = true;
}
break;
}
default:
break;
}
}
} else if ((fsr_ns == 1) && (gsr_im == 0)) {
// In Non-standard Mode we flush the subnormals to zero
// Based on Table 2-29 in Chapter 2.1.10 of the Millennium PRM
if ( src1_subnorm || src2_subnorm) {
switch (instr) {
case FADDS:
case FADDD:
case FSUBS:
case FSUBD:
case FSTOX:
case FDTOX:
case FSTOI:
case FDTOI:
case FSTOD:
case FDTOS:
if ( (!src1_nan) && (src_fpop != FP_OP_INF) && (!src2_nan) && (src2_fpop != FP_OP_INF) ) {
// set FSR.NX
fef = EXC_INEXACT;
}
break;
case FCMPS:
case FCMPD:
case FCMPES:
case FCMPED:
break;
case FMULS:
case FMULD:
case FSMULD:
{
// (!(OP_NaN or OP_0))
if ( (!src1_nan) && (src1_zero != true) && (!src2_nan) && (src2_zero != true) ) {
if ( (src2_fpop != FP_OP_INF) && (src_fpop != FP_OP_INF) ) {
fef = EXC_INEXACT; // set FSR.NX
} else {
fef = EXC_INVALID; // set FSR.NV
// return QNaN
(*rd_dp_value) = QNAN_64;
(*rd_sp_value) = QNAN_32;
}
}
break;
}
case FDIVS:
case FDIVD:
{
// !(OP_NaN)
if ( (!src2_nan) && (!src1_nan) ) {
if ( (src_fpop != FP_OP_INF) &&
(src2_fpop != FP_OP_INF) &&
(src1_zero != true) &&
(src2_zero != true) ) {
if ( src1_subnorm && src2_subnorm ) {
fef = EXC_INVALID;
} else if ( src2_subnorm == true) {
fef = EXC_DIVBYZERO;
} else {
fef = EXC_INEXACT;
}
} else if ( (src_fpop == FP_OP_INF) || (src2_fpop == FP_OP_INF) ) {
// clear anything?
} else if ( (src1_zero == true) || (src2_zero == true) ) {
fef = EXC_INVALID;
// Clear out FSR.DZ? I don't think it has been set
//---->This case overides DZ, so I might need to do something different
} else {
// Could cause FSR.DZ to be set to zero, would be caught above
}
}
break;
}
case FSQRTS:
case FSQRTD:
{
if ( (!src2_nan) && (src2_fpop != FP_OP_INF) ) {
if (src2_fpop == FP_OP_NSUBNORMAL) {
fef = EXC_INEXACT;
(*rd_dp_value) = to_nil(*rd_dp_value);
(*rd_sp_value) = to_nil(*rd_sp_value);
} else if (src2_zero) {
fef = EXC_NONE;
(*rd_dp_value) = to_nil(*rd_dp_value);
(*rd_sp_value) = to_nil(*rd_sp_value);
} else {
fef = EXC_INEXACT;
}
}
break;
}
default:
break;
}
} else if ( ( (src_fpop == FP_OP_NORMAL) && (src2_fpop == FP_OP_NORMAL) ) ||
( (src_fpop == FP_OP_NONE) && (src2_fpop == FP_OP_NORMAL) ) ) {
switch (instr) {
case FADDS:
case FADDD:
case FSUBS:
case FSUBD:
case FDTOS:
guzr = true;
break;
case FMULS:
case FMULD:
case FDIVS:
case FDIVD:
{
if (Er < emax) { // !(Er >= EMAX(P))
guzr = true;
} else {
gor = true; // generate overflow result
}
break;
}
default:
break;
}
}
}
}
eft = fef & tem;
// If there was no subnormal or the subnormals didn't trap, check for other trap conditions
if (ftt == FTT_NOTRAP)
{
if ( (fef & EXC_OVERFLOW) == EXC_OVERFLOW )
gor = true;
else if ( (eft & EXC_DIVBYZERO) == EXC_DIVBYZERO )
ftt = FTT_IEEE_754_EXCEPTION;
else if ( (eft & EXC_INVALID) == EXC_INVALID )
ftt = FTT_IEEE_754_EXCEPTION;
else if ( ((fef & EXC_UNDERFLOW) == EXC_UNDERFLOW) && !fpop_subnormal)
ur= true;
}
if (((eft & EXC_INEXACT) == EXC_INEXACT) && (guzr != true) && (gor != true) && (ftt == FTT_NOTRAP))
{
ftt = FTT_IEEE_754_EXCEPTION; // generate underflow trap
}
if ( (guzr == true) || (ur == true) )
{
ftt = FTT_NOTRAP;
if (guzr == true)
{
(*rd_dp_value) = to_nil(*rd_dp_value);
(*rd_sp_value) = to_nil(*rd_sp_value);
}
if ( ((tem & EXC_UNDERFLOW) != EXC_UNDERFLOW) && ((tem & EXC_INEXACT) != EXC_INEXACT) )
{
// if (FSR.UFM=0 && FSR.NXM=0)
fef = EXC_UNDERFLOW | EXC_INEXACT;
cexc = fef;
}
else if (((tem & EXC_UNDERFLOW) == EXC_UNDERFLOW) || ((tem & EXC_INEXACT) == EXC_INEXACT) )
{
// if (FSR.UFM=1 OR FSR.NXM=1)
ftt = FTT_IEEE_754_EXCEPTION;
fef = EXC_NONE;
if ( ((tem & EXC_UNDERFLOW) != EXC_UNDERFLOW) && ((tem & EXC_INEXACT) == EXC_INEXACT) )
{
fef = EXC_INEXACT;
}
if ((tem & EXC_UNDERFLOW) == EXC_UNDERFLOW)
{
fef = EXC_UNDERFLOW;
}
cexc = fef;
}
}
else if ( (gor == true) || ( ((fef & EXC_OVERFLOW) == EXC_OVERFLOW) && (ftt == FTT_NOTRAP) ) )
{
// (FSR.OFM = 0 && FSR.NXM = 0)
if ( ((tem & EXC_OVERFLOW) != EXC_OVERFLOW) && ((tem & EXC_INEXACT) != EXC_INEXACT) )
{
ftt = FTT_NOTRAP;
fef = EXC_OVERFLOW | EXC_INEXACT;
}
else if ( ((tem & EXC_OVERFLOW) == EXC_OVERFLOW) || ((tem & EXC_INEXACT) == EXC_INEXACT) )
{ // (FSR.OFM = 1 || FSR.NXM = 1)
ftt = FTT_IEEE_754_EXCEPTION;
if ( ((tem & EXC_OVERFLOW) != EXC_OVERFLOW) && ((tem & EXC_INEXACT) == EXC_INEXACT) )
{
fef = EXC_INEXACT;
}
if ( (tem & EXC_OVERFLOW) == EXC_OVERFLOW )
{
fef = EXC_OVERFLOW;
}
}
cexc = fef;
} else {
cexc = fef;
}
assert(cexc == fef);
float_exception_flags = cexc;
return ftt;
}
/*}}}*/
SS_Vaddr N2_Fpu::exe_fff( Instr instr, SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
uint64_t dp_value[2], dp_result;
uint32_t sp_value[2], sp_result;
uint64_t orig_dp_value[2];
uint32_t orig_sp_value[2];
int Er = 0; // Exponent result
Precision src1_type = UNKNOWN_TYPE;
Precision src2_type = UNKNOWN_TYPE;
Precision dest_type = UNKNOWN_TYPE;
NumberType src1_fptype;
NumberType src2_fptype;
NumberType dest_fptype;
if (s->sim_state.fp_disabled())
return (s->trap)(pc,npc,s,i,SS_Trap::FP_DISABLED);
s->get_fsr();
switch (instr)
{
case FADDS:
case FSUBS:
case FMULS:
case FDIVS:
dest_type = src1_type = src2_type = SP_TYPE;
sp_value[0] = orig_sp_value[0] = s->get_frf(i->rs1);
sp_value[1] = orig_sp_value[1] = s->get_frf(i->rs2);
src1_fptype = fpu_optype(sp_value[0]);
src2_fptype = fpu_optype(sp_value[1]);
break;
case FSMULD:
src1_type = src2_type = SP_TYPE;
dest_type = DP_TYPE;
sp_value[0] = orig_sp_value[0] = s->get_frf(i->rs1);
sp_value[1] = orig_sp_value[1] = s->get_frf(i->rs2);
src1_fptype = fpu_optype(sp_value[0]);
src2_fptype = fpu_optype(sp_value[1]);
break;
case FADDD:
case FSUBD:
case FMULD:
case FDIVD:
dest_type = src1_type = src2_type = DP_TYPE;
dp_value[0] = orig_dp_value[0] = s->get_drf(i->rs1);
dp_value[1] = orig_dp_value[1] = s->get_drf(i->rs2);
src1_fptype = fpu_optype(dp_value[0]);
src2_fptype = fpu_optype(dp_value[1]);
break;
default:
assert(0);
}
if ((s->fsr.ns() == 1) && (s->gsr.im() == 0))
{
switch ( instr )
{
case FADDS:
case FSUBS:
if (is_sub(sp_value[0]) && !is_nan_or_inf(sp_value[1]))
sp_value[0] = to_nil(sp_value[0]);
if (is_sub(sp_value[1]) && !is_nan_or_inf(sp_value[0]))
sp_value[1] = to_nil(sp_value[1]);
break;
case FADDD:
case FSUBD:
if (is_sub(dp_value[0]) && !is_nan_or_inf(dp_value[1]))
dp_value[0] = to_nil(dp_value[0]);
if (is_sub(dp_value[1]) && !is_nan_or_inf(dp_value[0]))
dp_value[1] = to_nil(dp_value[1]);
break;
case FDIVS:
if (is_sub(sp_value[0]) && !is_nan(sp_value[1]))
sp_value[0] = to_nil(sp_value[0]);
if (is_sub(sp_value[1]) && !is_nan(sp_value[0]))
sp_value[1] = to_nil(sp_value[1]);
break;
case FDIVD:
if (is_sub(dp_value[0]) && !is_nan(dp_value[1]))
dp_value[0] = to_nil(dp_value[0]);
if (is_sub(dp_value[1]) && !is_nan(dp_value[0]))
dp_value[1] = to_nil(dp_value[1]);
break;
case FMULS:
case FSMULD:
if (is_sub(sp_value[0]) && !is_nan_or_inf(sp_value[1]) && !is_nil(sp_value[1]))
sp_value[0] = to_nil(sp_value[0]);
if (is_sub(sp_value[1]) && !is_nan_or_inf(sp_value[0]) && !is_nil(sp_value[0]))
sp_value[1] = to_nil(sp_value[1]);
break;
case FMULD:
if (is_sub(dp_value[0]) && !is_nan_or_inf(dp_value[1]) && !is_nil(dp_value[1]))
dp_value[0] = to_nil(dp_value[0]);
if (is_sub(dp_value[1]) && !is_nan_or_inf(dp_value[0]) && !is_nil(dp_value[0]))
dp_value[1] = to_nil(dp_value[1]);
break;
}
}
float_exception_flags = EXC_NONE;
float_rounding_mode = Rounding(s->gsr.im() ? s->gsr.irnd() : s->fsr.rd());
switch (instr)
{
case FADDS:
sp_result = float32_add( sp_value[0], sp_value[1], false );
dest_fptype = fpu_optype(sp_result);
break;
case FADDD:
dp_result = float64_add( dp_value[0], dp_value[1], false );
dest_fptype = fpu_optype(dp_result);
break;
case FSUBS:
sp_result = float32_sub( sp_value[0], sp_value[1], false );
dest_fptype = fpu_optype(sp_result);
break;
case FSUBD:
dp_result = float64_sub( dp_value[0], dp_value[1], false );
dest_fptype = fpu_optype(dp_result);
break;
case FMULS:
sp_result = float32_mul( sp_value[0], sp_value[1], false );
Er = to_exp(sp_value[0]) + to_exp(sp_value[1]) - SP_BIAS;
dest_fptype = fpu_optype(sp_result);
break;
case FMULD:
dp_result = float64_mul( dp_value[0], dp_value[1], false );
Er = to_exp(dp_value[0]) + to_exp(dp_value[1]) - DP_BIAS;
dest_fptype = fpu_optype(dp_result);
break;
case FDIVS:
sp_result = float32_div( sp_value[0], sp_value[1] );
Er = to_exp(sp_value[0]) - to_exp(sp_value[1]) + SP_BIAS - 1;
dest_fptype = fpu_optype(sp_result);
break;
case FDIVD:
dp_result = float64_div( dp_value[0], dp_value[1] );
Er = to_exp(dp_value[0]) - to_exp(dp_value[1]) + DP_BIAS - 1;
dest_fptype = fpu_optype(dp_result);
break;
case FSMULD:
dp_result = float64_mul( float32_to_float64( sp_value[0] ), float32_to_float64( sp_value[1] ), false );
dest_fptype = fpu_optype(dp_result);
break;
default:
assert(0);
}
FloatTrapType ftt = fpu_postprocess(instr,s,src1_fptype,src2_fptype,Er,dest_fptype,dest_type,&dp_result,&sp_result);
if (ftt == FTT_NOTRAP)
{
switch(instr)
{
case FADDS: case FSUBS: case FMULS: case FDIVS:
sp_result = nan_postprocess(orig_sp_value[0],orig_sp_value[1],sp_result);
s->get_frf(i->rd) = sp_result;
break;
case FADDD: case FSUBD: case FMULD: case FDIVD:
dp_result = nan_postprocess(orig_dp_value[0],orig_dp_value[1],dp_result);
s->get_drf(i->rd) = dp_result;
break;
case FSMULD:
dp_result = nan_postprocess(orig_sp_value[0],orig_sp_value[1],dp_result);
s->get_drf(i->rd) = dp_result;
break;
default:
assert(0);
break;
}
s->set_fprs(i->rd);
}
return exe_end(pc,npc,s,i,ftt,float_exception_flags);
}
/*}}}*/
SS_Vaddr N2_Fpu::exe_fof( Instr instr, SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
uint64_t dp_value;
uint32_t sp_value;
Precision src2_type = UNKNOWN_TYPE;
Precision dest_type = UNKNOWN_TYPE;
NumberType src2_fptype;
NumberType dest_fptype;
int Er = 0; // Exponent result
if (s->sim_state.fp_disabled())
return (s->trap)(pc,npc,s,i,SS_Trap::FP_DISABLED);
s->get_fsr();
switch (instr)
{
case FMOVS:
case FNEGS:
case FABSS:
case FSQRTS:
case FSTOI:
case FITOS:
src2_type = SP_TYPE;
dest_type = SP_TYPE;
sp_value = s->get_frf(i->rs2);
src2_fptype = fpu_optype(sp_value);
break;
case FMOVD:
case FNEGD:
case FABSD:
case FSQRTD:
case FDTOX:
case FXTOD:
src2_type = DP_TYPE;
dest_type = DP_TYPE;
dp_value = s->get_drf(i->rs2);
src2_fptype = fpu_optype(dp_value);
break;
case FSTOX:
case FSTOD:
case FITOD:
src2_type = SP_TYPE;
dest_type = DP_TYPE;
sp_value = s->get_frf(i->rs2);
src2_fptype = fpu_optype(sp_value);
break;
case FDTOI:
case FDTOS:
case FXTOS:
src2_type = DP_TYPE;
dest_type = SP_TYPE;
dp_value = s->get_drf(i->rs2);
src2_fptype = fpu_optype(dp_value);
break;
default:
assert(0);
}
if ((s->fsr.ns() == 1) && (s->gsr.im() == 0)) // Non-standard Mode
{
switch ( instr )
{
case FSTOX:
case FSTOI:
case FSTOD:
case FSQRTS:
if (is_sub(sp_value))
sp_value = to_nil(sp_value);
break;
case FDTOX:
case FDTOI:
case FDTOS:
case FSQRTD:
if (is_sub(dp_value))
dp_value = to_nil(dp_value);
break;
}
}
float_exception_flags = EXC_NONE;
if ((instr == FSTOX) || (instr == FSTOI) || (instr == FDTOX) || (instr == FDTOI))
float_rounding_mode = ROUND_TO_ZERO;
else
float_rounding_mode = Rounding(s->gsr.im() ? s->gsr.irnd() : s->fsr.rd());
switch (instr)
{
case FMOVS:
sp_value = sp_value;
dest_fptype = fpu_optype(sp_value);
break;
case FMOVD:
dp_value = dp_value;
dest_fptype = fpu_optype(dp_value);
break;
case FNEGS:
sp_value = to_neg(sp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FNEGD:
dp_value = to_neg(dp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FABSS:
sp_value = to_abs(sp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FABSD:
dp_value = to_abs(dp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FSTOI:
sp_value = float32_to_int32(sp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FSTOX:
dp_value = float32_to_int64(sp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FITOS:
sp_value = int32_to_float32(sp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FITOD:
dp_value = int32_to_float64(sp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FDTOI:
sp_value = float64_to_int32(dp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FDTOX:
dp_value = float64_to_int64(dp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FXTOS:
sp_value = int64_to_float32(dp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FXTOD:
dp_value = int64_to_float64(dp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FSTOD:
dp_value = float32_to_float64(sp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FSQRTS:
Er = to_sgn(sp_value);
sp_value = float32_sqrt(sp_value);
dest_fptype = fpu_optype(sp_value);
break;
case FSQRTD:
Er = to_sgn(dp_value);
dp_value = float64_sqrt(dp_value);
dest_fptype = fpu_optype(dp_value);
break;
case FDTOS:
Er = to_exp(dp_value) - DP_BIAS + SP_BIAS;
sp_value = float64_to_float32(dp_value);
dest_fptype = fpu_optype(sp_value);
break;
default:
assert(0);
}
FloatTrapType ftt = fpu_postprocess(instr,s,FP_OP_NONE,src2_fptype,Er,dest_fptype,dest_type,&dp_value,&sp_value);
if (ftt == FTT_NOTRAP)
{
switch (dest_type)
{
case SP_TYPE: s->get_frf(i->rd) = sp_value; break;
case DP_TYPE: s->get_drf(i->rd) = dp_value; break;
}
s->set_fprs(i->rd);
}
return exe_end(pc,npc,s,i,ftt,float_exception_flags);
}
/*}}}*/
SS_Vaddr N2_Fpu::exe_off( Instr instr, SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
int e, l, g;
if (s->sim_state.fp_disabled())
return (s->trap)(pc,npc,s,i,SS_Trap::FP_DISABLED);
s->get_fsr();
float_exception_flags = EXC_NONE;
float_rounding_mode = Rounding(s->gsr.im() ? s->gsr.irnd() : s->fsr.rd());
switch (instr)
{
case FCMPS:
{
uint32_t a = s->get_frf(i->rs1);
uint32_t b = s->get_frf(i->rs2);
e = float32_eq(a,b);
l = float32_lt_quiet(a,b);
g = float32_lt_quiet(b,a) && !e;
break;
}
case FCMPES:
{
uint32_t a = s->get_frf(i->rs1);
uint32_t b = s->get_frf(i->rs2);
e = float32_eq_signaling(a,b);
l = float32_lt(a,b);
g = float32_lt(b,a) && !e;
break;
}
case FCMPD:
{
uint64_t a = s->get_drf(i->rs1);
uint64_t b = s->get_drf(i->rs2);
e = float64_eq(a,b);
l = float64_lt_quiet(a,b);
g = float64_lt_quiet(b,a) && !e;
break;
}
case FCMPED:
{
uint64_t a = s->get_drf(i->rs1);
uint64_t b = s->get_drf(i->rs2);
e = float64_eq_signaling(a,b);
l = float64_lt(a,b);
g = float64_lt(b,a) && !e;
break;
}
default:
assert(0);
}
FloatTrapType ftt = FTT_NOTRAP;
int eft = float_exception_flags & s->fsr.tem();
if (eft & EXC_INVALID)
ftt = FTT_IEEE_754_EXCEPTION;
else
set_fcc(s->fsr,ConditionField(i->rd),(e ? EQ : (l ? LT : (g ? GT : UN))));
return exe_end(pc,npc,s,i,ftt,float_exception_flags);
}
/*}}}*/
SS_Vaddr n2_exe_fadds( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FADDS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fsubs( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FSUBS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fmuls( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FMULS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fdivs( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FDIVS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_faddd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FADDD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fsubd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FSUBD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fmuld( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FMULD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fdivd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FDIVD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fsmuld( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fff(N2_Fpu::FSMULD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fstoi( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FSTOI,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fstox( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FSTOX,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fstod( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FSTOD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fitos( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FITOS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fitod( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FITOD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fdtoi( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FDTOI,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fdtox( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FDTOX,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fdtos( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FDTOS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fxtos( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FXTOS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fxtod( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FXTOD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fmovs( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FMOVS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fnegs( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FNEGS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fabss( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FABSS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fmovd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FMOVD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fnegd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FNEGD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fabsd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FABSD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fsqrts( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FSQRTS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fsqrtd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_fof(N2_Fpu::FSQRTD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fcmps( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_off(N2_Fpu::FCMPS,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fcmpd( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_off(N2_Fpu::FCMPD,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fcmpes( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_off(N2_Fpu::FCMPES,pc,npc,s,i);
}
/*}}}*/
SS_Vaddr n2_exe_fcmped( SS_Vaddr pc, SS_Vaddr npc, SS_Strand* s, SS_Instr* i )/*{{{*/
{
return ((N2_Strand*)s)->fpu.exe_off(N2_Fpu::FCMPED,pc,npc,s,i);
}
/*}}}*/