Commit | Line | Data |
---|---|---|
f603c8fe NC |
1 | /* maverick.c -- Cirrus/DSP co-processor interface. |
2 | Copyright (C) 2003 Free Software Foundation, Inc. | |
3 | Contributed by Aldy Hernandez (aldyh@redhat.com). | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; if not, write to the Free Software | |
380d9419 | 17 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
f603c8fe NC |
18 | |
19 | #include <assert.h> | |
20 | #include "armdefs.h" | |
21 | #include "ansidecl.h" | |
22 | #include "armemu.h" | |
23 | ||
24 | /*#define CIRRUS_DEBUG 1 /**/ | |
25 | #if CIRRUS_DEBUG | |
26 | # define printfdbg printf | |
27 | #else | |
28 | # define printfdbg printf_nothing | |
29 | #endif | |
30 | ||
31 | #define POS64(i) ( (~(i)) >> 63 ) | |
32 | #define NEG64(i) ( (i) >> 63 ) | |
33 | ||
34 | /* Define Co-Processor instruction handlers here. */ | |
35 | ||
36 | /* Here's ARMulator's DSP definition. A few things to note: | |
37 | 1) it has 16 64-bit registers and 4 72-bit accumulators | |
38 | 2) you can only access its registers with MCR and MRC. */ | |
39 | ||
40 | /* We can't define these in here because this file might not be linked | |
41 | unless the target is arm9e-*. They are defined in wrapper.c. | |
42 | Eventually the simulator should be made to handle any coprocessor | |
43 | at run time. */ | |
44 | struct maverick_regs | |
45 | { | |
46 | union | |
47 | { | |
48 | int i; | |
49 | float f; | |
50 | } upper; | |
51 | ||
52 | union | |
53 | { | |
54 | int i; | |
55 | float f; | |
56 | } lower; | |
57 | }; | |
58 | ||
59 | union maverick_acc_regs | |
60 | { | |
61 | long double ld; /* Acc registers are 72-bits. */ | |
62 | }; | |
63 | ||
64 | struct maverick_regs DSPregs[16]; | |
65 | union maverick_acc_regs DSPacc[4]; | |
66 | ARMword DSPsc; | |
67 | ||
68 | #define DEST_REG (BITS (12, 15)) | |
69 | #define SRC1_REG (BITS (16, 19)) | |
70 | #define SRC2_REG (BITS (0, 3)) | |
71 | ||
72 | static int lsw_int_index, msw_int_index; | |
73 | static int lsw_float_index, msw_float_index; | |
74 | ||
75 | static double mv_getRegDouble (int); | |
76 | static long long mv_getReg64int (int); | |
77 | static void mv_setRegDouble (int, double val); | |
78 | static void mv_setReg64int (int, long long val); | |
79 | ||
80 | static union | |
81 | { | |
82 | double d; | |
83 | long long ll; | |
84 | int ints[2]; | |
85 | } reg_conv; | |
86 | ||
87 | static void | |
88 | printf_nothing (void * foo, ...) | |
89 | { | |
90 | } | |
91 | ||
92 | static void | |
93 | cirrus_not_implemented (char * insn) | |
94 | { | |
95 | fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn); | |
96 | fprintf (stderr, "aborting!\n"); | |
97 | ||
98 | exit (1); | |
99 | } | |
100 | ||
101 | static unsigned | |
102 | DSPInit (ARMul_State * state) | |
103 | { | |
104 | ARMul_ConsolePrint (state, ", DSP present"); | |
105 | return TRUE; | |
106 | } | |
107 | ||
108 | unsigned | |
109 | DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED, | |
110 | unsigned type ATTRIBUTE_UNUSED, | |
111 | ARMword instr, | |
112 | ARMword * value) | |
113 | { | |
114 | switch (BITS (5, 7)) | |
115 | { | |
116 | case 0: /* cfmvrdl */ | |
117 | /* Move lower half of a DF stored in a DSP reg into an Arm reg. */ | |
118 | printfdbg ("cfmvrdl\n"); | |
119 | printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i); | |
120 | printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); | |
121 | ||
122 | *value = (ARMword) DSPregs[SRC1_REG].lower.i; | |
123 | break; | |
124 | ||
125 | case 1: /* cfmvrdh */ | |
126 | /* Move upper half of a DF stored in a DSP reg into an Arm reg. */ | |
127 | printfdbg ("cfmvrdh\n"); | |
128 | printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i); | |
129 | printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG)); | |
130 | ||
131 | *value = (ARMword) DSPregs[SRC1_REG].upper.i; | |
132 | break; | |
133 | ||
134 | case 2: /* cfmvrs */ | |
135 | /* Move SF from upper half of a DSP register to an Arm register. */ | |
136 | *value = (ARMword) DSPregs[SRC1_REG].upper.i; | |
137 | printfdbg ("cfmvrs = mvf%d <-- %f\n", | |
138 | SRC1_REG, | |
139 | DSPregs[SRC1_REG].upper.f); | |
140 | break; | |
141 | ||
142 | #ifdef doesnt_work | |
143 | case 4: /* cfcmps */ | |
144 | { | |
145 | float a, b; | |
146 | int n, z, c, v; | |
147 | ||
148 | a = DSPregs[SRC1_REG].upper.f; | |
149 | b = DSPregs[SRC2_REG].upper.f; | |
150 | ||
151 | printfdbg ("cfcmps\n"); | |
152 | printfdbg ("\tcomparing %f and %f\n", a, b); | |
153 | ||
154 | z = a == b; /* zero */ | |
155 | n = a != b; /* negative */ | |
156 | v = a > b; /* overflow */ | |
157 | c = 0; /* carry */ | |
158 | *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); | |
159 | break; | |
160 | } | |
161 | ||
162 | case 5: /* cfcmpd */ | |
163 | { | |
164 | double a, b; | |
165 | int n, z, c, v; | |
166 | ||
167 | a = mv_getRegDouble (SRC1_REG); | |
168 | b = mv_getRegDouble (SRC2_REG); | |
169 | ||
170 | printfdbg ("cfcmpd\n"); | |
171 | printfdbg ("\tcomparing %g and %g\n", a, b); | |
172 | ||
173 | z = a == b; /* zero */ | |
174 | n = a != b; /* negative */ | |
175 | v = a > b; /* overflow */ | |
176 | c = 0; /* carry */ | |
177 | *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); | |
178 | break; | |
179 | } | |
180 | #else | |
181 | case 4: /* cfcmps */ | |
182 | { | |
183 | float a, b; | |
184 | int n, z, c, v; | |
185 | ||
186 | a = DSPregs[SRC1_REG].upper.f; | |
187 | b = DSPregs[SRC2_REG].upper.f; | |
188 | ||
189 | printfdbg ("cfcmps\n"); | |
190 | printfdbg ("\tcomparing %f and %f\n", a, b); | |
191 | ||
192 | z = a == b; /* zero */ | |
193 | n = a < b; /* negative */ | |
194 | c = a > b; /* carry */ | |
195 | v = 0; /* fixme */ | |
196 | printfdbg ("\tz = %d, n = %d\n", z, n); | |
197 | *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); | |
198 | break; | |
199 | } | |
200 | ||
201 | case 5: /* cfcmpd */ | |
202 | { | |
203 | double a, b; | |
204 | int n, z, c, v; | |
205 | ||
206 | a = mv_getRegDouble (SRC1_REG); | |
207 | b = mv_getRegDouble (SRC2_REG); | |
208 | ||
209 | printfdbg ("cfcmpd\n"); | |
210 | printfdbg ("\tcomparing %g and %g\n", a, b); | |
211 | ||
212 | z = a == b; /* zero */ | |
213 | n = a < b; /* negative */ | |
214 | c = a > b; /* carry */ | |
215 | v = 0; /* fixme */ | |
216 | *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); | |
217 | break; | |
218 | } | |
219 | #endif | |
220 | default: | |
221 | fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr); | |
222 | cirrus_not_implemented ("unknown"); | |
223 | break; | |
224 | } | |
225 | ||
226 | return ARMul_DONE; | |
227 | } | |
228 | ||
229 | unsigned | |
230 | DSPMRC5 (ARMul_State * state ATTRIBUTE_UNUSED, | |
231 | unsigned type ATTRIBUTE_UNUSED, | |
232 | ARMword instr, | |
233 | ARMword * value) | |
234 | { | |
235 | switch (BITS (5, 7)) | |
236 | { | |
237 | case 0: /* cfmvr64l */ | |
238 | /* Move lower half of 64bit int from Cirrus to Arm. */ | |
239 | *value = (ARMword) DSPregs[SRC1_REG].lower.i; | |
240 | printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n", | |
241 | DEST_REG, | |
242 | (int) *value); | |
243 | break; | |
244 | ||
245 | case 1: /* cfmvr64h */ | |
246 | /* Move upper half of 64bit int from Cirrus to Arm. */ | |
247 | *value = (ARMword) DSPregs[SRC1_REG].upper.i; | |
248 | printfdbg ("cfmvr64h <-- %d\n", (int) *value); | |
249 | break; | |
250 | ||
251 | case 4: /* cfcmp32 */ | |
252 | { | |
253 | int res; | |
254 | int n, z, c, v; | |
255 | unsigned int a, b; | |
256 | ||
257 | printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", | |
258 | SRC1_REG, | |
259 | SRC2_REG); | |
260 | ||
261 | /* FIXME: see comment for cfcmps. */ | |
262 | a = DSPregs[SRC1_REG].lower.i; | |
263 | b = DSPregs[SRC2_REG].lower.i; | |
264 | ||
265 | res = DSPregs[SRC1_REG].lower.i - DSPregs[SRC2_REG].lower.i; | |
266 | /* zero */ | |
267 | z = res == 0; | |
268 | /* negative */ | |
269 | n = res < 0; | |
270 | /* overflow */ | |
271 | v = SubOverflow (DSPregs[SRC1_REG].lower.i, DSPregs[SRC2_REG].lower.i, | |
272 | res); | |
273 | /* carry */ | |
274 | c = (NEG (a) && POS (b) || | |
275 | (NEG (a) && POS (res)) || (POS (b) && POS (res))); | |
276 | ||
277 | *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); | |
278 | break; | |
279 | } | |
280 | ||
281 | case 5: /* cfcmp64 */ | |
282 | { | |
283 | long long res; | |
284 | int n, z, c, v; | |
285 | unsigned long long a, b; | |
286 | ||
287 | printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", | |
288 | SRC1_REG, | |
289 | SRC2_REG); | |
290 | ||
291 | /* fixme: see comment for cfcmps. */ | |
292 | ||
293 | a = mv_getReg64int (SRC1_REG); | |
294 | b = mv_getReg64int (SRC2_REG); | |
295 | ||
296 | res = mv_getReg64int (SRC1_REG) - mv_getReg64int (SRC2_REG); | |
297 | /* zero */ | |
298 | z = res == 0; | |
299 | /* negative */ | |
300 | n = res < 0; | |
301 | /* overflow */ | |
302 | v = ((NEG64 (a) && POS64 (b) && POS64 (res)) | |
303 | || (POS64 (a) && NEG64 (b) && NEG64 (res))); | |
304 | /* carry */ | |
305 | c = (NEG64 (a) && POS64 (b) || | |
306 | (NEG64 (a) && POS64 (res)) || (POS64 (b) && POS64 (res))); | |
307 | ||
308 | *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); | |
309 | break; | |
310 | } | |
311 | ||
312 | default: | |
313 | fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr); | |
314 | cirrus_not_implemented ("unknown"); | |
315 | break; | |
316 | } | |
317 | ||
318 | return ARMul_DONE; | |
319 | } | |
320 | ||
321 | unsigned | |
322 | DSPMRC6 (ARMul_State * state ATTRIBUTE_UNUSED, | |
323 | unsigned type ATTRIBUTE_UNUSED, | |
324 | ARMword instr, | |
325 | ARMword * value) | |
326 | { | |
327 | switch (BITS (5, 7)) | |
328 | { | |
329 | case 0: /* cfmval32 */ | |
330 | cirrus_not_implemented ("cfmval32"); | |
331 | break; | |
332 | ||
333 | case 1: /* cfmvam32 */ | |
334 | cirrus_not_implemented ("cfmvam32"); | |
335 | break; | |
336 | ||
337 | case 2: /* cfmvah32 */ | |
338 | cirrus_not_implemented ("cfmvah32"); | |
339 | break; | |
340 | ||
341 | case 3: /* cfmva32 */ | |
342 | cirrus_not_implemented ("cfmva32"); | |
343 | break; | |
344 | ||
345 | case 4: /* cfmva64 */ | |
346 | cirrus_not_implemented ("cfmva64"); | |
347 | break; | |
348 | ||
349 | case 5: /* cfmvsc32 */ | |
350 | cirrus_not_implemented ("cfmvsc32"); | |
351 | break; | |
352 | ||
353 | default: | |
354 | fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr); | |
355 | cirrus_not_implemented ("unknown"); | |
356 | break; | |
357 | } | |
358 | ||
359 | return ARMul_DONE; | |
360 | } | |
361 | ||
362 | unsigned | |
363 | DSPMCR4 (ARMul_State * state, | |
364 | unsigned type ATTRIBUTE_UNUSED, | |
365 | ARMword instr, | |
366 | ARMword value) | |
367 | { | |
368 | switch (BITS (5, 7)) | |
369 | { | |
370 | case 0: /* cfmvdlr */ | |
371 | /* Move the lower half of a DF value from an Arm register into | |
372 | the lower half of a Cirrus register. */ | |
373 | printfdbg ("cfmvdlr <-- 0x%x\n", (int) value); | |
374 | DSPregs[SRC1_REG].lower.i = (int) value; | |
375 | break; | |
376 | ||
377 | case 1: /* cfmvdhr */ | |
378 | /* Move the upper half of a DF value from an Arm register into | |
379 | the upper half of a Cirrus register. */ | |
380 | printfdbg ("cfmvdhr <-- 0x%x\n", (int) value); | |
381 | DSPregs[SRC1_REG].upper.i = (int) value; | |
382 | break; | |
383 | ||
384 | case 2: /* cfmvsr */ | |
385 | /* Move SF from Arm register into upper half of Cirrus register. */ | |
386 | printfdbg ("cfmvsr <-- 0x%x\n", (int) value); | |
387 | DSPregs[SRC1_REG].upper.i = (int) value; | |
388 | break; | |
389 | ||
390 | default: | |
391 | fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr); | |
392 | cirrus_not_implemented ("unknown"); | |
393 | break; | |
394 | } | |
395 | ||
396 | return ARMul_DONE; | |
397 | } | |
398 | ||
399 | unsigned | |
400 | DSPMCR5 (ARMul_State * state, | |
401 | unsigned type ATTRIBUTE_UNUSED, | |
402 | ARMword instr, | |
403 | ARMword value) | |
404 | { | |
405 | union | |
406 | { | |
407 | int s; | |
408 | unsigned int us; | |
409 | } val; | |
410 | ||
411 | switch (BITS (5, 7)) | |
412 | { | |
413 | case 0: /* cfmv64lr */ | |
414 | /* Move lower half of a 64bit int from an ARM register into the | |
415 | lower half of a DSP register and sign extend it. */ | |
416 | printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG, (int) value); | |
417 | DSPregs[SRC1_REG].lower.i = (int) value; | |
418 | break; | |
419 | ||
420 | case 1: /* cfmv64hr */ | |
421 | /* Move upper half of a 64bit int from an ARM register into the | |
422 | upper half of a DSP register. */ | |
423 | printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n", | |
424 | SRC1_REG, | |
425 | (int) value); | |
426 | DSPregs[SRC1_REG].upper.i = (int) value; | |
427 | break; | |
428 | ||
429 | case 2: /* cfrshl32 */ | |
430 | printfdbg ("cfrshl32\n"); | |
431 | val.us = value; | |
432 | if (val.s > 0) | |
433 | DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i << value; | |
434 | else | |
435 | DSPregs[SRC2_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -value; | |
436 | break; | |
437 | ||
438 | case 3: /* cfrshl64 */ | |
439 | printfdbg ("cfrshl64\n"); | |
440 | val.us = value; | |
441 | if (val.s > 0) | |
442 | mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) << value); | |
443 | else | |
444 | mv_setReg64int (SRC2_REG, mv_getReg64int (SRC1_REG) >> -value); | |
445 | break; | |
446 | ||
447 | default: | |
448 | fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr); | |
449 | cirrus_not_implemented ("unknown"); | |
450 | break; | |
451 | } | |
452 | ||
453 | return ARMul_DONE; | |
454 | } | |
455 | ||
456 | unsigned | |
457 | DSPMCR6 (ARMul_State * state, | |
458 | unsigned type ATTRIBUTE_UNUSED, | |
459 | ARMword instr, | |
460 | ARMword value) | |
461 | { | |
462 | switch (BITS (5, 7)) | |
463 | { | |
464 | case 0: /* cfmv32al */ | |
465 | cirrus_not_implemented ("cfmv32al"); | |
466 | break; | |
467 | ||
468 | case 1: /* cfmv32am */ | |
469 | cirrus_not_implemented ("cfmv32am"); | |
470 | break; | |
471 | ||
472 | case 2: /* cfmv32ah */ | |
473 | cirrus_not_implemented ("cfmv32ah"); | |
474 | break; | |
475 | ||
476 | case 3: /* cfmv32a */ | |
477 | cirrus_not_implemented ("cfmv32a"); | |
478 | break; | |
479 | ||
480 | case 4: /* cfmv64a */ | |
481 | cirrus_not_implemented ("cfmv64a"); | |
482 | break; | |
483 | ||
484 | case 5: /* cfmv32sc */ | |
485 | cirrus_not_implemented ("cfmv32sc"); | |
486 | break; | |
487 | ||
488 | default: | |
489 | fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr); | |
490 | cirrus_not_implemented ("unknown"); | |
491 | break; | |
492 | } | |
493 | ||
494 | return ARMul_DONE; | |
495 | } | |
496 | ||
497 | unsigned | |
498 | DSPLDC4 (ARMul_State * state ATTRIBUTE_UNUSED, | |
499 | unsigned type, | |
500 | ARMword instr, | |
501 | ARMword data) | |
502 | { | |
503 | static unsigned words; | |
504 | ||
505 | if (type != ARMul_DATA) | |
506 | { | |
507 | words = 0; | |
508 | return ARMul_DONE; | |
509 | } | |
510 | ||
511 | if (BIT (22)) | |
512 | { /* it's a long access, get two words */ | |
513 | /* cfldrd */ | |
514 | ||
515 | printfdbg ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n", | |
516 | data, words, state->bigendSig, DEST_REG); | |
517 | ||
518 | if (words == 0) | |
519 | { | |
520 | if (state->bigendSig) | |
521 | DSPregs[DEST_REG].upper.i = (int) data; | |
522 | else | |
523 | DSPregs[DEST_REG].lower.i = (int) data; | |
524 | } | |
525 | else | |
526 | { | |
527 | if (state->bigendSig) | |
528 | DSPregs[DEST_REG].lower.i = (int) data; | |
529 | else | |
530 | DSPregs[DEST_REG].upper.i = (int) data; | |
531 | } | |
532 | ||
533 | ++ words; | |
534 | ||
535 | if (words == 2) | |
536 | { | |
537 | printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG, | |
538 | mv_getRegDouble (DEST_REG)); | |
539 | ||
540 | return ARMul_DONE; | |
541 | } | |
542 | else | |
543 | return ARMul_INC; | |
544 | } | |
545 | else | |
546 | { | |
547 | /* Get just one word. */ | |
548 | ||
549 | /* cfldrs */ | |
550 | printfdbg ("cfldrs\n"); | |
551 | ||
552 | DSPregs[DEST_REG].upper.i = (int) data; | |
553 | ||
554 | printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG, | |
555 | DSPregs[DEST_REG].upper.f); | |
556 | ||
557 | return ARMul_DONE; | |
558 | } | |
559 | } | |
560 | ||
561 | unsigned | |
562 | DSPLDC5 (ARMul_State * state ATTRIBUTE_UNUSED, | |
563 | unsigned type, | |
564 | ARMword instr, | |
565 | ARMword data) | |
566 | { | |
567 | static unsigned words; | |
568 | ||
569 | if (type != ARMul_DATA) | |
570 | { | |
571 | words = 0; | |
572 | return ARMul_DONE; | |
573 | } | |
574 | ||
575 | if (BIT (22)) | |
576 | { | |
577 | /* It's a long access, get two words. */ | |
578 | ||
579 | /* cfldr64 */ | |
580 | printfdbg ("cfldr64: %d\n", data); | |
581 | ||
582 | if (words == 0) | |
583 | { | |
584 | if (state->bigendSig) | |
585 | DSPregs[DEST_REG].upper.i = (int) data; | |
586 | else | |
587 | DSPregs[DEST_REG].lower.i = (int) data; | |
588 | } | |
589 | else | |
590 | { | |
591 | if (state->bigendSig) | |
592 | DSPregs[DEST_REG].lower.i = (int) data; | |
593 | else | |
594 | DSPregs[DEST_REG].upper.i = (int) data; | |
595 | } | |
596 | ||
597 | ++ words; | |
598 | ||
599 | if (words == 2) | |
600 | { | |
601 | printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG, | |
602 | mv_getReg64int (DEST_REG)); | |
603 | ||
604 | return ARMul_DONE; | |
605 | } | |
606 | else | |
607 | return ARMul_INC; | |
608 | } | |
609 | else | |
610 | { | |
611 | /* Get just one word. */ | |
612 | ||
613 | /* cfldr32 */ | |
614 | printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data); | |
615 | ||
616 | /* 32bit ints should be sign extended to 64bits when loaded. */ | |
617 | mv_setReg64int (DEST_REG, (long long) data); | |
618 | ||
619 | return ARMul_DONE; | |
620 | } | |
621 | } | |
622 | ||
623 | unsigned | |
624 | DSPSTC4 (ARMul_State * state ATTRIBUTE_UNUSED, | |
625 | unsigned type, | |
626 | ARMword instr, | |
627 | ARMword * data) | |
628 | { | |
629 | static unsigned words; | |
630 | ||
631 | if (type != ARMul_DATA) | |
632 | { | |
633 | words = 0; | |
634 | return ARMul_DONE; | |
635 | } | |
636 | ||
637 | if (BIT (22)) | |
638 | { | |
639 | /* It's a long access, get two words. */ | |
640 | /* cfstrd */ | |
641 | printfdbg ("cfstrd\n"); | |
642 | ||
643 | if (words == 0) | |
644 | { | |
645 | if (state->bigendSig) | |
646 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | |
647 | else | |
648 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | |
649 | } | |
650 | else | |
651 | { | |
652 | if (state->bigendSig) | |
653 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | |
654 | else | |
655 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | |
656 | } | |
657 | ||
658 | ++ words; | |
659 | ||
660 | if (words == 2) | |
661 | { | |
662 | printfdbg ("\tmem = mvd%d = %g\n", DEST_REG, | |
663 | mv_getRegDouble (DEST_REG)); | |
664 | ||
665 | return ARMul_DONE; | |
666 | } | |
667 | else | |
668 | return ARMul_INC; | |
669 | } | |
670 | else | |
671 | { | |
672 | /* Get just one word. */ | |
673 | /* cfstrs */ | |
674 | printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG, | |
675 | DSPregs[DEST_REG].upper.f); | |
676 | ||
677 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | |
678 | ||
679 | return ARMul_DONE; | |
680 | } | |
681 | } | |
682 | ||
683 | unsigned | |
684 | DSPSTC5 (ARMul_State * state ATTRIBUTE_UNUSED, | |
685 | unsigned type, | |
686 | ARMword instr, | |
687 | ARMword * data) | |
688 | { | |
689 | static unsigned words; | |
690 | ||
691 | if (type != ARMul_DATA) | |
692 | { | |
693 | words = 0; | |
694 | return ARMul_DONE; | |
695 | } | |
696 | ||
697 | if (BIT (22)) | |
698 | { | |
699 | /* It's a long access, store two words. */ | |
700 | /* cfstr64 */ | |
701 | printfdbg ("cfstr64\n"); | |
702 | ||
703 | if (words == 0) | |
704 | { | |
705 | if (state->bigendSig) | |
706 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | |
707 | else | |
708 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | |
709 | } | |
710 | else | |
711 | { | |
712 | if (state->bigendSig) | |
713 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | |
714 | else | |
715 | *data = (ARMword) DSPregs[DEST_REG].upper.i; | |
716 | } | |
717 | ||
718 | ++ words; | |
719 | ||
720 | if (words == 2) | |
721 | { | |
722 | printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG, | |
723 | mv_getReg64int (DEST_REG)); | |
724 | ||
725 | return ARMul_DONE; | |
726 | } | |
727 | else | |
728 | return ARMul_INC; | |
729 | } | |
730 | else | |
731 | { | |
732 | /* Store just one word. */ | |
733 | /* cfstr32 */ | |
734 | *data = (ARMword) DSPregs[DEST_REG].lower.i; | |
735 | ||
736 | printfdbg ("cfstr32 MEM = %d\n", (int) *data); | |
737 | ||
738 | return ARMul_DONE; | |
739 | } | |
740 | } | |
741 | ||
742 | unsigned | |
743 | DSPCDP4 (ARMul_State * state, | |
744 | unsigned type, | |
745 | ARMword instr) | |
746 | { | |
747 | int opcode2; | |
748 | ||
749 | opcode2 = BITS (5,7); | |
750 | ||
751 | switch (BITS (20,21)) | |
752 | { | |
753 | case 0: | |
754 | switch (opcode2) | |
755 | { | |
756 | case 0: /* cfcpys */ | |
757 | printfdbg ("cfcpys mvf%d = mvf%d = %f\n", | |
758 | DEST_REG, | |
759 | SRC1_REG, | |
760 | DSPregs[SRC1_REG].upper.f); | |
761 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f; | |
762 | break; | |
763 | ||
764 | case 1: /* cfcpyd */ | |
765 | printfdbg ("cfcpyd mvd%d = mvd%d = %g\n", | |
766 | DEST_REG, | |
767 | SRC1_REG, | |
768 | mv_getRegDouble (SRC1_REG)); | |
769 | mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)); | |
770 | break; | |
771 | ||
772 | case 2: /* cfcvtds */ | |
773 | printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n", | |
774 | DEST_REG, | |
775 | SRC1_REG, | |
776 | (float) mv_getRegDouble (SRC1_REG)); | |
777 | DSPregs[DEST_REG].upper.f = (float) mv_getRegDouble (SRC1_REG); | |
778 | break; | |
779 | ||
780 | case 3: /* cfcvtsd */ | |
781 | printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n", | |
782 | DEST_REG, | |
783 | SRC1_REG, | |
784 | (double) DSPregs[SRC1_REG].upper.f); | |
785 | mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].upper.f); | |
786 | break; | |
787 | ||
788 | case 4: /* cfcvt32s */ | |
789 | printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n", | |
790 | DEST_REG, | |
791 | SRC1_REG, | |
792 | (float) DSPregs[SRC1_REG].lower.i); | |
793 | DSPregs[DEST_REG].upper.f = (float) DSPregs[SRC1_REG].lower.i; | |
794 | break; | |
795 | ||
796 | case 5: /* cfcvt32d */ | |
797 | printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n", | |
798 | DEST_REG, | |
799 | SRC1_REG, | |
800 | (double) DSPregs[SRC1_REG].lower.i); | |
801 | mv_setRegDouble (DEST_REG, (double) DSPregs[SRC1_REG].lower.i); | |
802 | break; | |
803 | ||
804 | case 6: /* cfcvt64s */ | |
805 | printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n", | |
806 | DEST_REG, | |
807 | SRC1_REG, | |
808 | (float) mv_getReg64int (SRC1_REG)); | |
809 | DSPregs[DEST_REG].upper.f = (float) mv_getReg64int (SRC1_REG); | |
810 | break; | |
811 | ||
812 | case 7: /* cfcvt64d */ | |
813 | printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n", | |
814 | DEST_REG, | |
815 | SRC1_REG, | |
816 | (double) mv_getReg64int (SRC1_REG)); | |
817 | mv_setRegDouble (DEST_REG, (double) mv_getReg64int (SRC1_REG)); | |
818 | break; | |
819 | } | |
820 | break; | |
821 | ||
822 | case 1: | |
823 | switch (opcode2) | |
824 | { | |
825 | case 0: /* cfmuls */ | |
826 | printfdbg ("cfmuls mvf%d = mvf%d = %f\n", | |
827 | DEST_REG, | |
828 | SRC1_REG, | |
829 | DSPregs[SRC1_REG].upper.f * DSPregs[SRC2_REG].upper.f); | |
830 | ||
831 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f | |
832 | * DSPregs[SRC2_REG].upper.f; | |
833 | break; | |
834 | ||
835 | case 1: /* cfmuld */ | |
836 | printfdbg ("cfmuld mvd%d = mvd%d = %g\n", | |
837 | DEST_REG, | |
838 | SRC1_REG, | |
839 | mv_getRegDouble (SRC1_REG) * mv_getRegDouble (SRC2_REG)); | |
840 | ||
841 | mv_setRegDouble (DEST_REG, | |
842 | mv_getRegDouble (SRC1_REG) | |
843 | * mv_getRegDouble (SRC2_REG)); | |
844 | break; | |
845 | ||
846 | default: | |
847 | fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); | |
848 | cirrus_not_implemented ("unknown"); | |
849 | break; | |
850 | } | |
851 | break; | |
852 | ||
853 | case 3: | |
854 | switch (opcode2) | |
855 | { | |
856 | case 0: /* cfabss */ | |
857 | DSPregs[DEST_REG].upper.f = (DSPregs[SRC1_REG].upper.f < 0.0F ? | |
858 | -DSPregs[SRC1_REG].upper.f | |
859 | : DSPregs[SRC1_REG].upper.f); | |
860 | printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", | |
861 | DEST_REG, | |
862 | SRC1_REG, | |
863 | DSPregs[DEST_REG].upper.f); | |
864 | break; | |
865 | ||
866 | case 1: /* cfabsd */ | |
867 | mv_setRegDouble (DEST_REG, | |
868 | (mv_getRegDouble (SRC1_REG) < 0.0 ? | |
869 | -mv_getRegDouble (SRC1_REG) | |
870 | : mv_getRegDouble (SRC1_REG))); | |
871 | printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n", | |
872 | DEST_REG, | |
873 | SRC1_REG, | |
874 | mv_getRegDouble (DEST_REG)); | |
875 | break; | |
876 | ||
877 | case 2: /* cfnegs */ | |
878 | DSPregs[DEST_REG].upper.f = -DSPregs[SRC1_REG].upper.f; | |
879 | printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", | |
880 | DEST_REG, | |
881 | SRC1_REG, | |
882 | DSPregs[DEST_REG].upper.f); | |
883 | break; | |
884 | ||
885 | case 3: /* cfnegd */ | |
886 | mv_setRegDouble (DEST_REG, | |
887 | -mv_getRegDouble (SRC1_REG)); | |
888 | printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", | |
889 | DEST_REG, | |
890 | mv_getRegDouble (DEST_REG)); | |
891 | break; | |
892 | ||
893 | case 4: /* cfadds */ | |
894 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f | |
895 | + DSPregs[SRC2_REG].upper.f; | |
896 | printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n", | |
897 | DEST_REG, | |
898 | SRC1_REG, | |
899 | SRC2_REG, | |
900 | DSPregs[DEST_REG].upper.f); | |
901 | break; | |
902 | ||
903 | case 5: /* cfaddd */ | |
904 | mv_setRegDouble (DEST_REG, | |
905 | mv_getRegDouble (SRC1_REG) | |
906 | + mv_getRegDouble (SRC2_REG)); | |
907 | printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n", | |
908 | DEST_REG, | |
909 | SRC1_REG, | |
910 | SRC2_REG, | |
911 | mv_getRegDouble (DEST_REG)); | |
912 | break; | |
913 | ||
914 | case 6: /* cfsubs */ | |
915 | DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f | |
916 | - DSPregs[SRC2_REG].upper.f; | |
917 | printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n", | |
918 | DEST_REG, | |
919 | SRC1_REG, | |
920 | SRC2_REG, | |
921 | DSPregs[DEST_REG].upper.f); | |
922 | break; | |
923 | ||
924 | case 7: /* cfsubd */ | |
925 | mv_setRegDouble (DEST_REG, | |
926 | mv_getRegDouble (SRC1_REG) | |
927 | - mv_getRegDouble (SRC2_REG)); | |
928 | printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n", | |
929 | DEST_REG, | |
930 | SRC1_REG, | |
931 | SRC2_REG, | |
932 | mv_getRegDouble (DEST_REG)); | |
933 | break; | |
934 | } | |
935 | break; | |
936 | ||
937 | default: | |
938 | fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr); | |
939 | cirrus_not_implemented ("unknown"); | |
940 | break; | |
941 | } | |
942 | ||
943 | return ARMul_DONE; | |
944 | } | |
945 | ||
946 | unsigned | |
947 | DSPCDP5 (ARMul_State * state, | |
948 | unsigned type, | |
949 | ARMword instr) | |
950 | { | |
951 | int opcode2; | |
952 | char shift; | |
953 | ||
954 | opcode2 = BITS (5,7); | |
955 | ||
956 | /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */ | |
957 | shift = BITS (0, 3) | (BITS (5, 7)) << 4; | |
958 | if (shift & 0x40) | |
959 | shift |= 0xc0; | |
960 | ||
961 | switch (BITS (20,21)) | |
962 | { | |
963 | case 0: | |
964 | /* cfsh32 */ | |
965 | printfdbg ("cfsh32 %s amount=%d\n", shift < 0 ? "right" : "left", | |
966 | shift); | |
967 | if (shift < 0) | |
968 | /* Negative shift is a right shift. */ | |
969 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i >> -shift; | |
970 | else | |
971 | /* Positive shift is a left shift. */ | |
972 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i << shift; | |
973 | break; | |
974 | ||
975 | case 1: | |
976 | switch (opcode2) | |
977 | { | |
978 | case 0: /* cfmul32 */ | |
979 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i | |
980 | * DSPregs[SRC2_REG].lower.i; | |
981 | printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n", | |
982 | DEST_REG, | |
983 | SRC1_REG, | |
984 | SRC2_REG, | |
985 | DSPregs[DEST_REG].lower.i); | |
986 | break; | |
987 | ||
988 | case 1: /* cfmul64 */ | |
989 | mv_setReg64int (DEST_REG, | |
990 | mv_getReg64int (SRC1_REG) | |
991 | * mv_getReg64int (SRC2_REG)); | |
992 | printfdbg ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n", | |
993 | DEST_REG, | |
994 | SRC1_REG, | |
995 | SRC2_REG, | |
996 | mv_getReg64int (DEST_REG)); | |
997 | break; | |
998 | ||
999 | case 2: /* cfmac32 */ | |
1000 | DSPregs[DEST_REG].lower.i | |
1001 | += DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i; | |
1002 | printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n", | |
1003 | DEST_REG, | |
1004 | SRC1_REG, | |
1005 | SRC2_REG, | |
1006 | DSPregs[DEST_REG].lower.i); | |
1007 | break; | |
1008 | ||
1009 | case 3: /* cfmsc32 */ | |
1010 | DSPregs[DEST_REG].lower.i | |
1011 | -= DSPregs[SRC1_REG].lower.i * DSPregs[SRC2_REG].lower.i; | |
1012 | printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n", | |
1013 | DEST_REG, | |
1014 | SRC1_REG, | |
1015 | SRC2_REG, | |
1016 | DSPregs[DEST_REG].lower.i); | |
1017 | break; | |
1018 | ||
1019 | case 4: /* cfcvts32 */ | |
1020 | /* fixme: this should round */ | |
1021 | DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f; | |
1022 | printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", | |
1023 | DEST_REG, | |
1024 | SRC1_REG, | |
1025 | DSPregs[DEST_REG].lower.i); | |
1026 | break; | |
1027 | ||
1028 | case 5: /* cfcvtd32 */ | |
1029 | /* fixme: this should round */ | |
1030 | DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG); | |
1031 | printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", | |
1032 | DEST_REG, | |
1033 | SRC1_REG, | |
1034 | DSPregs[DEST_REG].lower.i); | |
1035 | break; | |
1036 | ||
1037 | case 6: /* cftruncs32 */ | |
1038 | DSPregs[DEST_REG].lower.i = (int) DSPregs[SRC1_REG].upper.f; | |
1039 | printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n", | |
1040 | DEST_REG, | |
1041 | SRC1_REG, | |
1042 | DSPregs[DEST_REG].lower.i); | |
1043 | break; | |
1044 | ||
1045 | case 7: /* cftruncd32 */ | |
1046 | DSPregs[DEST_REG].lower.i = (int) mv_getRegDouble (SRC1_REG); | |
1047 | printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n", | |
1048 | DEST_REG, | |
1049 | SRC1_REG, | |
1050 | DSPregs[DEST_REG].lower.i); | |
1051 | break; | |
1052 | } | |
1053 | break; | |
1054 | ||
1055 | case 2: | |
1056 | /* cfsh64 */ | |
1057 | printfdbg ("cfsh64\n"); | |
1058 | ||
1059 | if (shift < 0) | |
1060 | /* Negative shift is a right shift. */ | |
1061 | mv_setReg64int (DEST_REG, | |
1062 | mv_getReg64int (SRC1_REG) >> -shift); | |
1063 | else | |
1064 | /* Positive shift is a left shift. */ | |
1065 | mv_setReg64int (DEST_REG, | |
1066 | mv_getReg64int (SRC1_REG) << shift); | |
1067 | printfdbg ("\t%llx\n", mv_getReg64int(DEST_REG)); | |
1068 | break; | |
1069 | ||
1070 | case 3: | |
1071 | switch (opcode2) | |
1072 | { | |
1073 | case 0: /* cfabs32 */ | |
1074 | DSPregs[DEST_REG].lower.i = (DSPregs[SRC1_REG].lower.i < 0 | |
1075 | ? -DSPregs[SRC1_REG].lower.i : DSPregs[SRC1_REG].lower.i); | |
1076 | printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n", | |
1077 | DEST_REG, | |
1078 | SRC1_REG, | |
1079 | SRC2_REG, | |
1080 | DSPregs[DEST_REG].lower.i); | |
1081 | break; | |
1082 | ||
1083 | case 1: /* cfabs64 */ | |
1084 | mv_setReg64int (DEST_REG, | |
1085 | (mv_getReg64int (SRC1_REG) < 0 | |
1086 | ? -mv_getReg64int (SRC1_REG) | |
1087 | : mv_getReg64int (SRC1_REG))); | |
1088 | printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n", | |
1089 | DEST_REG, | |
1090 | SRC1_REG, | |
1091 | SRC2_REG, | |
1092 | mv_getReg64int (DEST_REG)); | |
1093 | break; | |
1094 | ||
1095 | case 2: /* cfneg32 */ | |
1096 | DSPregs[DEST_REG].lower.i = -DSPregs[SRC1_REG].lower.i; | |
1097 | printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n", | |
1098 | DEST_REG, | |
1099 | SRC1_REG, | |
1100 | SRC2_REG, | |
1101 | DSPregs[DEST_REG].lower.i); | |
1102 | break; | |
1103 | ||
1104 | case 3: /* cfneg64 */ | |
1105 | mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG)); | |
1106 | printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n", | |
1107 | DEST_REG, | |
1108 | SRC1_REG, | |
1109 | SRC2_REG, | |
1110 | mv_getReg64int (DEST_REG)); | |
1111 | break; | |
1112 | ||
1113 | case 4: /* cfadd32 */ | |
1114 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i | |
1115 | + DSPregs[SRC2_REG].lower.i; | |
1116 | printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n", | |
1117 | DEST_REG, | |
1118 | SRC1_REG, | |
1119 | SRC2_REG, | |
1120 | DSPregs[DEST_REG].lower.i); | |
1121 | break; | |
1122 | ||
1123 | case 5: /* cfadd64 */ | |
1124 | mv_setReg64int (DEST_REG, | |
1125 | mv_getReg64int (SRC1_REG) | |
1126 | + mv_getReg64int (SRC2_REG)); | |
1127 | printfdbg ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n", | |
1128 | DEST_REG, | |
1129 | SRC1_REG, | |
1130 | SRC2_REG, | |
1131 | mv_getReg64int (DEST_REG)); | |
1132 | break; | |
1133 | ||
1134 | case 6: /* cfsub32 */ | |
1135 | DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i | |
1136 | - DSPregs[SRC2_REG].lower.i; | |
1137 | printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n", | |
1138 | DEST_REG, | |
1139 | SRC1_REG, | |
1140 | SRC2_REG, | |
1141 | DSPregs[DEST_REG].lower.i); | |
1142 | break; | |
1143 | ||
1144 | case 7: /* cfsub64 */ | |
1145 | mv_setReg64int (DEST_REG, | |
1146 | mv_getReg64int (SRC1_REG) | |
1147 | - mv_getReg64int (SRC2_REG)); | |
1148 | printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n", | |
1149 | DEST_REG, | |
1150 | SRC1_REG, | |
1151 | SRC2_REG, | |
1152 | mv_getReg64int (DEST_REG)); | |
1153 | break; | |
1154 | } | |
1155 | break; | |
1156 | ||
1157 | default: | |
1158 | fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr); | |
1159 | cirrus_not_implemented ("unknown"); | |
1160 | break; | |
1161 | } | |
1162 | ||
1163 | return ARMul_DONE; | |
1164 | } | |
1165 | ||
1166 | unsigned | |
1167 | DSPCDP6 (ARMul_State * state, | |
1168 | unsigned type, | |
1169 | ARMword instr) | |
1170 | { | |
1171 | int opcode2; | |
1172 | ||
1173 | opcode2 = BITS (5,7); | |
1174 | ||
1175 | switch (BITS (20,21)) | |
1176 | { | |
1177 | case 0: | |
1178 | /* cfmadd32 */ | |
1179 | cirrus_not_implemented ("cfmadd32"); | |
1180 | break; | |
1181 | ||
1182 | case 1: | |
1183 | /* cfmsub32 */ | |
1184 | cirrus_not_implemented ("cfmsub32"); | |
1185 | break; | |
1186 | ||
1187 | case 2: | |
1188 | /* cfmadda32 */ | |
1189 | cirrus_not_implemented ("cfmadda32"); | |
1190 | break; | |
1191 | ||
1192 | case 3: | |
1193 | /* cfmsuba32 */ | |
1194 | cirrus_not_implemented ("cfmsuba32"); | |
1195 | break; | |
1196 | ||
1197 | default: | |
1198 | fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr); | |
1199 | } | |
1200 | ||
1201 | return ARMul_DONE; | |
1202 | } | |
1203 | ||
1204 | /* Conversion functions. | |
1205 | ||
1206 | 32-bit integers are stored in the LOWER half of a 64-bit physical | |
1207 | register. | |
1208 | ||
1209 | Single precision floats are stored in the UPPER half of a 64-bit | |
1210 | physical register. */ | |
1211 | ||
1212 | static double | |
1213 | mv_getRegDouble (int regnum) | |
1214 | { | |
1215 | reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i; | |
1216 | reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i; | |
1217 | return reg_conv.d; | |
1218 | } | |
1219 | ||
1220 | static void | |
1221 | mv_setRegDouble (int regnum, double val) | |
1222 | { | |
1223 | reg_conv.d = val; | |
1224 | DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index]; | |
1225 | DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index]; | |
1226 | } | |
1227 | ||
1228 | static long long | |
1229 | mv_getReg64int (int regnum) | |
1230 | { | |
1231 | reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i; | |
1232 | reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i; | |
1233 | return reg_conv.ll; | |
1234 | } | |
1235 | ||
1236 | static void | |
1237 | mv_setReg64int (int regnum, long long val) | |
1238 | { | |
1239 | reg_conv.ll = val; | |
1240 | DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index]; | |
1241 | DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index]; | |
1242 | } | |
1243 | ||
1244 | /* Compute LSW in a double and a long long. */ | |
1245 | ||
1246 | void | |
1247 | mv_compute_host_endianness (ARMul_State * state) | |
1248 | { | |
1249 | static union | |
1250 | { | |
1251 | long long ll; | |
1252 | long ints[2]; | |
1253 | long i; | |
1254 | double d; | |
1255 | float floats[2]; | |
1256 | float f; | |
1257 | } conv; | |
1258 | ||
1259 | /* Calculate where's the LSW in a 64bit int. */ | |
1260 | conv.ll = 45; | |
1261 | ||
1262 | if (conv.ints[0] == 0) | |
1263 | { | |
1264 | msw_int_index = 0; | |
1265 | lsw_int_index = 1; | |
1266 | } | |
1267 | else | |
1268 | { | |
1269 | assert (conv.ints[1] == 0); | |
1270 | msw_int_index = 1; | |
1271 | lsw_int_index = 0; | |
1272 | } | |
1273 | ||
1274 | /* Calculate where's the LSW in a double. */ | |
1275 | conv.d = 3.0; | |
1276 | ||
1277 | if (conv.ints[0] == 0) | |
1278 | { | |
1279 | msw_float_index = 0; | |
1280 | lsw_float_index = 1; | |
1281 | } | |
1282 | else | |
1283 | { | |
1284 | assert (conv.ints[1] == 0); | |
1285 | msw_float_index = 1; | |
1286 | lsw_float_index = 0; | |
1287 | } | |
1288 | ||
1289 | printfdbg ("lsw_int_index %d\n", lsw_int_index); | |
1290 | printfdbg ("lsw_float_index %d\n", lsw_float_index); | |
1291 | } |