You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

799 lines
13 KiB
C

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/* 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
*/
/* This must come before any other includes. */
#include "defs.h"
#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;
uint32_t 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;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
sim_fpu_32to (&op2, y);
status = sim_fpu_sub (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
sim_fpu_32to (&op2, y);
status = sim_fpu_mul (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
sim_fpu_32to (&op2, y);
status = sim_fpu_div (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to32 (&res, &ans);
return res;
}
static SF
remsf (CGEN_FPU* fpu, SF x, SF y)
{
sim_fpu op1;
sim_fpu op2;
sim_fpu ans;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
sim_fpu_32to (&op2, y);
status = sim_fpu_rem (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to32 (&res, &ans);
return res;
}
static SF
negsf (CGEN_FPU* fpu, SF x)
{
sim_fpu op1;
sim_fpu ans;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
status = sim_fpu_neg (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to32 (&res, &ans);
return res;
}
static SF
abssf (CGEN_FPU* fpu, SF x)
{
sim_fpu op1;
sim_fpu ans;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
status = sim_fpu_abs (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to32 (&res, &ans);
return res;
}
static SF
sqrtsf (CGEN_FPU* fpu, SF x)
{
sim_fpu op1;
sim_fpu ans;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
status = sim_fpu_sqrt (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to32 (&res, &ans);
return res;
}
static SF
invsf (CGEN_FPU* fpu, SF x)
{
sim_fpu op1;
sim_fpu ans;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
status = sim_fpu_inv (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
sim_fpu_32to (&op2, y);
status = sim_fpu_min (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint32_t res;
sim_fpu_status status;
sim_fpu_32to (&op1, x);
sim_fpu_32to (&op2, y);
status = sim_fpu_max (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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 int
unorderedsf (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_nan (&op1) || sim_fpu_is_nan (&op2);
}
static DF
fextsfdf (CGEN_FPU* fpu, int how UNUSED, SF x)
{
sim_fpu op1;
uint64_t res;
sim_fpu_32to (&op1, x);
sim_fpu_to64 (&res, &op1);
return res;
}
static SF
ftruncdfsf (CGEN_FPU* fpu, int how UNUSED, DF x)
{
sim_fpu op1;
uint32_t res;
sim_fpu_64to (&op1, x);
sim_fpu_to32 (&res, &op1);
return res;
}
static SF
floatsisf (CGEN_FPU* fpu, int how UNUSED, SI x)
{
sim_fpu ans;
uint32_t res;
sim_fpu_i32to (&ans, x, sim_fpu_round_near);
sim_fpu_to32 (&res, &ans);
return res;
}
static DF
floatsidf (CGEN_FPU* fpu, int how UNUSED, SI x)
{
sim_fpu ans;
uint64_t res;
sim_fpu_i32to (&ans, x, sim_fpu_round_near);
sim_fpu_to64 (&res, &ans);
return res;
}
static DF
floatdidf (CGEN_FPU* fpu, int how UNUSED, DI x)
{
sim_fpu ans;
uint64_t res;
sim_fpu_i64to (&ans, x, sim_fpu_round_near);
sim_fpu_to64 (&res, &ans);
return res;
}
static SF
ufloatsisf (CGEN_FPU* fpu, int how UNUSED, USI x)
{
sim_fpu ans;
uint32_t res;
sim_fpu_u32to (&ans, x, sim_fpu_round_near);
sim_fpu_to32 (&res, &ans);
return res;
}
static SI
fixsfsi (CGEN_FPU* fpu, int how UNUSED, SF x)
{
sim_fpu op1;
int32_t res;
sim_fpu_32to (&op1, x);
sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
return res;
}
static SI
fixdfsi (CGEN_FPU* fpu, int how UNUSED, DF x)
{
sim_fpu op1;
int32_t res;
sim_fpu_64to (&op1, x);
sim_fpu_to32i (&res, &op1, sim_fpu_round_near);
return res;
}
static DI
fixdfdi (CGEN_FPU* fpu, int how UNUSED, DF x)
{
sim_fpu op1;
int64_t res;
sim_fpu_64to (&op1, x);
sim_fpu_to64i (&res, &op1, sim_fpu_round_near);
return res;
}
static USI
ufixsfsi (CGEN_FPU* fpu, int how UNUSED, SF x)
{
sim_fpu op1;
uint32_t 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;
uint64_t 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;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
sim_fpu_64to (&op2, y);
status = sim_fpu_sub (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
sim_fpu_64to (&op2, y);
status = sim_fpu_mul (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
sim_fpu_64to (&op2, y);
status = sim_fpu_div (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to64 (&res, &ans);
return res;
}
static DF
remdf (CGEN_FPU* fpu, DF x, DF y)
{
sim_fpu op1;
sim_fpu op2;
sim_fpu ans;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
sim_fpu_64to (&op2, y);
status = sim_fpu_rem (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to64(&res, &ans);
return res;
}
static DF
negdf (CGEN_FPU* fpu, DF x)
{
sim_fpu op1;
sim_fpu ans;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
status = sim_fpu_neg (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to64 (&res, &ans);
return res;
}
static DF
absdf (CGEN_FPU* fpu, DF x)
{
sim_fpu op1;
sim_fpu ans;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
status = sim_fpu_abs (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to64 (&res, &ans);
return res;
}
static DF
sqrtdf (CGEN_FPU* fpu, DF x)
{
sim_fpu op1;
sim_fpu ans;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
status = sim_fpu_sqrt (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
sim_fpu_to64 (&res, &ans);
return res;
}
static DF
invdf (CGEN_FPU* fpu, DF x)
{
sim_fpu op1;
sim_fpu ans;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
status = sim_fpu_inv (&ans, &op1);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
sim_fpu_64to (&op2, y);
status = sim_fpu_min (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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;
uint64_t res;
sim_fpu_status status;
sim_fpu_64to (&op1, x);
sim_fpu_64to (&op2, y);
status = sim_fpu_max (&ans, &op1, &op2);
if (status != 0)
(*fpu->ops->error) (fpu, status);
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);
}
static int
unordereddf (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_nan (&op1) || sim_fpu_is_nan (&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->remsf = remsf;
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->unorderedsf = unorderedsf;
o->adddf = adddf;
o->subdf = subdf;
o->muldf = muldf;
o->divdf = divdf;
o->remdf = remdf;
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->unordereddf = unordereddf;
o->fextsfdf = fextsfdf;
o->ftruncdfsf = ftruncdfsf;
o->floatsisf = floatsisf;
o->floatsidf = floatsidf;
o->floatdidf = floatdidf;
o->ufloatsisf = ufloatsisf;
o->fixsfsi = fixsfsi;
o->fixdfsi = fixdfsi;
o->fixdfdi = fixdfdi;
o->ufixsfsi = ufixsfsi;
}