/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)fpu.c 8.1 (Berkeley) 6/11/93
*/
/*
* fpu_execute returns the following error numbers (0 = no error):
*/
#define FPE 1 /* take a floating point exception */
#define NOTFPU 2 /* not an FPU instruction */
/*
* Translate current exceptions into `first' exception. The
* bits go the wrong way for ffs() (0x10 is most important, etc).
* There are only 5, so do it the obvious way.
*/
#define X1(x) x
#define X2(x) x,x
#define X4(x) x,x,x,x
#define X8(x) X4(x),X4(x)
#define X16(x) X8(x),X8(x)
/* Note: SVR4(Solaris) FPE_* codes happen to be compatible with ours */
/*
* The FPU gave us an exception. Clean up the mess. Note that the
* fp queue can only have FPops in it, never load/store FP registers
* nor FBfcc instructions. Experiments with `crashme' prove that
* unknown FPops do enter the queue, however.
*/
int
fpu_cleanup(
struct lwp *l,
#ifndef SUN4U
struct fpstate *fs
#else /* SUN4U */
struct fpstate64 *fs
#endif /* SUN4U */
)
{
int i, fsr = fs->fs_fsr, error;
struct proc *p = l->l_proc;
union instr instr;
struct fpemu fe;
u_char *fpu_codes;
int code = 0;
int ret;
const struct emul *sunos_emul;
#ifdef notyet
/*
* If we have no FPU at all (are there any machines like this out
* there!?) we have to emulate each instruction, and we need a pointer
* to the trapframe so that we can step over them and do FBfcc's.
* We know the `queue' is empty, though; we just want to emulate
* the instruction at tf->tf_pc.
*/
fpu_emulate(l, tf, fs)
struct lwp *l;
struct trapframe *tf;
#ifndef SUN4U
struct fpstate *fs;
#else /* SUN4U */
struct fpstate64 *fs;
#endif /* SUN4U */
{
do {
fetch instr from pc
decode
if (integer instr) {
struct pcb *pcb = lwp_getpcb(l);
/*
* We do this here, rather than earlier, to avoid
* losing even more badly than usual.
*/
if (pcb->pcb_uw) {
write_user_windows();
if (rwindow_save(l))
sigexit(l, SIGILL);
}
if (loadstore) {
do_it;
pc = npc, npc += 4
} else if (fbfcc) {
do_annul_stuff;
} else
return;
} else if (fpu instr) {
fe.fe_fsr = fs->fs_fsr &= ~FSR_CX;
error = fpu_execute(&fe, fs, instr);
switch (error) {
etc;
}
} else
return;
if (want to reschedule)
return;
} while (error == 0);
}
#endif
/*
* Execute an FPU instruction (one that runs entirely in the FPU; not
* FBfcc or STF, for instance). On return, fe->fe_fs->fs_fsr will be
* modified to reflect the setting the hardware would have left.
*
* Note that we do not catch all illegal opcodes, so you can, for instance,
* multiply two integers this way.
*/
int
fpu_execute(struct fpemu *fe, union instr instr)
{
struct fpn *fp;
#ifndef SUN4U
int opf, rs1, rs2, rd, type, mask, fsr, cx;
struct fpstate *fs;
#else /* SUN4U */
int opf, rs1, rs2, rd, type, mask, fsr, cx, i, cond;
struct fpstate64 *fs;
#endif /* SUN4U */
u_int space[4];
/*
* `Decode' and execute instruction. Start with no exceptions.
* The type of any i_opf opcode is in the bottom two bits, so we
* squish them out here.
*/
opf = instr.i_opf.i_opf;
/*
* The low two bits of the opf field for floating point insns usually
* correspond to the operation width:
*
* 0: Invalid
* 1: Single precision float
* 2: Double precision float
* 3: Quad precision float
*
* The exceptions are the integer to float conversion instructions.
*
* For double and quad precision, the low bit if the rs or rd field
* is actually the high bit of the register number.
*/