xref: /openbmc/linux/arch/arm/nwfpe/fpa11_cpdt.c (revision a7144b23da073f4b3192e356ad74de12aba60e00)
1 /*
2     NetWinder Floating Point Emulator
3     (c) Rebel.com, 1998-1999
4     (c) Philip Blundell, 1998, 2001
5 
6     Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22 
23 #include <linux/config.h>
24 #include "fpa11.h"
25 #include "softfloat.h"
26 #include "fpopcode.h"
27 #include "fpmodule.h"
28 #include "fpmodule.inl"
29 
30 #include <asm/uaccess.h>
31 
32 static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
33 {
34 	FPA11 *fpa11 = GET_FPA11();
35 	fpa11->fType[Fn] = typeSingle;
36 	get_user(fpa11->fpreg[Fn].fSingle, pMem);
37 }
38 
39 static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
40 {
41 	FPA11 *fpa11 = GET_FPA11();
42 	unsigned int *p;
43 	p = (unsigned int *) &fpa11->fpreg[Fn].fDouble;
44 	fpa11->fType[Fn] = typeDouble;
45 #ifdef __ARMEB__
46 	get_user(p[0], &pMem[0]);	/* sign & exponent */
47 	get_user(p[1], &pMem[1]);
48 #else
49 	get_user(p[0], &pMem[1]);
50 	get_user(p[1], &pMem[0]);	/* sign & exponent */
51 #endif
52 }
53 
54 #ifdef CONFIG_FPE_NWFPE_XP
55 static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
56 {
57 	FPA11 *fpa11 = GET_FPA11();
58 	unsigned int *p;
59 	p = (unsigned int *) &fpa11->fpreg[Fn].fExtended;
60 	fpa11->fType[Fn] = typeExtended;
61 	get_user(p[0], &pMem[0]);	/* sign & exponent */
62 	get_user(p[1], &pMem[2]);	/* ls bits */
63 	get_user(p[2], &pMem[1]);	/* ms bits */
64 }
65 #endif
66 
67 static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
68 {
69 	FPA11 *fpa11 = GET_FPA11();
70 	register unsigned int *p;
71 	unsigned long x;
72 
73 	p = (unsigned int *) &(fpa11->fpreg[Fn]);
74 	get_user(x, &pMem[0]);
75 	fpa11->fType[Fn] = (x >> 14) & 0x00000003;
76 
77 	switch (fpa11->fType[Fn]) {
78 	case typeSingle:
79 	case typeDouble:
80 		{
81 			get_user(p[0], &pMem[2]);	/* Single */
82 			get_user(p[1], &pMem[1]);	/* double msw */
83 			p[2] = 0;			/* empty */
84 		}
85 		break;
86 
87 #ifdef CONFIG_FPE_NWFPE_XP
88 	case typeExtended:
89 		{
90 			get_user(p[1], &pMem[2]);
91 			get_user(p[2], &pMem[1]);	/* msw */
92 			p[0] = (x & 0x80003fff);
93 		}
94 		break;
95 #endif
96 	}
97 }
98 
99 static inline void storeSingle(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
100 {
101 	FPA11 *fpa11 = GET_FPA11();
102 	union {
103 		float32 f;
104 		unsigned int i[1];
105 	} val;
106 
107 	switch (fpa11->fType[Fn]) {
108 	case typeDouble:
109 		val.f = float64_to_float32(roundData, fpa11->fpreg[Fn].fDouble);
110 		break;
111 
112 #ifdef CONFIG_FPE_NWFPE_XP
113 	case typeExtended:
114 		val.f = floatx80_to_float32(roundData, fpa11->fpreg[Fn].fExtended);
115 		break;
116 #endif
117 
118 	default:
119 		val.f = fpa11->fpreg[Fn].fSingle;
120 	}
121 
122 	put_user(val.i[0], pMem);
123 }
124 
125 static inline void storeDouble(struct roundingData *roundData, const unsigned int Fn, unsigned int __user *pMem)
126 {
127 	FPA11 *fpa11 = GET_FPA11();
128 	union {
129 		float64 f;
130 		unsigned int i[2];
131 	} val;
132 
133 	switch (fpa11->fType[Fn]) {
134 	case typeSingle:
135 		val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle);
136 		break;
137 
138 #ifdef CONFIG_FPE_NWFPE_XP
139 	case typeExtended:
140 		val.f = floatx80_to_float64(roundData, fpa11->fpreg[Fn].fExtended);
141 		break;
142 #endif
143 
144 	default:
145 		val.f = fpa11->fpreg[Fn].fDouble;
146 	}
147 
148 #ifdef __ARMEB__
149 	put_user(val.i[0], &pMem[0]);	/* msw */
150 	put_user(val.i[1], &pMem[1]);	/* lsw */
151 #else
152 	put_user(val.i[1], &pMem[0]);	/* msw */
153 	put_user(val.i[0], &pMem[1]);	/* lsw */
154 #endif
155 }
156 
157 #ifdef CONFIG_FPE_NWFPE_XP
158 static inline void storeExtended(const unsigned int Fn, unsigned int __user *pMem)
159 {
160 	FPA11 *fpa11 = GET_FPA11();
161 	union {
162 		floatx80 f;
163 		unsigned int i[3];
164 	} val;
165 
166 	switch (fpa11->fType[Fn]) {
167 	case typeSingle:
168 		val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle);
169 		break;
170 
171 	case typeDouble:
172 		val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble);
173 		break;
174 
175 	default:
176 		val.f = fpa11->fpreg[Fn].fExtended;
177 	}
178 
179 	put_user(val.i[0], &pMem[0]);	/* sign & exp */
180 	put_user(val.i[1], &pMem[2]);
181 	put_user(val.i[2], &pMem[1]);	/* msw */
182 }
183 #endif
184 
185 static inline void storeMultiple(const unsigned int Fn, unsigned int __user *pMem)
186 {
187 	FPA11 *fpa11 = GET_FPA11();
188 	register unsigned int nType, *p;
189 
190 	p = (unsigned int *) &(fpa11->fpreg[Fn]);
191 	nType = fpa11->fType[Fn];
192 
193 	switch (nType) {
194 	case typeSingle:
195 	case typeDouble:
196 		{
197 			put_user(p[0], &pMem[2]);	/* single */
198 			put_user(p[1], &pMem[1]);	/* double msw */
199 			put_user(nType << 14, &pMem[0]);
200 		}
201 		break;
202 
203 #ifdef CONFIG_FPE_NWFPE_XP
204 	case typeExtended:
205 		{
206 			put_user(p[2], &pMem[1]);	/* msw */
207 			put_user(p[1], &pMem[2]);
208 			put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]);
209 		}
210 		break;
211 #endif
212 	}
213 }
214 
215 unsigned int PerformLDF(const unsigned int opcode)
216 {
217 	unsigned int __user *pBase, *pAddress, *pFinal;
218 	unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
219 
220 	pBase = (unsigned int __user *) readRegister(getRn(opcode));
221 	if (REG_PC == getRn(opcode)) {
222 		pBase += 2;
223 		write_back = 0;
224 	}
225 
226 	pFinal = pBase;
227 	if (BIT_UP_SET(opcode))
228 		pFinal += getOffset(opcode);
229 	else
230 		pFinal -= getOffset(opcode);
231 
232 	if (PREINDEXED(opcode))
233 		pAddress = pFinal;
234 	else
235 		pAddress = pBase;
236 
237 	switch (opcode & MASK_TRANSFER_LENGTH) {
238 	case TRANSFER_SINGLE:
239 		loadSingle(getFd(opcode), pAddress);
240 		break;
241 	case TRANSFER_DOUBLE:
242 		loadDouble(getFd(opcode), pAddress);
243 		break;
244 #ifdef CONFIG_FPE_NWFPE_XP
245 	case TRANSFER_EXTENDED:
246 		loadExtended(getFd(opcode), pAddress);
247 		break;
248 #endif
249 	default:
250 		nRc = 0;
251 	}
252 
253 	if (write_back)
254 		writeRegister(getRn(opcode), (unsigned long) pFinal);
255 	return nRc;
256 }
257 
258 unsigned int PerformSTF(const unsigned int opcode)
259 {
260 	unsigned int __user *pBase, *pAddress, *pFinal;
261 	unsigned int nRc = 1, write_back = WRITE_BACK(opcode);
262 	struct roundingData roundData;
263 
264 	roundData.mode = SetRoundingMode(opcode);
265 	roundData.precision = SetRoundingPrecision(opcode);
266 	roundData.exception = 0;
267 
268 	pBase = (unsigned int __user *) readRegister(getRn(opcode));
269 	if (REG_PC == getRn(opcode)) {
270 		pBase += 2;
271 		write_back = 0;
272 	}
273 
274 	pFinal = pBase;
275 	if (BIT_UP_SET(opcode))
276 		pFinal += getOffset(opcode);
277 	else
278 		pFinal -= getOffset(opcode);
279 
280 	if (PREINDEXED(opcode))
281 		pAddress = pFinal;
282 	else
283 		pAddress = pBase;
284 
285 	switch (opcode & MASK_TRANSFER_LENGTH) {
286 	case TRANSFER_SINGLE:
287 		storeSingle(&roundData, getFd(opcode), pAddress);
288 		break;
289 	case TRANSFER_DOUBLE:
290 		storeDouble(&roundData, getFd(opcode), pAddress);
291 		break;
292 #ifdef CONFIG_FPE_NWFPE_XP
293 	case TRANSFER_EXTENDED:
294 		storeExtended(getFd(opcode), pAddress);
295 		break;
296 #endif
297 	default:
298 		nRc = 0;
299 	}
300 
301 	if (roundData.exception)
302 		float_raise(roundData.exception);
303 
304 	if (write_back)
305 		writeRegister(getRn(opcode), (unsigned long) pFinal);
306 	return nRc;
307 }
308 
309 unsigned int PerformLFM(const unsigned int opcode)
310 {
311 	unsigned int __user *pBase, *pAddress, *pFinal;
312 	unsigned int i, Fd, write_back = WRITE_BACK(opcode);
313 
314 	pBase = (unsigned int __user *) readRegister(getRn(opcode));
315 	if (REG_PC == getRn(opcode)) {
316 		pBase += 2;
317 		write_back = 0;
318 	}
319 
320 	pFinal = pBase;
321 	if (BIT_UP_SET(opcode))
322 		pFinal += getOffset(opcode);
323 	else
324 		pFinal -= getOffset(opcode);
325 
326 	if (PREINDEXED(opcode))
327 		pAddress = pFinal;
328 	else
329 		pAddress = pBase;
330 
331 	Fd = getFd(opcode);
332 	for (i = getRegisterCount(opcode); i > 0; i--) {
333 		loadMultiple(Fd, pAddress);
334 		pAddress += 3;
335 		Fd++;
336 		if (Fd == 8)
337 			Fd = 0;
338 	}
339 
340 	if (write_back)
341 		writeRegister(getRn(opcode), (unsigned long) pFinal);
342 	return 1;
343 }
344 
345 unsigned int PerformSFM(const unsigned int opcode)
346 {
347 	unsigned int __user *pBase, *pAddress, *pFinal;
348 	unsigned int i, Fd, write_back = WRITE_BACK(opcode);
349 
350 	pBase = (unsigned int __user *) readRegister(getRn(opcode));
351 	if (REG_PC == getRn(opcode)) {
352 		pBase += 2;
353 		write_back = 0;
354 	}
355 
356 	pFinal = pBase;
357 	if (BIT_UP_SET(opcode))
358 		pFinal += getOffset(opcode);
359 	else
360 		pFinal -= getOffset(opcode);
361 
362 	if (PREINDEXED(opcode))
363 		pAddress = pFinal;
364 	else
365 		pAddress = pBase;
366 
367 	Fd = getFd(opcode);
368 	for (i = getRegisterCount(opcode); i > 0; i--) {
369 		storeMultiple(Fd, pAddress);
370 		pAddress += 3;
371 		Fd++;
372 		if (Fd == 8)
373 			Fd = 0;
374 	}
375 
376 	if (write_back)
377 		writeRegister(getRn(opcode), (unsigned long) pFinal);
378 	return 1;
379 }
380 
381 unsigned int EmulateCPDT(const unsigned int opcode)
382 {
383 	unsigned int nRc = 0;
384 
385 	if (LDF_OP(opcode)) {
386 		nRc = PerformLDF(opcode);
387 	} else if (LFM_OP(opcode)) {
388 		nRc = PerformLFM(opcode);
389 	} else if (STF_OP(opcode)) {
390 		nRc = PerformSTF(opcode);
391 	} else if (SFM_OP(opcode)) {
392 		nRc = PerformSFM(opcode);
393 	} else {
394 		nRc = 0;
395 	}
396 
397 	return nRc;
398 }
399