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"
26 //#include "fpmodule.h"
27 //#include "fpmodule.inl"
29 //#include <asm/uaccess.h>
32 void loadSingle(const unsigned int Fn
,const unsigned int *pMem
)
34 target_ulong addr
= (target_ulong
)(long)pMem
;
35 FPA11
*fpa11
= GET_FPA11();
36 fpa11
->fType
[Fn
] = typeSingle
;
37 fpa11
->fpreg
[Fn
].fSingle
= tget32(addr
);
41 void loadDouble(const unsigned int Fn
,const unsigned int *pMem
)
43 target_ulong addr
= (target_ulong
)(long)pMem
;
44 FPA11
*fpa11
= GET_FPA11();
46 p
= (unsigned int*)&fpa11
->fpreg
[Fn
].fDouble
;
47 fpa11
->fType
[Fn
] = typeDouble
;
48 #ifdef WORDS_BIGENDIAN
49 p
[0] = tget32(addr
); /* sign & exponent */
50 p
[1] = tget32(addr
+ 4);
52 p
[0] = tget32(addr
+ 4);
53 p
[1] = tget32(addr
); /* sign & exponent */
58 void loadExtended(const unsigned int Fn
,const unsigned int *pMem
)
60 target_ulong addr
= (target_ulong
)(long)pMem
;
61 FPA11
*fpa11
= GET_FPA11();
63 p
= (unsigned int*)&fpa11
->fpreg
[Fn
].fExtended
;
64 fpa11
->fType
[Fn
] = typeExtended
;
65 p
[0] = tget32(addr
); /* sign & exponent */
66 p
[1] = tget32(addr
+ 8); /* ls bits */
67 p
[2] = tget32(addr
+ 4); /* ms bits */
71 void loadMultiple(const unsigned int Fn
,const unsigned int *pMem
)
73 target_ulong addr
= (target_ulong
)(long)pMem
;
74 FPA11
*fpa11
= GET_FPA11();
75 register unsigned int *p
;
78 p
= (unsigned int*)&(fpa11
->fpreg
[Fn
]);
80 fpa11
->fType
[Fn
] = (x
>> 14) & 0x00000003;
82 switch (fpa11
->fType
[Fn
])
87 p
[0] = tget32(addr
+ 8); /* Single */
88 p
[1] = tget32(addr
+ 4); /* double msw */
95 p
[1] = tget32(addr
+ 8);
96 p
[2] = tget32(addr
+ 4); /* msw */
97 p
[0] = (x
& 0x80003fff);
104 void storeSingle(const unsigned int Fn
,unsigned int *pMem
)
106 target_ulong addr
= (target_ulong
)(long)pMem
;
107 FPA11
*fpa11
= GET_FPA11();
109 register unsigned int *p
= (unsigned int*)&val
;
111 switch (fpa11
->fType
[Fn
])
114 val
= float64_to_float32(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
);
118 val
= floatx80_to_float32(fpa11
->fpreg
[Fn
].fExtended
, &fpa11
->fp_status
);
121 default: val
= fpa11
->fpreg
[Fn
].fSingle
;
128 void storeDouble(const unsigned int Fn
,unsigned int *pMem
)
130 target_ulong addr
= (target_ulong
)(long)pMem
;
131 FPA11
*fpa11
= GET_FPA11();
133 register unsigned int *p
= (unsigned int*)&val
;
135 switch (fpa11
->fType
[Fn
])
138 val
= float32_to_float64(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
);
142 val
= floatx80_to_float64(fpa11
->fpreg
[Fn
].fExtended
, &fpa11
->fp_status
);
145 default: val
= fpa11
->fpreg
[Fn
].fDouble
;
147 #ifdef WORDS_BIGENDIAN
148 tput32(addr
, p
[0]); /* msw */
149 tput32(addr
+ 4, p
[1]); /* lsw */
151 tput32(addr
, p
[1]); /* msw */
152 tput32(addr
+ 4, p
[0]); /* lsw */
157 void storeExtended(const unsigned int Fn
,unsigned int *pMem
)
159 target_ulong addr
= (target_ulong
)(long)pMem
;
160 FPA11
*fpa11
= GET_FPA11();
162 register unsigned int *p
= (unsigned int*)&val
;
164 switch (fpa11
->fType
[Fn
])
167 val
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
);
171 val
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
);
174 default: val
= fpa11
->fpreg
[Fn
].fExtended
;
177 tput32(addr
, p
[0]); /* sign & exp */
178 tput32(addr
+ 8, p
[1]);
179 tput32(addr
+ 4, p
[2]); /* msw */
183 void storeMultiple(const unsigned int Fn
,unsigned int *pMem
)
185 target_ulong addr
= (target_ulong
)(long)pMem
;
186 FPA11
*fpa11
= GET_FPA11();
187 register unsigned int nType
, *p
;
189 p
= (unsigned int*)&(fpa11
->fpreg
[Fn
]);
190 nType
= fpa11
->fType
[Fn
];
197 tput32(addr
+ 8, p
[0]); /* single */
198 tput32(addr
+ 4, p
[1]); /* double msw */
199 tput32(addr
, nType
<< 14);
205 tput32(addr
+ 4, p
[2]); /* msw */
206 tput32(addr
+ 8, p
[1]);
207 tput32(addr
, (p
[0] & 0x80003fff) | (nType
<< 14));
213 unsigned int PerformLDF(const unsigned int opcode
)
215 unsigned int *pBase
, *pAddress
, *pFinal
, nRc
= 1,
216 write_back
= WRITE_BACK(opcode
);
218 //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
220 pBase
= (unsigned int*)readRegister(getRn(opcode
));
221 if (REG_PC
== getRn(opcode
))
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
: loadSingle(getFd(opcode
),pAddress
); break;
238 case TRANSFER_DOUBLE
: loadDouble(getFd(opcode
),pAddress
); break;
239 case TRANSFER_EXTENDED
: loadExtended(getFd(opcode
),pAddress
); break;
243 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
247 unsigned int PerformSTF(const unsigned int opcode
)
249 unsigned int *pBase
, *pAddress
, *pFinal
, nRc
= 1,
250 write_back
= WRITE_BACK(opcode
);
252 //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
253 SetRoundingMode(ROUND_TO_NEAREST
);
255 pBase
= (unsigned int*)readRegister(getRn(opcode
));
256 if (REG_PC
== getRn(opcode
))
263 if (BIT_UP_SET(opcode
))
264 pFinal
+= getOffset(opcode
);
266 pFinal
-= getOffset(opcode
);
268 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
270 switch (opcode
& MASK_TRANSFER_LENGTH
)
272 case TRANSFER_SINGLE
: storeSingle(getFd(opcode
),pAddress
); break;
273 case TRANSFER_DOUBLE
: storeDouble(getFd(opcode
),pAddress
); break;
274 case TRANSFER_EXTENDED
: storeExtended(getFd(opcode
),pAddress
); break;
278 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
282 unsigned int PerformLFM(const unsigned int opcode
)
284 unsigned int i
, Fd
, *pBase
, *pAddress
, *pFinal
,
285 write_back
= WRITE_BACK(opcode
);
287 pBase
= (unsigned int*)readRegister(getRn(opcode
));
288 if (REG_PC
== getRn(opcode
))
295 if (BIT_UP_SET(opcode
))
296 pFinal
+= getOffset(opcode
);
298 pFinal
-= getOffset(opcode
);
300 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
303 for (i
=getRegisterCount(opcode
);i
>0;i
--)
305 loadMultiple(Fd
,pAddress
);
310 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
314 unsigned int PerformSFM(const unsigned int opcode
)
316 unsigned int i
, Fd
, *pBase
, *pAddress
, *pFinal
,
317 write_back
= WRITE_BACK(opcode
);
319 pBase
= (unsigned int*)readRegister(getRn(opcode
));
320 if (REG_PC
== getRn(opcode
))
327 if (BIT_UP_SET(opcode
))
328 pFinal
+= getOffset(opcode
);
330 pFinal
-= getOffset(opcode
);
332 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
335 for (i
=getRegisterCount(opcode
);i
>0;i
--)
337 storeMultiple(Fd
,pAddress
);
342 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
347 unsigned int EmulateCPDT(const unsigned int opcode
)
349 unsigned int nRc
= 0;
351 //printk("EmulateCPDT(0x%08x)\n",opcode);
355 nRc
= PerformLDF(opcode
);
357 else if (LFM_OP(opcode
))
359 nRc
= PerformLFM(opcode
);
361 else if (STF_OP(opcode
))
363 nRc
= PerformSTF(opcode
);
365 else if (SFM_OP(opcode
))
367 nRc
= PerformSFM(opcode
);