1/* maverick.c -- Cirrus/DSP co-processor interface. 2 Copyright (C) 2003-2023 Free Software Foundation, Inc. 3 Contributed by Aldy Hernandez (aldyh@redhat.com). 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 17 18/* This must come before any other includes. */ 19#include "defs.h" 20 21#include <assert.h> 22#include "armdefs.h" 23#include "ansidecl.h" 24#include "armemu.h" 25#include "maverick.h" 26 27/*#define CIRRUS_DEBUG 1 */ 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 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. */ 41struct maverick_regs DSPregs[16]; 42union maverick_acc_regs DSPacc[4]; 43ARMword DSPsc; 44 45#define DEST_REG (BITS (12, 15)) 46#define SRC1_REG (BITS (16, 19)) 47#define SRC2_REG (BITS (0, 3)) 48 49static int lsw_int_index, msw_int_index; 50static int lsw_float_index, msw_float_index; 51 52static double mv_getRegDouble (int); 53static long long mv_getReg64int (int); 54static void mv_setRegDouble (int, double val); 55static void mv_setReg64int (int, long long val); 56 57static union 58{ 59 double d; 60 long long ll; 61 int ints[2]; 62} reg_conv; 63 64static void 65printf_nothing (void * foo, ...) 66{ 67} 68 69static void 70cirrus_not_implemented (char * insn) 71{ 72 fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn); 73 fprintf (stderr, "aborting!\n"); 74 75 exit (1); 76} 77 78unsigned 79DSPMRC4 (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)); 91 92 *value = (ARMword) DSPregs[SRC1_REG].lower.i; 93 break; 94 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)); 100 101 *value = (ARMword) DSPregs[SRC1_REG].upper.i; 102 break; 103 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; 111 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 } 131 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; 158 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); 178 179 printfdbg ("cfcmpd\n"); 180 printfdbg ("\tcomparing %g and %g\n", a, b); 181 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 199unsigned 200DSPMRC5 (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; 214 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; 220 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 */ 244 c = (NEG (a) && POS (b)) 245 || (NEG (a) && POS (res)) 246 || (POS (b) && POS (res)); 247 248 *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); 249 break; 250 } 251 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 */ 276 c = (NEG64 (a) && POS64 (b)) 277 || (NEG64 (a) && POS64 (res)) 278 || (POS64 (b) && POS64 (res)); 279 280 *value = (n << 31) | (z << 30) | (c << 29) | (v << 28); 281 break; 282 } 283 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 293unsigned 294DSPMRC6 (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; 304 305 case 1: /* cfmvam32 */ 306 cirrus_not_implemented ("cfmvam32"); 307 break; 308 309 case 2: /* cfmvah32 */ 310 cirrus_not_implemented ("cfmvah32"); 311 break; 312 313 case 3: /* cfmva32 */ 314 cirrus_not_implemented ("cfmva32"); 315 break; 316 317 case 4: /* cfmva64 */ 318 cirrus_not_implemented ("cfmva64"); 319 break; 320 321 case 5: /* cfmvsc32 */ 322 cirrus_not_implemented ("cfmvsc32"); 323 break; 324 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 334unsigned 335DSPMCR4 (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; 348 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; 355 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; 361 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 371unsigned 372DSPMCR5 (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; 391 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; 400 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; 409 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; 418 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 428unsigned 429DSPMCR6 (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; 439 440 case 1: /* cfmv32am */ 441 cirrus_not_implemented ("cfmv32am"); 442 break; 443 444 case 2: /* cfmv32ah */ 445 cirrus_not_implemented ("cfmv32ah"); 446 break; 447 448 case 3: /* cfmv32a */ 449 cirrus_not_implemented ("cfmv32a"); 450 break; 451 452 case 4: /* cfmv64a */ 453 cirrus_not_implemented ("cfmv64a"); 454 break; 455 456 case 5: /* cfmv32sc */ 457 cirrus_not_implemented ("cfmv32sc"); 458 break; 459 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 469unsigned 470DSPLDC4 (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 } 482 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); 489 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 } 504 505 ++ words; 506 507 if (words == 2) 508 { 509 printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG, 510 mv_getRegDouble (DEST_REG)); 511 512 return ARMul_DONE; 513 } 514 else 515 return ARMul_INC; 516 } 517 else 518 { 519 /* Get just one word. */ 520 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 533unsigned 534DSPLDC5 (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 } 546 547 if (BIT (22)) 548 { 549 /* It's a long access, get two words. */ 550 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 } 568 569 ++ words; 570 571 if (words == 2) 572 { 573 printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG, 574 mv_getReg64int (DEST_REG)); 575 576 return ARMul_DONE; 577 } 578 else 579 return ARMul_INC; 580 } 581 else 582 { 583 /* Get just one word. */ 584 585 /* cfldr32 */ 586 printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data); 587 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 595unsigned 596DSPSTC4 (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 } 608 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 } 629 630 ++ words; 631 632 if (words == 2) 633 { 634 printfdbg ("\tmem = mvd%d = %g\n", DEST_REG, 635 mv_getRegDouble (DEST_REG)); 636 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 655unsigned 656DSPSTC5 (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 } 668 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 } 689 690 ++ words; 691 692 if (words == 2) 693 { 694 printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG, 695 mv_getReg64int (DEST_REG)); 696 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; 707 708 printfdbg ("cfstr32 MEM = %d\n", (int) *data); 709 710 return ARMul_DONE; 711 } 712} 713 714unsigned 715DSPCDP4 (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; 735 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; 743 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; 751 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; 759 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; 767 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; 775 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; 783 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); 802 803 DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f 804 * DSPregs[SRC2_REG].upper.f; 805 break; 806 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; 817 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; 837 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; 848 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; 856 857 case 3: /* cfnegd */ 858 mv_setRegDouble (DEST_REG, 859 -mv_getRegDouble (SRC1_REG)); 860 printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", 861 DEST_REG, DEST_REG, 862 mv_getRegDouble (DEST_REG)); 863 break; 864 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; 874 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; 885 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; 895 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 918unsigned 919DSPCDP5 (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; 959 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; 970 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; 980 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; 990 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; 999 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; 1008 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; 1016 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"); 1030 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; 1054 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; 1066 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; 1075 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; 1084 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; 1094 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; 1105 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; 1115 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 1138unsigned 1139DSPCDP6 (ARMul_State * state, 1140 unsigned type, 1141 ARMword instr) 1142{ 1143 switch (BITS (20,21)) 1144 { 1145 case 0: 1146 /* cfmadd32 */ 1147 cirrus_not_implemented ("cfmadd32"); 1148 break; 1149 1150 case 1: 1151 /* cfmsub32 */ 1152 cirrus_not_implemented ("cfmsub32"); 1153 break; 1154 1155 case 2: 1156 /* cfmadda32 */ 1157 cirrus_not_implemented ("cfmadda32"); 1158 break; 1159 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 1180static double 1181mv_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 1188static void 1189mv_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 1196static long long 1197mv_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 1204static void 1205mv_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} 1211