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 /* FIXME - handle failure of get_user() */
38 get_user_u32(fpa11
->fpreg
[Fn
].fSingle
, addr
);
42 void loadDouble(const unsigned int Fn
,const unsigned int *pMem
)
44 target_ulong addr
= (target_ulong
)(long)pMem
;
45 FPA11
*fpa11
= GET_FPA11();
47 p
= (unsigned int*)&fpa11
->fpreg
[Fn
].fDouble
;
48 fpa11
->fType
[Fn
] = typeDouble
;
49 #ifdef WORDS_BIGENDIAN
50 /* FIXME - handle failure of get_user() */
51 get_user_u32(p
[0], addr
); /* sign & exponent */
52 get_user_u32(p
[1], addr
+ 4);
54 /* FIXME - handle failure of get_user() */
55 get_user_u32(p
[0], addr
+ 4);
56 get_user_u32(p
[1], addr
); /* sign & exponent */
61 void loadExtended(const unsigned int Fn
,const unsigned int *pMem
)
63 target_ulong addr
= (target_ulong
)(long)pMem
;
64 FPA11
*fpa11
= GET_FPA11();
66 p
= (unsigned int*)&fpa11
->fpreg
[Fn
].fExtended
;
67 fpa11
->fType
[Fn
] = typeExtended
;
68 /* FIXME - handle failure of get_user() */
69 get_user_u32(p
[0], addr
); /* sign & exponent */
70 get_user_u32(p
[1], addr
+ 8); /* ls bits */
71 get_user_u32(p
[2], addr
+ 4); /* ms bits */
75 void loadMultiple(const unsigned int Fn
,const unsigned int *pMem
)
77 target_ulong addr
= (target_ulong
)(long)pMem
;
78 FPA11
*fpa11
= GET_FPA11();
79 register unsigned int *p
;
82 p
= (unsigned int*)&(fpa11
->fpreg
[Fn
]);
83 /* FIXME - handle failure of get_user() */
84 get_user_u32(x
, addr
);
85 fpa11
->fType
[Fn
] = (x
>> 14) & 0x00000003;
87 switch (fpa11
->fType
[Fn
])
92 /* FIXME - handle failure of get_user() */
93 get_user_u32(p
[0], addr
+ 8); /* Single */
94 get_user_u32(p
[1], addr
+ 4); /* double msw */
101 /* FIXME - handle failure of get_user() */
102 get_user_u32(p
[1], addr
+ 8);
103 get_user_u32(p
[2], addr
+ 4); /* msw */
104 p
[0] = (x
& 0x80003fff);
111 void storeSingle(const unsigned int Fn
,unsigned int *pMem
)
113 target_ulong addr
= (target_ulong
)(long)pMem
;
114 FPA11
*fpa11
= GET_FPA11();
116 register unsigned int *p
= (unsigned int*)&val
;
118 switch (fpa11
->fType
[Fn
])
121 val
= float64_to_float32(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
);
125 val
= floatx80_to_float32(fpa11
->fpreg
[Fn
].fExtended
, &fpa11
->fp_status
);
128 default: val
= fpa11
->fpreg
[Fn
].fSingle
;
131 /* FIXME - handle put_user() failures */
132 put_user_u32(p
[0], addr
);
136 void storeDouble(const unsigned int Fn
,unsigned int *pMem
)
138 target_ulong addr
= (target_ulong
)(long)pMem
;
139 FPA11
*fpa11
= GET_FPA11();
141 register unsigned int *p
= (unsigned int*)&val
;
143 switch (fpa11
->fType
[Fn
])
146 val
= float32_to_float64(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
);
150 val
= floatx80_to_float64(fpa11
->fpreg
[Fn
].fExtended
, &fpa11
->fp_status
);
153 default: val
= fpa11
->fpreg
[Fn
].fDouble
;
155 /* FIXME - handle put_user() failures */
156 #ifdef WORDS_BIGENDIAN
157 put_user_u32(p
[0], addr
); /* msw */
158 put_user_u32(p
[1], addr
+ 4); /* lsw */
160 put_user_u32(p
[1], addr
); /* msw */
161 put_user_u32(p
[0], addr
+ 4); /* lsw */
166 void storeExtended(const unsigned int Fn
,unsigned int *pMem
)
168 target_ulong addr
= (target_ulong
)(long)pMem
;
169 FPA11
*fpa11
= GET_FPA11();
171 register unsigned int *p
= (unsigned int*)&val
;
173 switch (fpa11
->fType
[Fn
])
176 val
= float32_to_floatx80(fpa11
->fpreg
[Fn
].fSingle
, &fpa11
->fp_status
);
180 val
= float64_to_floatx80(fpa11
->fpreg
[Fn
].fDouble
, &fpa11
->fp_status
);
183 default: val
= fpa11
->fpreg
[Fn
].fExtended
;
186 /* FIXME - handle put_user() failures */
187 put_user_u32(p
[0], addr
); /* sign & exp */
188 put_user_u32(p
[1], addr
+ 8);
189 put_user_u32(p
[2], addr
+ 4); /* msw */
193 void storeMultiple(const unsigned int Fn
,unsigned int *pMem
)
195 target_ulong addr
= (target_ulong
)(long)pMem
;
196 FPA11
*fpa11
= GET_FPA11();
197 register unsigned int nType
, *p
;
199 p
= (unsigned int*)&(fpa11
->fpreg
[Fn
]);
200 nType
= fpa11
->fType
[Fn
];
207 put_user_u32(p
[0], addr
+ 8); /* single */
208 put_user_u32(p
[1], addr
+ 4); /* double msw */
209 put_user_u32(nType
<< 14, addr
);
215 put_user_u32(p
[2], addr
+ 4); /* msw */
216 put_user_u32(p
[1], addr
+ 8);
217 put_user_u32((p
[0] & 0x80003fff) | (nType
<< 14), addr
);
223 unsigned int PerformLDF(const unsigned int opcode
)
225 unsigned int *pBase
, *pAddress
, *pFinal
, nRc
= 1,
226 write_back
= WRITE_BACK(opcode
);
228 //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
230 pBase
= (unsigned int*)readRegister(getRn(opcode
));
231 if (REG_PC
== getRn(opcode
))
238 if (BIT_UP_SET(opcode
))
239 pFinal
+= getOffset(opcode
);
241 pFinal
-= getOffset(opcode
);
243 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
245 switch (opcode
& MASK_TRANSFER_LENGTH
)
247 case TRANSFER_SINGLE
: loadSingle(getFd(opcode
),pAddress
); break;
248 case TRANSFER_DOUBLE
: loadDouble(getFd(opcode
),pAddress
); break;
249 case TRANSFER_EXTENDED
: loadExtended(getFd(opcode
),pAddress
); break;
253 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
257 unsigned int PerformSTF(const unsigned int opcode
)
259 unsigned int *pBase
, *pAddress
, *pFinal
, nRc
= 1,
260 write_back
= WRITE_BACK(opcode
);
262 //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode));
263 SetRoundingMode(ROUND_TO_NEAREST
);
265 pBase
= (unsigned int*)readRegister(getRn(opcode
));
266 if (REG_PC
== getRn(opcode
))
273 if (BIT_UP_SET(opcode
))
274 pFinal
+= getOffset(opcode
);
276 pFinal
-= getOffset(opcode
);
278 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
280 switch (opcode
& MASK_TRANSFER_LENGTH
)
282 case TRANSFER_SINGLE
: storeSingle(getFd(opcode
),pAddress
); break;
283 case TRANSFER_DOUBLE
: storeDouble(getFd(opcode
),pAddress
); break;
284 case TRANSFER_EXTENDED
: storeExtended(getFd(opcode
),pAddress
); break;
288 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
292 unsigned int PerformLFM(const unsigned int opcode
)
294 unsigned int i
, Fd
, *pBase
, *pAddress
, *pFinal
,
295 write_back
= WRITE_BACK(opcode
);
297 pBase
= (unsigned int*)readRegister(getRn(opcode
));
298 if (REG_PC
== getRn(opcode
))
305 if (BIT_UP_SET(opcode
))
306 pFinal
+= getOffset(opcode
);
308 pFinal
-= getOffset(opcode
);
310 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
313 for (i
=getRegisterCount(opcode
);i
>0;i
--)
315 loadMultiple(Fd
,pAddress
);
320 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
324 unsigned int PerformSFM(const unsigned int opcode
)
326 unsigned int i
, Fd
, *pBase
, *pAddress
, *pFinal
,
327 write_back
= WRITE_BACK(opcode
);
329 pBase
= (unsigned int*)readRegister(getRn(opcode
));
330 if (REG_PC
== getRn(opcode
))
337 if (BIT_UP_SET(opcode
))
338 pFinal
+= getOffset(opcode
);
340 pFinal
-= getOffset(opcode
);
342 if (PREINDEXED(opcode
)) pAddress
= pFinal
; else pAddress
= pBase
;
345 for (i
=getRegisterCount(opcode
);i
>0;i
--)
347 storeMultiple(Fd
,pAddress
);
352 if (write_back
) writeRegister(getRn(opcode
),(unsigned int)pFinal
);
357 unsigned int EmulateCPDT(const unsigned int opcode
)
359 unsigned int nRc
= 0;
361 //printk("EmulateCPDT(0x%08x)\n",opcode);
365 nRc
= PerformLDF(opcode
);
367 else if (LFM_OP(opcode
))
369 nRc
= PerformLFM(opcode
);
371 else if (STF_OP(opcode
))
373 nRc
= PerformSTF(opcode
);
375 else if (SFM_OP(opcode
))
377 nRc
= PerformSFM(opcode
);