Linux Audio

Check our new training course

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