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