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