2019-05-20 14:19:02 +07:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2005-04-17 05:20:36 +07:00
|
|
|
/*
|
|
|
|
NetWinder Floating Point Emulator
|
|
|
|
(c) Rebel.COM, 1998,1999
|
|
|
|
(c) Philip Blundell, 2001
|
|
|
|
|
|
|
|
Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "fpa11.h"
|
|
|
|
#include "fpopcode.h"
|
|
|
|
|
|
|
|
#include "fpmodule.h"
|
|
|
|
#include "fpmodule.inl"
|
|
|
|
|
|
|
|
#include <linux/compiler.h>
|
|
|
|
#include <linux/string.h>
|
|
|
|
|
|
|
|
/* Reset the FPA11 chip. Called to initialize and reset the emulator. */
|
|
|
|
static void resetFPA11(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
FPA11 *fpa11 = GET_FPA11();
|
|
|
|
|
|
|
|
/* initialize the register type array */
|
|
|
|
for (i = 0; i <= 7; i++) {
|
|
|
|
fpa11->fType[i] = typeNone;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
|
|
|
|
fpa11->fpsr = FP_EMULATOR | BIT_AC;
|
|
|
|
}
|
|
|
|
|
2005-08-04 01:49:17 +07:00
|
|
|
int8 SetRoundingMode(const unsigned int opcode)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
switch (opcode & MASK_ROUNDING_MODE) {
|
|
|
|
default:
|
|
|
|
case ROUND_TO_NEAREST:
|
2005-08-04 01:49:17 +07:00
|
|
|
return float_round_nearest_even;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
case ROUND_TO_PLUS_INFINITY:
|
2005-08-04 01:49:17 +07:00
|
|
|
return float_round_up;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
case ROUND_TO_MINUS_INFINITY:
|
2005-08-04 01:49:17 +07:00
|
|
|
return float_round_down;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
case ROUND_TO_ZERO:
|
2005-08-04 01:49:17 +07:00
|
|
|
return float_round_to_zero;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-08-04 01:49:17 +07:00
|
|
|
int8 SetRoundingPrecision(const unsigned int opcode)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
#ifdef CONFIG_FPE_NWFPE_XP
|
|
|
|
switch (opcode & MASK_ROUNDING_PRECISION) {
|
|
|
|
case ROUND_SINGLE:
|
2005-08-04 01:49:17 +07:00
|
|
|
return 32;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
case ROUND_DOUBLE:
|
2005-08-04 01:49:17 +07:00
|
|
|
return 64;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
case ROUND_EXTENDED:
|
2005-08-04 01:49:17 +07:00
|
|
|
return 80;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
default:
|
2005-08-04 01:49:17 +07:00
|
|
|
return 80;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
#endif
|
2005-08-04 01:49:17 +07:00
|
|
|
return 80;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
void nwfpe_init_fpa(union fp_state *fp)
|
|
|
|
{
|
|
|
|
FPA11 *fpa11 = (FPA11 *)fp;
|
|
|
|
#ifdef NWFPE_DEBUG
|
|
|
|
printk("NWFPE: setting up state.\n");
|
|
|
|
#endif
|
|
|
|
memset(fpa11, 0, sizeof(FPA11));
|
|
|
|
resetFPA11();
|
|
|
|
fpa11->initflag = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Emulate the instruction in the opcode. */
|
|
|
|
unsigned int EmulateAll(unsigned int opcode)
|
|
|
|
{
|
|
|
|
unsigned int code;
|
|
|
|
|
|
|
|
#ifdef NWFPE_DEBUG
|
|
|
|
printk("NWFPE: emulating opcode %08x\n", opcode);
|
|
|
|
#endif
|
|
|
|
code = opcode & 0x00000f00;
|
|
|
|
if (code == 0x00000100 || code == 0x00000200) {
|
|
|
|
/* For coprocessor 1 or 2 (FPA11) */
|
|
|
|
code = opcode & 0x0e000000;
|
|
|
|
if (code == 0x0e000000) {
|
|
|
|
if (opcode & 0x00000010) {
|
|
|
|
/* Emulate conversion opcodes. */
|
|
|
|
/* Emulate register transfer opcodes. */
|
|
|
|
/* Emulate comparison opcodes. */
|
|
|
|
return EmulateCPRT(opcode);
|
|
|
|
} else {
|
|
|
|
/* Emulate monadic arithmetic opcodes. */
|
|
|
|
/* Emulate dyadic arithmetic opcodes. */
|
|
|
|
return EmulateCPDO(opcode);
|
|
|
|
}
|
|
|
|
} else if (code == 0x0c000000) {
|
|
|
|
/* Emulate load/store opcodes. */
|
|
|
|
/* Emulate load/store multiple opcodes. */
|
|
|
|
return EmulateCPDT(opcode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Invalid instruction detected. Return FALSE. */
|
|
|
|
return 0;
|
|
|
|
}
|