PageRenderTime 25ms CodeModel.GetById 2ms app.highlight 19ms RepoModel.GetById 2ms app.codeStats 0ms

/arch/arm/nwfpe/fpa11_cpdt.c

https://bitbucket.org/evzijst/gittest
C | 392 lines | 315 code | 56 blank | 21 comment | 41 complexity | d741d66346e32ff704d112369e8c0b9e MD5 | raw file
  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
 32static 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
 39static 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
 55static 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
 67static 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
 99static inline void storeSingle(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(fpa11->fpreg[Fn].fDouble);
110		break;
111
112#ifdef CONFIG_FPE_NWFPE_XP
113	case typeExtended:
114		val.f = floatx80_to_float32(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
125static inline void storeDouble(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(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
158static 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
185static 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
215unsigned 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
258unsigned 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
263	SetRoundingMode(ROUND_TO_NEAREST);
264
265	pBase = (unsigned int __user *) readRegister(getRn(opcode));
266	if (REG_PC == getRn(opcode)) {
267		pBase += 2;
268		write_back = 0;
269	}
270
271	pFinal = pBase;
272	if (BIT_UP_SET(opcode))
273		pFinal += getOffset(opcode);
274	else
275		pFinal -= getOffset(opcode);
276
277	if (PREINDEXED(opcode))
278		pAddress = pFinal;
279	else
280		pAddress = pBase;
281
282	switch (opcode & MASK_TRANSFER_LENGTH) {
283	case TRANSFER_SINGLE:
284		storeSingle(getFd(opcode), pAddress);
285		break;
286	case TRANSFER_DOUBLE:
287		storeDouble(getFd(opcode), pAddress);
288		break;
289#ifdef CONFIG_FPE_NWFPE_XP
290	case TRANSFER_EXTENDED:
291		storeExtended(getFd(opcode), pAddress);
292		break;
293#endif
294	default:
295		nRc = 0;
296	}
297
298	if (write_back)
299		writeRegister(getRn(opcode), (unsigned long) pFinal);
300	return nRc;
301}
302
303unsigned int PerformLFM(const unsigned int opcode)
304{
305	unsigned int __user *pBase, *pAddress, *pFinal;
306	unsigned int i, Fd, write_back = WRITE_BACK(opcode);
307
308	pBase = (unsigned int __user *) readRegister(getRn(opcode));
309	if (REG_PC == getRn(opcode)) {
310		pBase += 2;
311		write_back = 0;
312	}
313
314	pFinal = pBase;
315	if (BIT_UP_SET(opcode))
316		pFinal += getOffset(opcode);
317	else
318		pFinal -= getOffset(opcode);
319
320	if (PREINDEXED(opcode))
321		pAddress = pFinal;
322	else
323		pAddress = pBase;
324
325	Fd = getFd(opcode);
326	for (i = getRegisterCount(opcode); i > 0; i--) {
327		loadMultiple(Fd, pAddress);
328		pAddress += 3;
329		Fd++;
330		if (Fd == 8)
331			Fd = 0;
332	}
333
334	if (write_back)
335		writeRegister(getRn(opcode), (unsigned long) pFinal);
336	return 1;
337}
338
339unsigned int PerformSFM(const unsigned int opcode)
340{
341	unsigned int __user *pBase, *pAddress, *pFinal;
342	unsigned int i, Fd, write_back = WRITE_BACK(opcode);
343
344	pBase = (unsigned int __user *) readRegister(getRn(opcode));
345	if (REG_PC == getRn(opcode)) {
346		pBase += 2;
347		write_back = 0;
348	}
349
350	pFinal = pBase;
351	if (BIT_UP_SET(opcode))
352		pFinal += getOffset(opcode);
353	else
354		pFinal -= getOffset(opcode);
355
356	if (PREINDEXED(opcode))
357		pAddress = pFinal;
358	else
359		pAddress = pBase;
360
361	Fd = getFd(opcode);
362	for (i = getRegisterCount(opcode); i > 0; i--) {
363		storeMultiple(Fd, pAddress);
364		pAddress += 3;
365		Fd++;
366		if (Fd == 8)
367			Fd = 0;
368	}
369
370	if (write_back)
371		writeRegister(getRn(opcode), (unsigned long) pFinal);
372	return 1;
373}
374
375unsigned int EmulateCPDT(const unsigned int opcode)
376{
377	unsigned int nRc = 0;
378
379	if (LDF_OP(opcode)) {
380		nRc = PerformLDF(opcode);
381	} else if (LFM_OP(opcode)) {
382		nRc = PerformLFM(opcode);
383	} else if (STF_OP(opcode)) {
384		nRc = PerformSTF(opcode);
385	} else if (SFM_OP(opcode)) {
386		nRc = PerformSFM(opcode);
387	} else {
388		nRc = 0;
389	}
390
391	return nRc;
392}