xref: /linux/arch/arm/nwfpe/fpa11.c (revision 37744feebc086908fd89760650f458ab19071750)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3     NetWinder Floating Point Emulator
4     (c) Rebel.COM, 1998,1999
5     (c) Philip Blundell, 2001
6 
7     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
8 
9 */
10 
11 #include "fpa11.h"
12 #include "fpopcode.h"
13 
14 #include "fpmodule.h"
15 #include "fpmodule.inl"
16 
17 #include <linux/compiler.h>
18 #include <linux/string.h>
19 
20 /* Reset the FPA11 chip.  Called to initialize and reset the emulator. */
21 static void resetFPA11(void)
22 {
23 	int i;
24 	FPA11 *fpa11 = GET_FPA11();
25 
26 	/* initialize the register type array */
27 	for (i = 0; i <= 7; i++) {
28 		fpa11->fType[i] = typeNone;
29 	}
30 
31 	/* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
32 	fpa11->fpsr = FP_EMULATOR | BIT_AC;
33 }
34 
35 int8 SetRoundingMode(const unsigned int opcode)
36 {
37 	switch (opcode & MASK_ROUNDING_MODE) {
38 	default:
39 	case ROUND_TO_NEAREST:
40 		return float_round_nearest_even;
41 
42 	case ROUND_TO_PLUS_INFINITY:
43 		return float_round_up;
44 
45 	case ROUND_TO_MINUS_INFINITY:
46 		return float_round_down;
47 
48 	case ROUND_TO_ZERO:
49 		return float_round_to_zero;
50 	}
51 }
52 
53 int8 SetRoundingPrecision(const unsigned int opcode)
54 {
55 #ifdef CONFIG_FPE_NWFPE_XP
56 	switch (opcode & MASK_ROUNDING_PRECISION) {
57 	case ROUND_SINGLE:
58 		return 32;
59 
60 	case ROUND_DOUBLE:
61 		return 64;
62 
63 	case ROUND_EXTENDED:
64 		return 80;
65 
66 	default:
67 		return 80;
68 	}
69 #endif
70 	return 80;
71 }
72 
73 void nwfpe_init_fpa(union fp_state *fp)
74 {
75 	FPA11 *fpa11 = (FPA11 *)fp;
76 #ifdef NWFPE_DEBUG
77 	printk("NWFPE: setting up state.\n");
78 #endif
79  	memset(fpa11, 0, sizeof(FPA11));
80 	resetFPA11();
81 	fpa11->initflag = 1;
82 }
83 
84 /* Emulate the instruction in the opcode. */
85 unsigned int EmulateAll(unsigned int opcode)
86 {
87 	unsigned int code;
88 
89 #ifdef NWFPE_DEBUG
90 	printk("NWFPE: emulating opcode %08x\n", opcode);
91 #endif
92 	code = opcode & 0x00000f00;
93 	if (code == 0x00000100 || code == 0x00000200) {
94 		/* For coprocessor 1 or 2 (FPA11) */
95 		code = opcode & 0x0e000000;
96 		if (code == 0x0e000000) {
97 			if (opcode & 0x00000010) {
98 				/* Emulate conversion opcodes. */
99 				/* Emulate register transfer opcodes. */
100 				/* Emulate comparison opcodes. */
101 				return EmulateCPRT(opcode);
102 			} else {
103 				/* Emulate monadic arithmetic opcodes. */
104 				/* Emulate dyadic arithmetic opcodes. */
105 				return EmulateCPDO(opcode);
106 			}
107 		} else if (code == 0x0c000000) {
108 			/* Emulate load/store opcodes. */
109 			/* Emulate load/store multiple opcodes. */
110 			return EmulateCPDT(opcode);
111 		}
112 	}
113 
114 	/* Invalid instruction detected.  Return FALSE. */
115 	return 0;
116 }
117