/* Accurate fp support for CGEN-based simulators.
|
/* Accurate fp support for CGEN-based simulators.
|
Copyright (C) 1999 Cygnus Solutions.
|
Copyright (C) 1999 Cygnus Solutions.
|
|
|
This implemention assumes:
|
This implemention assumes:
|
typedef USI SF;
|
typedef USI SF;
|
typedef UDI DF;
|
typedef UDI DF;
|
|
|
TODO:
|
TODO:
|
- lazy encoding/decoding
|
- lazy encoding/decoding
|
- checking return code (say by callback)
|
- checking return code (say by callback)
|
- proper rounding
|
- proper rounding
|
*/
|
*/
|
|
|
#include "sim-main.h"
|
#include "sim-main.h"
|
#include "sim-fpu.h"
|
#include "sim-fpu.h"
|
|
|
/* SF mode support */
|
/* SF mode support */
|
|
|
static SF
|
static SF
|
addsf (CGEN_FPU* fpu, SF x, SF y)
|
addsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
status = sim_fpu_add (&ans, &op1, &op2);
|
status = sim_fpu_add (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
subsf (CGEN_FPU* fpu, SF x, SF y)
|
subsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
status = sim_fpu_sub (&ans, &op1, &op2);
|
status = sim_fpu_sub (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
mulsf (CGEN_FPU* fpu, SF x, SF y)
|
mulsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
status = sim_fpu_mul (&ans, &op1, &op2);
|
status = sim_fpu_mul (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
divsf (CGEN_FPU* fpu, SF x, SF y)
|
divsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
status = sim_fpu_div (&ans, &op1, &op2);
|
status = sim_fpu_div (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
negsf (CGEN_FPU* fpu, SF x)
|
negsf (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
status = sim_fpu_neg (&ans, &op1);
|
status = sim_fpu_neg (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
abssf (CGEN_FPU* fpu, SF x)
|
abssf (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
status = sim_fpu_abs (&ans, &op1);
|
status = sim_fpu_abs (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
sqrtsf (CGEN_FPU* fpu, SF x)
|
sqrtsf (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
status = sim_fpu_sqrt (&ans, &op1);
|
status = sim_fpu_sqrt (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
invsf (CGEN_FPU* fpu, SF x)
|
invsf (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
status = sim_fpu_inv (&ans, &op1);
|
status = sim_fpu_inv (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
minsf (CGEN_FPU* fpu, SF x, SF y)
|
minsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
status = sim_fpu_min (&ans, &op1, &op2);
|
status = sim_fpu_min (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
maxsf (CGEN_FPU* fpu, SF x, SF y)
|
maxsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
status = sim_fpu_max (&ans, &op1, &op2);
|
status = sim_fpu_max (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static CGEN_FP_CMP
|
static CGEN_FP_CMP
|
cmpsf (CGEN_FPU* fpu, SF x, SF y)
|
cmpsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
|
|
if (sim_fpu_is_nan (&op1)
|
if (sim_fpu_is_nan (&op1)
|
|| sim_fpu_is_nan (&op2))
|
|| sim_fpu_is_nan (&op2))
|
return FP_CMP_NAN;
|
return FP_CMP_NAN;
|
|
|
if (x < y)
|
if (x < y)
|
return FP_CMP_LT;
|
return FP_CMP_LT;
|
if (x > y)
|
if (x > y)
|
return FP_CMP_GT;
|
return FP_CMP_GT;
|
return FP_CMP_EQ;
|
return FP_CMP_EQ;
|
}
|
}
|
|
|
static int
|
static int
|
eqsf (CGEN_FPU* fpu, SF x, SF y)
|
eqsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
return sim_fpu_is_eq (&op1, &op2);
|
return sim_fpu_is_eq (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
nesf (CGEN_FPU* fpu, SF x, SF y)
|
nesf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
return sim_fpu_is_ne (&op1, &op2);
|
return sim_fpu_is_ne (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
ltsf (CGEN_FPU* fpu, SF x, SF y)
|
ltsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
return sim_fpu_is_lt (&op1, &op2);
|
return sim_fpu_is_lt (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
lesf (CGEN_FPU* fpu, SF x, SF y)
|
lesf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
return sim_fpu_is_le (&op1, &op2);
|
return sim_fpu_is_le (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
gtsf (CGEN_FPU* fpu, SF x, SF y)
|
gtsf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
return sim_fpu_is_gt (&op1, &op2);
|
return sim_fpu_is_gt (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
gesf (CGEN_FPU* fpu, SF x, SF y)
|
gesf (CGEN_FPU* fpu, SF x, SF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op2, y);
|
sim_fpu_32to (&op2, y);
|
return sim_fpu_is_ge (&op1, &op2);
|
return sim_fpu_is_ge (&op1, &op2);
|
}
|
}
|
|
|
static DF
|
static DF
|
fextsfdf (CGEN_FPU* fpu, SF x)
|
fextsfdf (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
unsigned64 res;
|
unsigned64 res;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_to64 (&res, &op1);
|
sim_fpu_to64 (&res, &op1);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
ftruncdfsf (CGEN_FPU* fpu, DF x)
|
ftruncdfsf (CGEN_FPU* fpu, DF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
unsigned32 res;
|
unsigned32 res;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_to32 (&res, &op1);
|
sim_fpu_to32 (&res, &op1);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
floatsisf (CGEN_FPU* fpu, SI x)
|
floatsisf (CGEN_FPU* fpu, SI x)
|
{
|
{
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
|
|
sim_fpu_i32to (&ans, x, sim_fpu_round_near);
|
sim_fpu_i32to (&ans, x, sim_fpu_round_near);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
floatsidf (CGEN_FPU* fpu, SI x)
|
floatsidf (CGEN_FPU* fpu, SI x)
|
{
|
{
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
|
|
sim_fpu_i32to (&ans, x, sim_fpu_round_near);
|
sim_fpu_i32to (&ans, x, sim_fpu_round_near);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
return res;
|
return res;
|
}
|
}
|
|
|
static SF
|
static SF
|
ufloatsisf (CGEN_FPU* fpu, USI x)
|
ufloatsisf (CGEN_FPU* fpu, USI x)
|
{
|
{
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned32 res;
|
unsigned32 res;
|
|
|
sim_fpu_u32to (&ans, x, sim_fpu_round_near);
|
sim_fpu_u32to (&ans, x, sim_fpu_round_near);
|
sim_fpu_to32 (&res, &ans);
|
sim_fpu_to32 (&res, &ans);
|
return res;
|
return res;
|
}
|
}
|
|
|
static SI
|
static SI
|
fixsfsi (CGEN_FPU* fpu, SF x)
|
fixsfsi (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
unsigned32 res;
|
unsigned32 res;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
|
sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
|
return res;
|
return res;
|
}
|
}
|
|
|
static SI
|
static SI
|
fixdfsi (CGEN_FPU* fpu, DF x)
|
fixdfsi (CGEN_FPU* fpu, DF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
unsigned32 res;
|
unsigned32 res;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
|
sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
|
return res;
|
return res;
|
}
|
}
|
|
|
static USI
|
static USI
|
ufixsfsi (CGEN_FPU* fpu, SF x)
|
ufixsfsi (CGEN_FPU* fpu, SF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
unsigned32 res;
|
unsigned32 res;
|
|
|
sim_fpu_32to (&op1, x);
|
sim_fpu_32to (&op1, x);
|
sim_fpu_to32u (&res, &op1, sim_fpu_round_near);
|
sim_fpu_to32u (&res, &op1, sim_fpu_round_near);
|
return res;
|
return res;
|
}
|
}
|
|
|
/* DF mode support */
|
/* DF mode support */
|
|
|
static DF
|
static DF
|
adddf (CGEN_FPU* fpu, DF x, DF y)
|
adddf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
status = sim_fpu_add (&ans, &op1, &op2);
|
status = sim_fpu_add (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
subdf (CGEN_FPU* fpu, DF x, DF y)
|
subdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
status = sim_fpu_sub (&ans, &op1, &op2);
|
status = sim_fpu_sub (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
muldf (CGEN_FPU* fpu, DF x, DF y)
|
muldf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
status = sim_fpu_mul (&ans, &op1, &op2);
|
status = sim_fpu_mul (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
divdf (CGEN_FPU* fpu, DF x, DF y)
|
divdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
status = sim_fpu_div (&ans, &op1, &op2);
|
status = sim_fpu_div (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
negdf (CGEN_FPU* fpu, DF x)
|
negdf (CGEN_FPU* fpu, DF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
status = sim_fpu_neg (&ans, &op1);
|
status = sim_fpu_neg (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
absdf (CGEN_FPU* fpu, DF x)
|
absdf (CGEN_FPU* fpu, DF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
status = sim_fpu_abs (&ans, &op1);
|
status = sim_fpu_abs (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
sqrtdf (CGEN_FPU* fpu, DF x)
|
sqrtdf (CGEN_FPU* fpu, DF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
status = sim_fpu_sqrt (&ans, &op1);
|
status = sim_fpu_sqrt (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
invdf (CGEN_FPU* fpu, DF x)
|
invdf (CGEN_FPU* fpu, DF x)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
status = sim_fpu_inv (&ans, &op1);
|
status = sim_fpu_inv (&ans, &op1);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
mindf (CGEN_FPU* fpu, DF x, DF y)
|
mindf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
status = sim_fpu_min (&ans, &op1, &op2);
|
status = sim_fpu_min (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static DF
|
static DF
|
maxdf (CGEN_FPU* fpu, DF x, DF y)
|
maxdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
sim_fpu ans;
|
sim_fpu ans;
|
unsigned64 res;
|
unsigned64 res;
|
sim_fpu_status status;
|
sim_fpu_status status;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
status = sim_fpu_max (&ans, &op1, &op2);
|
status = sim_fpu_max (&ans, &op1, &op2);
|
if (status != 0)
|
if (status != 0)
|
(*fpu->ops->error) (fpu, status);
|
(*fpu->ops->error) (fpu, status);
|
sim_fpu_to64 (&res, &ans);
|
sim_fpu_to64 (&res, &ans);
|
|
|
return res;
|
return res;
|
}
|
}
|
|
|
static CGEN_FP_CMP
|
static CGEN_FP_CMP
|
cmpdf (CGEN_FPU* fpu, DF x, DF y)
|
cmpdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
|
|
if (sim_fpu_is_nan (&op1)
|
if (sim_fpu_is_nan (&op1)
|
|| sim_fpu_is_nan (&op2))
|
|| sim_fpu_is_nan (&op2))
|
return FP_CMP_NAN;
|
return FP_CMP_NAN;
|
|
|
if (x < y)
|
if (x < y)
|
return FP_CMP_LT;
|
return FP_CMP_LT;
|
if (x > y)
|
if (x > y)
|
return FP_CMP_GT;
|
return FP_CMP_GT;
|
return FP_CMP_EQ;
|
return FP_CMP_EQ;
|
}
|
}
|
|
|
static int
|
static int
|
eqdf (CGEN_FPU* fpu, DF x, DF y)
|
eqdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
return sim_fpu_is_eq (&op1, &op2);
|
return sim_fpu_is_eq (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
nedf (CGEN_FPU* fpu, DF x, DF y)
|
nedf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
return sim_fpu_is_ne (&op1, &op2);
|
return sim_fpu_is_ne (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
ltdf (CGEN_FPU* fpu, DF x, DF y)
|
ltdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
return sim_fpu_is_lt (&op1, &op2);
|
return sim_fpu_is_lt (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
ledf (CGEN_FPU* fpu, DF x, DF y)
|
ledf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
return sim_fpu_is_le (&op1, &op2);
|
return sim_fpu_is_le (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
gtdf (CGEN_FPU* fpu, DF x, DF y)
|
gtdf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
return sim_fpu_is_gt (&op1, &op2);
|
return sim_fpu_is_gt (&op1, &op2);
|
}
|
}
|
|
|
static int
|
static int
|
gedf (CGEN_FPU* fpu, DF x, DF y)
|
gedf (CGEN_FPU* fpu, DF x, DF y)
|
{
|
{
|
sim_fpu op1;
|
sim_fpu op1;
|
sim_fpu op2;
|
sim_fpu op2;
|
|
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op1, x);
|
sim_fpu_64to (&op2, y);
|
sim_fpu_64to (&op2, y);
|
return sim_fpu_is_ge (&op1, &op2);
|
return sim_fpu_is_ge (&op1, &op2);
|
}
|
}
|
|
|
/* Initialize FP_OPS to use accurate library. */
|
/* Initialize FP_OPS to use accurate library. */
|
|
|
void
|
void
|
cgen_init_accurate_fpu (SIM_CPU* cpu, CGEN_FPU* fpu, CGEN_FPU_ERROR_FN* error)
|
cgen_init_accurate_fpu (SIM_CPU* cpu, CGEN_FPU* fpu, CGEN_FPU_ERROR_FN* error)
|
{
|
{
|
CGEN_FP_OPS* o;
|
CGEN_FP_OPS* o;
|
|
|
fpu->owner = cpu;
|
fpu->owner = cpu;
|
/* ??? small memory leak, not freed by sim_close */
|
/* ??? small memory leak, not freed by sim_close */
|
fpu->ops = (CGEN_FP_OPS*) xmalloc (sizeof (CGEN_FP_OPS));
|
fpu->ops = (CGEN_FP_OPS*) xmalloc (sizeof (CGEN_FP_OPS));
|
|
|
o = fpu->ops;
|
o = fpu->ops;
|
memset (o, 0, sizeof (*o));
|
memset (o, 0, sizeof (*o));
|
|
|
o->error = error;
|
o->error = error;
|
|
|
o->addsf = addsf;
|
o->addsf = addsf;
|
o->subsf = subsf;
|
o->subsf = subsf;
|
o->mulsf = mulsf;
|
o->mulsf = mulsf;
|
o->divsf = divsf;
|
o->divsf = divsf;
|
o->negsf = negsf;
|
o->negsf = negsf;
|
o->abssf = abssf;
|
o->abssf = abssf;
|
o->sqrtsf = sqrtsf;
|
o->sqrtsf = sqrtsf;
|
o->invsf = invsf;
|
o->invsf = invsf;
|
o->minsf = minsf;
|
o->minsf = minsf;
|
o->maxsf = maxsf;
|
o->maxsf = maxsf;
|
o->cmpsf = cmpsf;
|
o->cmpsf = cmpsf;
|
o->eqsf = eqsf;
|
o->eqsf = eqsf;
|
o->nesf = nesf;
|
o->nesf = nesf;
|
o->ltsf = ltsf;
|
o->ltsf = ltsf;
|
o->lesf = lesf;
|
o->lesf = lesf;
|
o->gtsf = gtsf;
|
o->gtsf = gtsf;
|
o->gesf = gesf;
|
o->gesf = gesf;
|
|
|
o->adddf = adddf;
|
o->adddf = adddf;
|
o->subdf = subdf;
|
o->subdf = subdf;
|
o->muldf = muldf;
|
o->muldf = muldf;
|
o->divdf = divdf;
|
o->divdf = divdf;
|
o->negdf = negdf;
|
o->negdf = negdf;
|
o->absdf = absdf;
|
o->absdf = absdf;
|
o->sqrtdf = sqrtdf;
|
o->sqrtdf = sqrtdf;
|
o->invdf = invdf;
|
o->invdf = invdf;
|
o->mindf = mindf;
|
o->mindf = mindf;
|
o->maxdf = maxdf;
|
o->maxdf = maxdf;
|
o->cmpdf = cmpdf;
|
o->cmpdf = cmpdf;
|
o->eqdf = eqdf;
|
o->eqdf = eqdf;
|
o->nedf = nedf;
|
o->nedf = nedf;
|
o->ltdf = ltdf;
|
o->ltdf = ltdf;
|
o->ledf = ledf;
|
o->ledf = ledf;
|
o->gtdf = gtdf;
|
o->gtdf = gtdf;
|
o->gedf = gedf;
|
o->gedf = gedf;
|
o->fextsfdf = fextsfdf;
|
o->fextsfdf = fextsfdf;
|
o->ftruncdfsf = ftruncdfsf;
|
o->ftruncdfsf = ftruncdfsf;
|
o->floatsisf = floatsisf;
|
o->floatsisf = floatsisf;
|
o->floatsidf = floatsidf;
|
o->floatsidf = floatsidf;
|
o->ufloatsisf = ufloatsisf;
|
o->ufloatsisf = ufloatsisf;
|
o->fixsfsi = fixsfsi;
|
o->fixsfsi = fixsfsi;
|
o->fixdfsi = fixdfsi;
|
o->fixdfsi = fixdfsi;
|
o->ufixsfsi = ufixsfsi;
|
o->ufixsfsi = ufixsfsi;
|
}
|
}
|
|
|