xref: /openbmc/linux/arch/arm/nwfpe/fpa11.c (revision 74ba9207)
174ba9207SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds     NetWinder Floating Point Emulator
41da177e4SLinus Torvalds     (c) Rebel.COM, 1998,1999
51da177e4SLinus Torvalds     (c) Philip Blundell, 2001
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds */
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds #include "fpa11.h"
121da177e4SLinus Torvalds #include "fpopcode.h"
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include "fpmodule.h"
151da177e4SLinus Torvalds #include "fpmodule.inl"
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/compiler.h>
181da177e4SLinus Torvalds #include <linux/string.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
resetFPA11(void)211da177e4SLinus Torvalds static void resetFPA11(void)
221da177e4SLinus Torvalds {
231da177e4SLinus Torvalds 	int i;
241da177e4SLinus Torvalds 	FPA11 *fpa11 = GET_FPA11();
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds 	/* initialize the register type array */
271da177e4SLinus Torvalds 	for (i = 0; i <= 7; i++) {
281da177e4SLinus Torvalds 		fpa11->fType[i] = typeNone;
291da177e4SLinus Torvalds 	}
301da177e4SLinus Torvalds 
311da177e4SLinus Torvalds 	/* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
321da177e4SLinus Torvalds 	fpa11->fpsr = FP_EMULATOR | BIT_AC;
331da177e4SLinus Torvalds }
341da177e4SLinus Torvalds 
SetRoundingMode(const unsigned int opcode)35f148af25SRichard Purdie int8 SetRoundingMode(const unsigned int opcode)
361da177e4SLinus Torvalds {
371da177e4SLinus Torvalds 	switch (opcode & MASK_ROUNDING_MODE) {
381da177e4SLinus Torvalds 	default:
391da177e4SLinus Torvalds 	case ROUND_TO_NEAREST:
40f148af25SRichard Purdie 		return float_round_nearest_even;
411da177e4SLinus Torvalds 
421da177e4SLinus Torvalds 	case ROUND_TO_PLUS_INFINITY:
43f148af25SRichard Purdie 		return float_round_up;
441da177e4SLinus Torvalds 
451da177e4SLinus Torvalds 	case ROUND_TO_MINUS_INFINITY:
46f148af25SRichard Purdie 		return float_round_down;
471da177e4SLinus Torvalds 
481da177e4SLinus Torvalds 	case ROUND_TO_ZERO:
49f148af25SRichard Purdie 		return float_round_to_zero;
501da177e4SLinus Torvalds 	}
511da177e4SLinus Torvalds }
521da177e4SLinus Torvalds 
SetRoundingPrecision(const unsigned int opcode)53f148af25SRichard Purdie int8 SetRoundingPrecision(const unsigned int opcode)
541da177e4SLinus Torvalds {
551da177e4SLinus Torvalds #ifdef CONFIG_FPE_NWFPE_XP
561da177e4SLinus Torvalds 	switch (opcode & MASK_ROUNDING_PRECISION) {
571da177e4SLinus Torvalds 	case ROUND_SINGLE:
58f148af25SRichard Purdie 		return 32;
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	case ROUND_DOUBLE:
61f148af25SRichard Purdie 		return 64;
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds 	case ROUND_EXTENDED:
64f148af25SRichard Purdie 		return 80;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds 	default:
67f148af25SRichard Purdie 		return 80;
681da177e4SLinus Torvalds 	}
691da177e4SLinus Torvalds #endif
70f148af25SRichard Purdie 	return 80;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
nwfpe_init_fpa(union fp_state * fp)731da177e4SLinus Torvalds void nwfpe_init_fpa(union fp_state *fp)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds 	FPA11 *fpa11 = (FPA11 *)fp;
761da177e4SLinus Torvalds #ifdef NWFPE_DEBUG
771da177e4SLinus Torvalds 	printk("NWFPE: setting up state.\n");
781da177e4SLinus Torvalds #endif
791da177e4SLinus Torvalds  	memset(fpa11, 0, sizeof(FPA11));
801da177e4SLinus Torvalds 	resetFPA11();
811da177e4SLinus Torvalds 	fpa11->initflag = 1;
821da177e4SLinus Torvalds }
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds /* Emulate the instruction in the opcode. */
EmulateAll(unsigned int opcode)851da177e4SLinus Torvalds unsigned int EmulateAll(unsigned int opcode)
861da177e4SLinus Torvalds {
871da177e4SLinus Torvalds 	unsigned int code;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds #ifdef NWFPE_DEBUG
901da177e4SLinus Torvalds 	printk("NWFPE: emulating opcode %08x\n", opcode);
911da177e4SLinus Torvalds #endif
921da177e4SLinus Torvalds 	code = opcode & 0x00000f00;
931da177e4SLinus Torvalds 	if (code == 0x00000100 || code == 0x00000200) {
941da177e4SLinus Torvalds 		/* For coprocessor 1 or 2 (FPA11) */
951da177e4SLinus Torvalds 		code = opcode & 0x0e000000;
961da177e4SLinus Torvalds 		if (code == 0x0e000000) {
971da177e4SLinus Torvalds 			if (opcode & 0x00000010) {
981da177e4SLinus Torvalds 				/* Emulate conversion opcodes. */
991da177e4SLinus Torvalds 				/* Emulate register transfer opcodes. */
1001da177e4SLinus Torvalds 				/* Emulate comparison opcodes. */
1011da177e4SLinus Torvalds 				return EmulateCPRT(opcode);
1021da177e4SLinus Torvalds 			} else {
1031da177e4SLinus Torvalds 				/* Emulate monadic arithmetic opcodes. */
1041da177e4SLinus Torvalds 				/* Emulate dyadic arithmetic opcodes. */
1051da177e4SLinus Torvalds 				return EmulateCPDO(opcode);
1061da177e4SLinus Torvalds 			}
1071da177e4SLinus Torvalds 		} else if (code == 0x0c000000) {
1081da177e4SLinus Torvalds 			/* Emulate load/store opcodes. */
1091da177e4SLinus Torvalds 			/* Emulate load/store multiple opcodes. */
1101da177e4SLinus Torvalds 			return EmulateCPDT(opcode);
1111da177e4SLinus Torvalds 		}
1121da177e4SLinus Torvalds 	}
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 	/* Invalid instruction detected.  Return FALSE. */
1151da177e4SLinus Torvalds 	return 0;
1161da177e4SLinus Torvalds }
117