#include "../tahoe/psl.h"
#include "../tahoe/reg.h"
#include "../tahoe/pte.h"
#include "../tahoe/mtpr.h"
#include "../tahoemath/Kfp.h"
* Floating point emulation support.
extern float Kcvtlf(), Kaddf(), Ksubf(), Kmulf(), Kdivf();
extern double Kcvtld(), Kaddd(), Ksubd(), Kmuld(), Kdivd();
extern float Ksinf(), Kcosf(), Katanf(), Klogf(), Ksqrtf(), Kexpf();
#define OP(dop) ((dop) &~ 01) /* precision-less version of opcode */
#define isdouble(op) ((op) & 01) /* is opcode double or float */
int fpe_op
; /* base opcode emulating */
float (*fpe_ffunc
)(); /* float version of op */
double (*fpe_dfunc
)(); /* double version of op */
{ OP(CVLD
), Kcvtlf
, Kcvtld
},
{ OP(ADDD
), Kaddf
, Kaddd
},
{ OP(SUBD
), Ksubf
, Ksubd
},
{ OP(MULD
), Kmulf
, Kmuld
},
{ OP(DIVD
), Kdivf
, Kdivd
},
#define NFPETAB (sizeof (fpetab) / sizeof (fpetab[0]))
* Emulate the FP opcode. Update psl as necessary.
* If OK, set opcode to 0, else to the FP exception #.
* Not all parameter longwords are relevant, depends on opcode.
* The entry mask is set by locore.s so ALL registers are saved.
* This enables FP opcodes to change user registers on return.
/* WARNING!!!! THIS CODE MUST NOT PRODUCE ANY FLOATING POINT EXCEPTIONS */
fpemulate(hfsreg
, acc_most
, acc_least
, dbl
, op_most
, op_least
, opcode
, pc
, psl
)
int r0
, r1
; /* must reserve space */
register int *locr0
= ((int *)&psl
)-PS
;
register struct fpetab
*fp
;
int hfs
= 0; /* returned data about exceptions */
int type
; /* opcode type, FLOAT or DOUBLE */
union { float ff
; int fi
; } f_res
;
union { double dd
; int di
[2]; } d_res
;
r0
= 0; r0
= r0
; r1
= 0; r1
= r1
;
type
= isdouble(opcode
) ? DOUBLE
: FLOAT
;
for (fp
= fpetab
; fp
< &fpetab
[NFPETAB
]; fp
++)
if ((opcode
& 0xfe) == fp
->fpe_op
)
if (fp
>= &fpetab
[NFPETAB
]) {
opcode
= DIV0_EXC
; /* generate SIGILL - XXX */
d_res
.dd
= (*fp
->fpe_dfunc
)(acc_most
, acc_least
, op_most
,
if (d_res
.di
[0] == 0 && d_res
.di
[1] == 0)
f_res
.ff
= (*fp
->fpe_ffunc
)(acc_most
, acc_least
, op_most
,
locr0
[PS
] |= PSL_V
; /* turn on overflow bit */
if (locr0
[PS
] & PSL_IV
) { /* overflow enabled? */
u
.u_error
= (hfs
& HFS_DOM
) ? EDOM
: ERANGE
;
} else if (hfs
& HFS_UNDF
) {
if (locr0
[PS
] & PSL_FU
) { /* underflow enabled? */
u
.u_error
= (hfs
& HFS_DOM
) ? EDOM
: ERANGE
;
} else if (hfs
& HFS_DIVZ
) {
} else if (hfs
& HFS_DOM
)
else if (hfs
& HFS_RANGE
)
if (hfs
& (HFS_OVF
|HFS_UNDF
)) {
mvtodacc(d_res
.di
[0], d_res
.di
[1], &acc_most
);
if (hfs
& (HFS_OVF
|HFS_UNDF
)) {
mvtofacc(f_res
.ff
, &acc_most
);