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