2 NetWinder Floating Point Emulator
3 (c) Rebel.com, 1998-1999
4 (c) Philip Blundell, 1998
6 Direct questions, comments to Scott Bambrough <scottb@netwinder.org>
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.
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.
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.
24 #include "softfloat.h"
28 #include "fpmodule.inl"
30 #include <asm/uaccess.h>
33 void loadSingle(const unsigned int Fn
,const unsigned int *pMem
)
35 fpa11
->fpreg
[Fn
].fType
= typeSingle
;
36 get_user(fpa11
->fpreg
[Fn
].fValue
.fSingle
, pMem
);
40 void loadDouble(const unsigned int Fn
,const unsigned int *pMem
)
43 p
= (unsigned int*)&fpa11
->fpreg
[Fn
].fValue
.fDouble
;
44 fpa11
->fpreg
[Fn
].fType
= typeDouble
;
45 get_user(p
[0], &pMem
[1]);
46 get_user(p
[1], &pMem
[0]); /* sign & exponent */
50 void loadExtended(const unsigned int Fn
,const unsigned int *pMem
)
53 p
= (unsigned int*)&fpa11
->fpreg
[Fn
].fValue
.fExtended
;
54 fpa11
->fpreg
[Fn
].fType
= typeExtended
;
55 get_user(p
[0], &pMem
[0]); /* sign & exponent */
56 get_user(p
[1], &pMem
[2]); /* ls bits */
57 get_user(p
[2], &pMem
[1]); /* ms bits */
61 void loadMultiple(const unsigned int Fn
,const unsigned int *pMem
)
63 register unsigned int *p
;
66 p
= (unsigned int*)&(fpa11
->fpreg
[Fn
].fValue
);
67 get_user(x
, &pMem
[0]);
68 fpa11
->fpreg
[Fn
].fType
= (x
>> 14) & 0x00000003;
70 switch (fpa11
->fpreg
[Fn
].fType
)
75 get_user(p
[0], &pMem
[2]); /* Single */
76 get_user(p
[1], &pMem
[1]); /* double msw */
83 get_user(p
[1], &pMem
[2]);
84 get_user(p
[2], &pMem
[1]); /* msw */
85 p
[0] = (x
& 0x80003fff);
92 void storeSingle(const unsigned int Fn
,unsigned int *pMem
)
95 register unsigned int *p
= (unsigned int*)&val
;
97 switch (fpa11
->fpreg
[Fn
].fType
)
100 val
= float64_to_float32(fpa11
->fpreg
[Fn
].fValue
.fDouble
);
104 val
= floatx80_to_float32(fpa11
->fpreg
[Fn
].fValue
.fExtended
);
107 default: val
= fpa11
->fpreg
[Fn
].fValue
.fSingle
;
110 put_user(p
[0], pMem
);
114 void storeDouble(const unsigned int Fn
,unsigned int *pMem
)
117 register unsigned int *p
= (unsigned int*)&val
;
119 switch (fpa11
->fpreg
[Fn
].fType
)
122 val
= float32_to_float64(fpa11
->fpreg
[Fn
].fValue
.fSingle
);
126 val
= floatx80_to_float64(fpa11
->fpreg
[Fn
].fValue
.fExtended
);
129 default: val
= fpa11
->fpreg
[Fn
].fValue
.fDouble
;
131 put_user(p
[1], &pMem
[0]); /* msw */
132 put_user(p
[0], &pMem
[1]); /* lsw */
136 void storeExtended(const unsigned int Fn
,unsigned int *pMem
)
139 register unsigned int *p
= (unsigned int*)&val
;
141 switch (fpa11
->fpreg
[Fn
].fType
)
144 val
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fValue
.fSingle
);
148 val
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fValue
.fDouble
);
151 default: val
= fpa11
->fpreg
[Fn
].fValue
.fExtended
;
154 put_user(p
[0], &pMem
[0]); /* sign & exp */
155 put_user(p
[1], &pMem
[2]);
156 put_user(p
[2], &pMem
[1]); /* msw */
160 void storeMultiple(const unsigned int Fn
,unsigned int *pMem
)
162 register unsigned int nType
, *p
;
164 p
= (unsigned int*)&(fpa11
->fpreg
[Fn
].fValue
);
165 nType
= fpa11
->fpreg
[Fn
].fType
;
172 put_user(p
[0], &pMem
[2]); /* single */
173 put_user(p
[1], &pMem
[1]); /* double msw */
174 put_user(nType
<< 14, &pMem
[0]);
180 put_user(p
[2], &pMem
[1]); /* msw */
181 put_user(p
[1], &pMem
[2]);
182 put_user((p
[0] & 0x80003fff) | (nType
<< 14), &pMem
[0]);
188 unsigned int PerformLDF(const unsigned int opcode
)
190 unsigned int *pBase
, *pAddress
, *pFinal
, nRc
= 1;
192 //fp_printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
194 pBase
= (unsigned int*)readRegister(getRn(opcode
));
195 if (REG_PC
== getRn(opcode
)) pBase
+= 2;
198 if (BIT_UP_SET(opcode
))
199 pFinal
+= getOffset(opcode
);
201 pFinal
-= getOffset(opcode
);
203 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
205 switch (opcode
& MASK_TRANSFER_LENGTH
)
207 case TRANSFER_SINGLE
: loadSingle(getFd(opcode
),pAddress
); break;
208 case TRANSFER_DOUBLE
: loadDouble(getFd(opcode
),pAddress
); break;
209 case TRANSFER_EXTENDED
: loadExtended(getFd(opcode
),pAddress
); break;
213 if (WRITE_BACK(opcode
)) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
217 unsigned int PerformSTF(const unsigned int opcode
)
219 unsigned int *pBase
, *pAddress
, *pFinal
, nRc
= 1;
221 //fp_printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
222 SetRoundingMode(ROUND_TO_NEAREST
);
224 pBase
= (unsigned int*)readRegister(getRn(opcode
));
225 if (REG_PC
== getRn(opcode
)) pBase
+= 2;
228 if (BIT_UP_SET(opcode
))
229 pFinal
+= getOffset(opcode
);
231 pFinal
-= getOffset(opcode
);
233 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
235 switch (opcode
& MASK_TRANSFER_LENGTH
)
237 case TRANSFER_SINGLE
: storeSingle(getFd(opcode
),pAddress
); break;
238 case TRANSFER_DOUBLE
: storeDouble(getFd(opcode
),pAddress
); break;
239 case TRANSFER_EXTENDED
: storeExtended(getFd(opcode
),pAddress
); break;
243 if (WRITE_BACK(opcode
)) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
247 unsigned int PerformLFM(const unsigned int opcode
)
249 unsigned int i
, Fd
, *pBase
, *pAddress
, *pFinal
;
250 pBase
= (unsigned int*)readRegister(getRn(opcode
));
251 if (REG_PC
== getRn(opcode
)) pBase
+= 2;
254 if (BIT_UP_SET(opcode
))
255 pFinal
+= getOffset(opcode
);
257 pFinal
-= getOffset(opcode
);
259 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
262 for (i
=getRegisterCount(opcode
);i
>0;i
--)
264 loadMultiple(Fd
,pAddress
);
269 if (WRITE_BACK(opcode
)) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
273 unsigned int PerformSFM(const unsigned int opcode
)
275 unsigned int i
, Fd
, *pBase
, *pAddress
, *pFinal
;
277 pBase
= (unsigned int*)readRegister(getRn(opcode
));
278 if (REG_PC
== getRn(opcode
)) pBase
+= 2;
281 if (BIT_UP_SET(opcode
))
282 pFinal
+= getOffset(opcode
);
284 pFinal
-= getOffset(opcode
);
286 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
289 for (i
=getRegisterCount(opcode
);i
>0;i
--)
291 storeMultiple(Fd
,pAddress
);
296 if (WRITE_BACK(opcode
)) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
301 unsigned int EmulateCPDT(const unsigned int opcode
)
303 unsigned int nRc
= 0;
305 //fp_printk("EmulateCPDT(0x%08x)\n",opcode);
309 nRc
= PerformLDF(opcode
);
311 else if (LFM_OP(opcode
))
313 nRc
= PerformLFM(opcode
);
315 else if (STF_OP(opcode
))
317 nRc
= PerformSTF(opcode
);
319 else if (SFM_OP(opcode
))
321 nRc
= PerformSFM(opcode
);