File: /usr/src/linux/arch/arm/nwfpe/fpa11.c
1 /*
2 NetWinder Floating Point Emulator
3 (c) Rebel.COM, 1998,1999
4
5 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include <asm/system.h>
23
24 #include "fpa11.h"
25 #include "fpopcode.h"
26
27 #include "fpmodule.h"
28 #include "fpmodule.inl"
29
30 /* forward declarations */
31 unsigned int EmulateCPDO(const unsigned int);
32 unsigned int EmulateCPDT(const unsigned int);
33 unsigned int EmulateCPRT(const unsigned int);
34
35 /* Reset the FPA11 chip. Called to initialize and reset the emulator. */
36 void resetFPA11(void)
37 {
38 int i;
39 FPA11 *fpa11 = GET_FPA11();
40
41 /* initialize the register type array */
42 for (i=0;i<=7;i++)
43 {
44 fpa11->fType[i] = typeNone;
45 }
46
47 /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */
48 fpa11->fpsr = FP_EMULATOR | BIT_AC;
49
50 /* FPCR: set SB, AB and DA bits, clear all others */
51 #if MAINTAIN_FPCR
52 fpa11->fpcr = MASK_RESET;
53 #endif
54 }
55
56 void SetRoundingMode(const unsigned int opcode)
57 {
58 #if MAINTAIN_FPCR
59 fpa11->fpcr &= ~MASK_ROUNDING_MODE;
60 #endif
61 switch (opcode & MASK_ROUNDING_MODE)
62 {
63 default:
64 case ROUND_TO_NEAREST:
65 float_rounding_mode = float_round_nearest_even;
66 #if MAINTAIN_FPCR
67 fpa11->fpcr |= ROUND_TO_NEAREST;
68 #endif
69 break;
70
71 case ROUND_TO_PLUS_INFINITY:
72 float_rounding_mode = float_round_up;
73 #if MAINTAIN_FPCR
74 fpa11->fpcr |= ROUND_TO_PLUS_INFINITY;
75 #endif
76 break;
77
78 case ROUND_TO_MINUS_INFINITY:
79 float_rounding_mode = float_round_down;
80 #if MAINTAIN_FPCR
81 fpa11->fpcr |= ROUND_TO_MINUS_INFINITY;
82 #endif
83 break;
84
85 case ROUND_TO_ZERO:
86 float_rounding_mode = float_round_to_zero;
87 #if MAINTAIN_FPCR
88 fpa11->fpcr |= ROUND_TO_ZERO;
89 #endif
90 break;
91 }
92 }
93
94 void SetRoundingPrecision(const unsigned int opcode)
95 {
96 #if MAINTAIN_FPCR
97 fpa11->fpcr &= ~MASK_ROUNDING_PRECISION;
98 #endif
99 switch (opcode & MASK_ROUNDING_PRECISION)
100 {
101 case ROUND_SINGLE:
102 floatx80_rounding_precision = 32;
103 #if MAINTAIN_FPCR
104 fpa11->fpcr |= ROUND_SINGLE;
105 #endif
106 break;
107
108 case ROUND_DOUBLE:
109 floatx80_rounding_precision = 64;
110 #if MAINTAIN_FPCR
111 fpa11->fpcr |= ROUND_DOUBLE;
112 #endif
113 break;
114
115 case ROUND_EXTENDED:
116 floatx80_rounding_precision = 80;
117 #if MAINTAIN_FPCR
118 fpa11->fpcr |= ROUND_EXTENDED;
119 #endif
120 break;
121
122 default: floatx80_rounding_precision = 80;
123 }
124 }
125
126 /* Emulate the instruction in the opcode. */
127 unsigned int EmulateAll(unsigned int opcode)
128 {
129 unsigned int nRc = 0;
130 unsigned long flags;
131 FPA11 *fpa11;
132 save_flags(flags); sti();
133
134 fpa11 = GET_FPA11();
135
136 if (fpa11->initflag == 0) /* good place for __builtin_expect */
137 {
138 resetFPA11();
139 SetRoundingMode(ROUND_TO_NEAREST);
140 SetRoundingPrecision(ROUND_EXTENDED);
141 fpa11->initflag = 1;
142 }
143
144 if (TEST_OPCODE(opcode,MASK_CPRT))
145 {
146 /* Emulate conversion opcodes. */
147 /* Emulate register transfer opcodes. */
148 /* Emulate comparison opcodes. */
149 nRc = EmulateCPRT(opcode);
150 }
151 else if (TEST_OPCODE(opcode,MASK_CPDO))
152 {
153 /* Emulate monadic arithmetic opcodes. */
154 /* Emulate dyadic arithmetic opcodes. */
155 nRc = EmulateCPDO(opcode);
156 }
157 else if (TEST_OPCODE(opcode,MASK_CPDT))
158 {
159 /* Emulate load/store opcodes. */
160 /* Emulate load/store multiple opcodes. */
161 nRc = EmulateCPDT(opcode);
162 }
163 else
164 {
165 /* Invalid instruction detected. Return FALSE. */
166 nRc = 0;
167 }
168
169 restore_flags(flags);
170
171 return(nRc);
172 }
173
174 #if 0
175 unsigned int EmulateAll1(unsigned int opcode)
176 {
177 switch ((opcode >> 24) & 0xf)
178 {
179 case 0xc:
180 case 0xd:
181 if ((opcode >> 20) & 0x1)
182 {
183 switch ((opcode >> 8) & 0xf)
184 {
185 case 0x1: return PerformLDF(opcode); break;
186 case 0x2: return PerformLFM(opcode); break;
187 default: return 0;
188 }
189 }
190 else
191 {
192 switch ((opcode >> 8) & 0xf)
193 {
194 case 0x1: return PerformSTF(opcode); break;
195 case 0x2: return PerformSFM(opcode); break;
196 default: return 0;
197 }
198 }
199 break;
200
201 case 0xe:
202 if (opcode & 0x10)
203 return EmulateCPDO(opcode);
204 else
205 return EmulateCPRT(opcode);
206 break;
207
208 default: return 0;
209 }
210 }
211 #endif
212
213