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