]>
Commit | Line | Data |
---|---|---|
00406dff FB |
1 | /* |
2 | NetWinder Floating Point Emulator | |
3 | (c) Rebel.com, 1998-1999 | |
4 | (c) Philip Blundell, 1998 | |
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 <asm/uaccess.h> | |
30 | ||
31 | static inline | |
32 | void loadSingle(const unsigned int Fn,const unsigned int *pMem) | |
33 | { | |
53a5960a | 34 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
35 | FPA11 *fpa11 = GET_FPA11(); |
36 | fpa11->fType[Fn] = typeSingle; | |
53a5960a | 37 | fpa11->fpreg[Fn].fSingle = tget32(addr); |
00406dff FB |
38 | } |
39 | ||
40 | static inline | |
41 | void loadDouble(const unsigned int Fn,const unsigned int *pMem) | |
42 | { | |
53a5960a | 43 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
44 | FPA11 *fpa11 = GET_FPA11(); |
45 | unsigned int *p; | |
46 | p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; | |
47 | fpa11->fType[Fn] = typeDouble; | |
a8d3431a | 48 | #ifdef WORDS_BIGENDIAN |
53a5960a PB |
49 | p[0] = tget32(addr); /* sign & exponent */ |
50 | p[1] = tget32(addr + 4); | |
a8d3431a | 51 | #else |
53a5960a PB |
52 | p[0] = tget32(addr + 4); |
53 | p[1] = tget32(addr); /* sign & exponent */ | |
a8d3431a | 54 | #endif |
5fafdf24 | 55 | } |
00406dff FB |
56 | |
57 | static inline | |
58 | void loadExtended(const unsigned int Fn,const unsigned int *pMem) | |
59 | { | |
53a5960a | 60 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
61 | FPA11 *fpa11 = GET_FPA11(); |
62 | unsigned int *p; | |
63 | p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; | |
64 | fpa11->fType[Fn] = typeExtended; | |
53a5960a PB |
65 | p[0] = tget32(addr); /* sign & exponent */ |
66 | p[1] = tget32(addr + 8); /* ls bits */ | |
67 | p[2] = tget32(addr + 4); /* ms bits */ | |
5fafdf24 | 68 | } |
00406dff FB |
69 | |
70 | static inline | |
71 | void loadMultiple(const unsigned int Fn,const unsigned int *pMem) | |
72 | { | |
53a5960a | 73 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
74 | FPA11 *fpa11 = GET_FPA11(); |
75 | register unsigned int *p; | |
76 | unsigned long x; | |
77 | ||
78 | p = (unsigned int*)&(fpa11->fpreg[Fn]); | |
53a5960a | 79 | x = tget32(addr); |
00406dff | 80 | fpa11->fType[Fn] = (x >> 14) & 0x00000003; |
5fafdf24 | 81 | |
00406dff FB |
82 | switch (fpa11->fType[Fn]) |
83 | { | |
84 | case typeSingle: | |
85 | case typeDouble: | |
86 | { | |
53a5960a PB |
87 | p[0] = tget32(addr + 8); /* Single */ |
88 | p[1] = tget32(addr + 4); /* double msw */ | |
00406dff FB |
89 | p[2] = 0; /* empty */ |
90 | } | |
5fafdf24 TS |
91 | break; |
92 | ||
00406dff FB |
93 | case typeExtended: |
94 | { | |
53a5960a PB |
95 | p[1] = tget32(addr + 8); |
96 | p[2] = tget32(addr + 4); /* msw */ | |
5fafdf24 | 97 | p[0] = (x & 0x80003fff); |
00406dff FB |
98 | } |
99 | break; | |
100 | } | |
101 | } | |
102 | ||
103 | static inline | |
104 | void storeSingle(const unsigned int Fn,unsigned int *pMem) | |
105 | { | |
53a5960a | 106 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
107 | FPA11 *fpa11 = GET_FPA11(); |
108 | float32 val; | |
109 | register unsigned int *p = (unsigned int*)&val; | |
5fafdf24 | 110 | |
00406dff FB |
111 | switch (fpa11->fType[Fn]) |
112 | { | |
5fafdf24 | 113 | case typeDouble: |
20495218 | 114 | val = float64_to_float32(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); |
00406dff FB |
115 | break; |
116 | ||
5fafdf24 | 117 | case typeExtended: |
20495218 | 118 | val = floatx80_to_float32(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); |
00406dff FB |
119 | break; |
120 | ||
121 | default: val = fpa11->fpreg[Fn].fSingle; | |
122 | } | |
5fafdf24 | 123 | |
53a5960a | 124 | tput32(addr, p[0]); |
5fafdf24 | 125 | } |
00406dff FB |
126 | |
127 | static inline | |
128 | void storeDouble(const unsigned int Fn,unsigned int *pMem) | |
129 | { | |
53a5960a | 130 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
131 | FPA11 *fpa11 = GET_FPA11(); |
132 | float64 val; | |
133 | register unsigned int *p = (unsigned int*)&val; | |
134 | ||
135 | switch (fpa11->fType[Fn]) | |
136 | { | |
5fafdf24 | 137 | case typeSingle: |
20495218 | 138 | val = float32_to_float64(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); |
00406dff FB |
139 | break; |
140 | ||
141 | case typeExtended: | |
20495218 | 142 | val = floatx80_to_float64(fpa11->fpreg[Fn].fExtended, &fpa11->fp_status); |
00406dff FB |
143 | break; |
144 | ||
145 | default: val = fpa11->fpreg[Fn].fDouble; | |
146 | } | |
a8d3431a | 147 | #ifdef WORDS_BIGENDIAN |
53a5960a PB |
148 | tput32(addr, p[0]); /* msw */ |
149 | tput32(addr + 4, p[1]); /* lsw */ | |
a8d3431a | 150 | #else |
53a5960a PB |
151 | tput32(addr, p[1]); /* msw */ |
152 | tput32(addr + 4, p[0]); /* lsw */ | |
a8d3431a | 153 | #endif |
5fafdf24 | 154 | } |
00406dff FB |
155 | |
156 | static inline | |
157 | void storeExtended(const unsigned int Fn,unsigned int *pMem) | |
158 | { | |
53a5960a | 159 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
160 | FPA11 *fpa11 = GET_FPA11(); |
161 | floatx80 val; | |
162 | register unsigned int *p = (unsigned int*)&val; | |
5fafdf24 | 163 | |
00406dff FB |
164 | switch (fpa11->fType[Fn]) |
165 | { | |
5fafdf24 | 166 | case typeSingle: |
20495218 | 167 | val = float32_to_floatx80(fpa11->fpreg[Fn].fSingle, &fpa11->fp_status); |
00406dff FB |
168 | break; |
169 | ||
5fafdf24 | 170 | case typeDouble: |
20495218 | 171 | val = float64_to_floatx80(fpa11->fpreg[Fn].fDouble, &fpa11->fp_status); |
00406dff FB |
172 | break; |
173 | ||
174 | default: val = fpa11->fpreg[Fn].fExtended; | |
175 | } | |
5fafdf24 | 176 | |
53a5960a PB |
177 | tput32(addr, p[0]); /* sign & exp */ |
178 | tput32(addr + 8, p[1]); | |
179 | tput32(addr + 4, p[2]); /* msw */ | |
5fafdf24 | 180 | } |
00406dff FB |
181 | |
182 | static inline | |
183 | void storeMultiple(const unsigned int Fn,unsigned int *pMem) | |
184 | { | |
53a5960a | 185 | target_ulong addr = (target_ulong)(long)pMem; |
00406dff FB |
186 | FPA11 *fpa11 = GET_FPA11(); |
187 | register unsigned int nType, *p; | |
5fafdf24 | 188 | |
00406dff FB |
189 | p = (unsigned int*)&(fpa11->fpreg[Fn]); |
190 | nType = fpa11->fType[Fn]; | |
5fafdf24 | 191 | |
00406dff FB |
192 | switch (nType) |
193 | { | |
194 | case typeSingle: | |
195 | case typeDouble: | |
196 | { | |
53a5960a PB |
197 | tput32(addr + 8, p[0]); /* single */ |
198 | tput32(addr + 4, p[1]); /* double msw */ | |
199 | tput32(addr, nType << 14); | |
00406dff | 200 | } |
5fafdf24 TS |
201 | break; |
202 | ||
00406dff FB |
203 | case typeExtended: |
204 | { | |
53a5960a PB |
205 | tput32(addr + 4, p[2]); /* msw */ |
206 | tput32(addr + 8, p[1]); | |
207 | tput32(addr, (p[0] & 0x80003fff) | (nType << 14)); | |
00406dff FB |
208 | } |
209 | break; | |
210 | } | |
211 | } | |
212 | ||
213 | unsigned int PerformLDF(const unsigned int opcode) | |
214 | { | |
215 | unsigned int *pBase, *pAddress, *pFinal, nRc = 1, | |
216 | write_back = WRITE_BACK(opcode); | |
217 | ||
218 | //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); | |
219 | ||
220 | pBase = (unsigned int*)readRegister(getRn(opcode)); | |
221 | if (REG_PC == getRn(opcode)) | |
222 | { | |
223 | pBase += 2; | |
224 | write_back = 0; | |
225 | } | |
226 | ||
227 | pFinal = pBase; | |
228 | if (BIT_UP_SET(opcode)) | |
229 | pFinal += getOffset(opcode); | |
230 | else | |
231 | pFinal -= getOffset(opcode); | |
232 | ||
233 | if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
234 | ||
235 | switch (opcode & MASK_TRANSFER_LENGTH) | |
236 | { | |
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; | |
240 | default: nRc = 0; | |
241 | } | |
5fafdf24 | 242 | |
00406dff FB |
243 | if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); |
244 | return nRc; | |
245 | } | |
246 | ||
247 | unsigned int PerformSTF(const unsigned int opcode) | |
248 | { | |
249 | unsigned int *pBase, *pAddress, *pFinal, nRc = 1, | |
250 | write_back = WRITE_BACK(opcode); | |
5fafdf24 | 251 | |
00406dff FB |
252 | //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); |
253 | SetRoundingMode(ROUND_TO_NEAREST); | |
5fafdf24 | 254 | |
00406dff FB |
255 | pBase = (unsigned int*)readRegister(getRn(opcode)); |
256 | if (REG_PC == getRn(opcode)) | |
257 | { | |
258 | pBase += 2; | |
259 | write_back = 0; | |
260 | } | |
261 | ||
262 | pFinal = pBase; | |
263 | if (BIT_UP_SET(opcode)) | |
264 | pFinal += getOffset(opcode); | |
265 | else | |
266 | pFinal -= getOffset(opcode); | |
267 | ||
268 | if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
269 | ||
270 | switch (opcode & MASK_TRANSFER_LENGTH) | |
271 | { | |
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; | |
275 | default: nRc = 0; | |
276 | } | |
5fafdf24 | 277 | |
00406dff FB |
278 | if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); |
279 | return nRc; | |
280 | } | |
281 | ||
282 | unsigned int PerformLFM(const unsigned int opcode) | |
283 | { | |
284 | unsigned int i, Fd, *pBase, *pAddress, *pFinal, | |
285 | write_back = WRITE_BACK(opcode); | |
286 | ||
287 | pBase = (unsigned int*)readRegister(getRn(opcode)); | |
288 | if (REG_PC == getRn(opcode)) | |
289 | { | |
290 | pBase += 2; | |
291 | write_back = 0; | |
292 | } | |
293 | ||
294 | pFinal = pBase; | |
295 | if (BIT_UP_SET(opcode)) | |
296 | pFinal += getOffset(opcode); | |
297 | else | |
298 | pFinal -= getOffset(opcode); | |
299 | ||
300 | if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
301 | ||
302 | Fd = getFd(opcode); | |
303 | for (i=getRegisterCount(opcode);i>0;i--) | |
304 | { | |
305 | loadMultiple(Fd,pAddress); | |
306 | pAddress += 3; Fd++; | |
307 | if (Fd == 8) Fd = 0; | |
308 | } | |
309 | ||
310 | if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | |
311 | return 1; | |
312 | } | |
313 | ||
314 | unsigned int PerformSFM(const unsigned int opcode) | |
315 | { | |
316 | unsigned int i, Fd, *pBase, *pAddress, *pFinal, | |
317 | write_back = WRITE_BACK(opcode); | |
5fafdf24 | 318 | |
00406dff FB |
319 | pBase = (unsigned int*)readRegister(getRn(opcode)); |
320 | if (REG_PC == getRn(opcode)) | |
321 | { | |
322 | pBase += 2; | |
323 | write_back = 0; | |
324 | } | |
5fafdf24 | 325 | |
00406dff FB |
326 | pFinal = pBase; |
327 | if (BIT_UP_SET(opcode)) | |
328 | pFinal += getOffset(opcode); | |
329 | else | |
330 | pFinal -= getOffset(opcode); | |
331 | ||
332 | if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; | |
333 | ||
334 | Fd = getFd(opcode); | |
335 | for (i=getRegisterCount(opcode);i>0;i--) | |
336 | { | |
337 | storeMultiple(Fd,pAddress); | |
338 | pAddress += 3; Fd++; | |
339 | if (Fd == 8) Fd = 0; | |
340 | } | |
341 | ||
342 | if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); | |
343 | return 1; | |
344 | } | |
345 | ||
346 | #if 1 | |
347 | unsigned int EmulateCPDT(const unsigned int opcode) | |
348 | { | |
349 | unsigned int nRc = 0; | |
350 | ||
351 | //printk("EmulateCPDT(0x%08x)\n",opcode); | |
5fafdf24 | 352 | |
00406dff FB |
353 | if (LDF_OP(opcode)) |
354 | { | |
355 | nRc = PerformLDF(opcode); | |
356 | } | |
357 | else if (LFM_OP(opcode)) | |
358 | { | |
359 | nRc = PerformLFM(opcode); | |
360 | } | |
361 | else if (STF_OP(opcode)) | |
362 | { | |
363 | nRc = PerformSTF(opcode); | |
5fafdf24 | 364 | } |
00406dff FB |
365 | else if (SFM_OP(opcode)) |
366 | { | |
367 | nRc = PerformSFM(opcode); | |
368 | } | |
369 | else | |
370 | { | |
371 | nRc = 0; | |
372 | } | |
5fafdf24 | 373 | |
00406dff FB |
374 | return nRc; |
375 | } | |
376 | #endif |