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