|
|
@@ -0,0 +1,1206 @@
|
|
|
+/* maverick.c -- Cirrus/DSP co-processor interface.
|
|
|
+ Copyright (C) 2003 Free Software Foundation, Inc.
|
|
|
+ Contributed by Aldy Hernandez (aldyh@redhat.com).
|
|
|
+
|
|
|
+ This program is free software; you can redistribute it and/or modify
|
|
|
+ it under the terms of the GNU General Public License as published by
|
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
|
+ (at your option) any later version.
|
|
|
+
|
|
|
+ This program is distributed in the hope that it will be useful,
|
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ GNU General Public License for more details.
|
|
|
+
|
|
|
+ You should have received a copy of the GNU General Public License
|
|
|
+ along with this program; if not, write to the Free Software
|
|
|
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
|
+
|
|
|
+#include <assert.h>
|
|
|
+
|
|
|
+#include "core/arm/interpreter/armdefs.h"
|
|
|
+#include "core/arm/interpreter/armemu.h"
|
|
|
+
|
|
|
+
|
|
|
+/*#define CIRRUS_DEBUG 1 */
|
|
|
+#if CIRRUS_DEBUG
|
|
|
+# define printfdbg printf
|
|
|
+#else
|
|
|
+# define printfdbg printf_nothing
|
|
|
+#endif
|
|
|
+
|
|
|
+#define POS64(i) ( (~(i)) >> 63 )
|
|
|
+#define NEG64(i) ( (i) >> 63 )
|
|
|
+
|
|
|
+/* Define Co-Processor instruction handlers here. */
|
|
|
+
|
|
|
+/* Here's ARMulator's DSP definition. A few things to note:
|
|
|
+ 1) it has 16 64-bit registers and 4 72-bit accumulators
|
|
|
+ 2) you can only access its registers with MCR and MRC. */
|
|
|
+
|
|
|
+/* We can't define these in here because this file might not be linked
|
|
|
+ unless the target is arm9e-*. They are defined in wrapper.c.
|
|
|
+ Eventually the simulator should be made to handle any coprocessor
|
|
|
+ at run time. */
|
|
|
+struct maverick_regs
|
|
|
+{
|
|
|
+ union
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ float f;
|
|
|
+ } upper;
|
|
|
+
|
|
|
+ union
|
|
|
+ {
|
|
|
+ int i;
|
|
|
+ float f;
|
|
|
+ } lower;
|
|
|
+};
|
|
|
+
|
|
|
+union maverick_acc_regs
|
|
|
+{
|
|
|
+ long double ld; /* Acc registers are 72-bits. */
|
|
|
+};
|
|
|
+
|
|
|
+struct maverick_regs DSPregs[16];
|
|
|
+union maverick_acc_regs DSPacc[4];
|
|
|
+ARMword DSPsc;
|
|
|
+
|
|
|
+#define DEST_REG (BITS (12, 15))
|
|
|
+#define SRC1_REG (BITS (16, 19))
|
|
|
+#define SRC2_REG (BITS (0, 3))
|
|
|
+
|
|
|
+static int lsw_int_index, msw_int_index;
|
|
|
+static int lsw_float_index, msw_float_index;
|
|
|
+
|
|
|
+static double mv_getRegDouble (int);
|
|
|
+static long long mv_getReg64int (int);
|
|
|
+static void mv_setRegDouble (int, double val);
|
|
|
+static void mv_setReg64int (int, long long val);
|
|
|
+
|
|
|
+static union
|
|
|
+{
|
|
|
+ double d;
|
|
|
+ long long ll;
|
|
|
+ int ints[2];
|
|
|
+} reg_conv;
|
|
|
+
|
|
|
+static void
|
|
|
+printf_nothing (void *foo, ...)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+cirrus_not_implemented (char *insn)
|
|
|
+{
|
|
|
+ fprintf (stderr, "Cirrus instruction '%s' not implemented.\n", insn);
|
|
|
+ fprintf (stderr, "aborting!\n");
|
|
|
+
|
|
|
+ // skyeye_exit (1);
|
|
|
+}
|
|
|
+
|
|
|
+static unsigned
|
|
|
+DSPInit (ARMul_State * state)
|
|
|
+{
|
|
|
+ NOTICE_LOG(ARM11, "ARMul_ConsolePrint: DSP present");
|
|
|
+ return TRUE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPMRC4 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword * value)
|
|
|
+{
|
|
|
+ switch (BITS (5, 7)) {
|
|
|
+ case 0: /* cfmvrdl */
|
|
|
+ /* Move lower half of a DF stored in a DSP reg into an Arm reg. */
|
|
|
+ printfdbg ("cfmvrdl\n");
|
|
|
+ printfdbg ("\tlower half=0x%x\n", DSPregs[SRC1_REG].lower.i);
|
|
|
+ printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
|
|
|
+
|
|
|
+ *value = (ARMword) DSPregs[SRC1_REG].lower.i;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmvrdh */
|
|
|
+ /* Move upper half of a DF stored in a DSP reg into an Arm reg. */
|
|
|
+ printfdbg ("cfmvrdh\n");
|
|
|
+ printfdbg ("\tupper half=0x%x\n", DSPregs[SRC1_REG].upper.i);
|
|
|
+ printfdbg ("\tentire thing=%g\n", mv_getRegDouble (SRC1_REG));
|
|
|
+
|
|
|
+ *value = (ARMword) DSPregs[SRC1_REG].upper.i;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfmvrs */
|
|
|
+ /* Move SF from upper half of a DSP register to an Arm register. */
|
|
|
+ *value = (ARMword) DSPregs[SRC1_REG].upper.i;
|
|
|
+ printfdbg ("cfmvrs = mvf%d <-- %f\n",
|
|
|
+ SRC1_REG, DSPregs[SRC1_REG].upper.f);
|
|
|
+ break;
|
|
|
+
|
|
|
+#ifdef doesnt_work
|
|
|
+ case 4: /* cfcmps */
|
|
|
+ {
|
|
|
+ float a, b;
|
|
|
+ int n, z, c, v;
|
|
|
+
|
|
|
+ a = DSPregs[SRC1_REG].upper.f;
|
|
|
+ b = DSPregs[SRC2_REG].upper.f;
|
|
|
+
|
|
|
+ printfdbg ("cfcmps\n");
|
|
|
+ printfdbg ("\tcomparing %f and %f\n", a, b);
|
|
|
+
|
|
|
+ z = a == b; /* zero */
|
|
|
+ n = a != b; /* negative */
|
|
|
+ v = a > b; /* overflow */
|
|
|
+ c = 0; /* carry */
|
|
|
+ *value = (n << 31) | (z << 30) | (c << 29) | (v <<
|
|
|
+ 28);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 5: /* cfcmpd */
|
|
|
+ {
|
|
|
+ double a, b;
|
|
|
+ int n, z, c, v;
|
|
|
+
|
|
|
+ a = mv_getRegDouble (SRC1_REG);
|
|
|
+ b = mv_getRegDouble (SRC2_REG);
|
|
|
+
|
|
|
+ printfdbg ("cfcmpd\n");
|
|
|
+ printfdbg ("\tcomparing %g and %g\n", a, b);
|
|
|
+
|
|
|
+ z = a == b; /* zero */
|
|
|
+ n = a != b; /* negative */
|
|
|
+ v = a > b; /* overflow */
|
|
|
+ c = 0; /* carry */
|
|
|
+ *value = (n << 31) | (z << 30) | (c << 29) | (v <<
|
|
|
+ 28);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+#else
|
|
|
+ case 4: /* cfcmps */
|
|
|
+ {
|
|
|
+ float a, b;
|
|
|
+ int n, z, c, v;
|
|
|
+
|
|
|
+ a = DSPregs[SRC1_REG].upper.f;
|
|
|
+ b = DSPregs[SRC2_REG].upper.f;
|
|
|
+
|
|
|
+ printfdbg ("cfcmps\n");
|
|
|
+ printfdbg ("\tcomparing %f and %f\n", a, b);
|
|
|
+
|
|
|
+ z = a == b; /* zero */
|
|
|
+ n = a < b; /* negative */
|
|
|
+ c = a > b; /* carry */
|
|
|
+ v = 0; /* fixme */
|
|
|
+ printfdbg ("\tz = %d, n = %d\n", z, n);
|
|
|
+ *value = (n << 31) | (z << 30) | (c << 29) | (v <<
|
|
|
+ 28);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 5: /* cfcmpd */
|
|
|
+ {
|
|
|
+ double a, b;
|
|
|
+ int n, z, c, v;
|
|
|
+
|
|
|
+ a = mv_getRegDouble (SRC1_REG);
|
|
|
+ b = mv_getRegDouble (SRC2_REG);
|
|
|
+
|
|
|
+ printfdbg ("cfcmpd\n");
|
|
|
+ printfdbg ("\tcomparing %g and %g\n", a, b);
|
|
|
+
|
|
|
+ z = a == b; /* zero */
|
|
|
+ n = a < b; /* negative */
|
|
|
+ c = a > b; /* carry */
|
|
|
+ v = 0; /* fixme */
|
|
|
+ *value = (n << 31) | (z << 30) | (c << 29) | (v <<
|
|
|
+ 28);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPMRC4 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPMRC5 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword * value)
|
|
|
+{
|
|
|
+ switch (BITS (5, 7)) {
|
|
|
+ case 0: /* cfmvr64l */
|
|
|
+ /* Move lower half of 64bit int from Cirrus to Arm. */
|
|
|
+ *value = (ARMword) DSPregs[SRC1_REG].lower.i;
|
|
|
+ printfdbg ("cfmvr64l ARM_REG = mvfx%d <-- %d\n",
|
|
|
+ DEST_REG, (int) *value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmvr64h */
|
|
|
+ /* Move upper half of 64bit int from Cirrus to Arm. */
|
|
|
+ *value = (ARMword) DSPregs[SRC1_REG].upper.i;
|
|
|
+ printfdbg ("cfmvr64h <-- %d\n", (int) *value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfcmp32 */
|
|
|
+ {
|
|
|
+ int res;
|
|
|
+ int n, z, c, v;
|
|
|
+ unsigned int a, b;
|
|
|
+
|
|
|
+ printfdbg ("cfcmp32 mvfx%d - mvfx%d\n", SRC1_REG,
|
|
|
+ SRC2_REG);
|
|
|
+
|
|
|
+ /* FIXME: see comment for cfcmps. */
|
|
|
+ a = DSPregs[SRC1_REG].lower.i;
|
|
|
+ b = DSPregs[SRC2_REG].lower.i;
|
|
|
+
|
|
|
+ res = DSPregs[SRC1_REG].lower.i -
|
|
|
+ DSPregs[SRC2_REG].lower.i;
|
|
|
+ /* zero */
|
|
|
+ z = res == 0;
|
|
|
+ /* negative */
|
|
|
+ n = res < 0;
|
|
|
+ /* overflow */
|
|
|
+ v = SubOverflow (DSPregs[SRC1_REG].lower.i,
|
|
|
+ DSPregs[SRC2_REG].lower.i, res);
|
|
|
+ /* carry */
|
|
|
+ c = (NEG (a) && POS (b) ||
|
|
|
+ (NEG (a) && POS (res)) || (POS (b)
|
|
|
+ && POS (res)));
|
|
|
+
|
|
|
+ *value = (n << 31) | (z << 30) | (c << 29) | (v <<
|
|
|
+ 28);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 5: /* cfcmp64 */
|
|
|
+ {
|
|
|
+ long long res;
|
|
|
+ int n, z, c, v;
|
|
|
+ unsigned long long a, b;
|
|
|
+
|
|
|
+ printfdbg ("cfcmp64 mvdx%d - mvdx%d\n", SRC1_REG,
|
|
|
+ SRC2_REG);
|
|
|
+
|
|
|
+ /* fixme: see comment for cfcmps. */
|
|
|
+
|
|
|
+ a = mv_getReg64int (SRC1_REG);
|
|
|
+ b = mv_getReg64int (SRC2_REG);
|
|
|
+
|
|
|
+ res = mv_getReg64int (SRC1_REG) -
|
|
|
+ mv_getReg64int (SRC2_REG);
|
|
|
+ /* zero */
|
|
|
+ z = res == 0;
|
|
|
+ /* negative */
|
|
|
+ n = res < 0;
|
|
|
+ /* overflow */
|
|
|
+ v = ((NEG64 (a) && POS64 (b) && POS64 (res))
|
|
|
+ || (POS64 (a) && NEG64 (b) && NEG64 (res)));
|
|
|
+ /* carry */
|
|
|
+ c = (NEG64 (a) && POS64 (b) ||
|
|
|
+ (NEG64 (a) && POS64 (res)) || (POS64 (b)
|
|
|
+ && POS64 (res)));
|
|
|
+
|
|
|
+ *value = (n << 31) | (z << 30) | (c << 29) | (v <<
|
|
|
+ 28);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPMRC5 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPMRC6 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword * value)
|
|
|
+{
|
|
|
+ switch (BITS (5, 7)) {
|
|
|
+ case 0: /* cfmval32 */
|
|
|
+ cirrus_not_implemented ("cfmval32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmvam32 */
|
|
|
+ cirrus_not_implemented ("cfmvam32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfmvah32 */
|
|
|
+ cirrus_not_implemented ("cfmvah32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfmva32 */
|
|
|
+ cirrus_not_implemented ("cfmva32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfmva64 */
|
|
|
+ cirrus_not_implemented ("cfmva64");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: /* cfmvsc32 */
|
|
|
+ cirrus_not_implemented ("cfmvsc32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPMRC6 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPMCR4 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword value)
|
|
|
+{
|
|
|
+ switch (BITS (5, 7)) {
|
|
|
+ case 0: /* cfmvdlr */
|
|
|
+ /* Move the lower half of a DF value from an Arm register into
|
|
|
+ the lower half of a Cirrus register. */
|
|
|
+ printfdbg ("cfmvdlr <-- 0x%x\n", (int) value);
|
|
|
+ DSPregs[SRC1_REG].lower.i = (int) value;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmvdhr */
|
|
|
+ /* Move the upper half of a DF value from an Arm register into
|
|
|
+ the upper half of a Cirrus register. */
|
|
|
+ printfdbg ("cfmvdhr <-- 0x%x\n", (int) value);
|
|
|
+ DSPregs[SRC1_REG].upper.i = (int) value;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfmvsr */
|
|
|
+ /* Move SF from Arm register into upper half of Cirrus register. */
|
|
|
+ printfdbg ("cfmvsr <-- 0x%x\n", (int) value);
|
|
|
+ DSPregs[SRC1_REG].upper.i = (int) value;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPMCR4 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPMCR5 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword value)
|
|
|
+{
|
|
|
+ union
|
|
|
+ {
|
|
|
+ int s;
|
|
|
+ unsigned int us;
|
|
|
+ } val;
|
|
|
+
|
|
|
+ switch (BITS (5, 7)) {
|
|
|
+ case 0: /* cfmv64lr */
|
|
|
+ /* Move lower half of a 64bit int from an ARM register into the
|
|
|
+ lower half of a DSP register and sign extend it. */
|
|
|
+ printfdbg ("cfmv64lr mvdx%d <-- 0x%x\n", SRC1_REG,
|
|
|
+ (int) value);
|
|
|
+ DSPregs[SRC1_REG].lower.i = (int) value;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmv64hr */
|
|
|
+ /* Move upper half of a 64bit int from an ARM register into the
|
|
|
+ upper half of a DSP register. */
|
|
|
+ printfdbg ("cfmv64hr ARM_REG = mvfx%d <-- 0x%x\n",
|
|
|
+ SRC1_REG, (int) value);
|
|
|
+ DSPregs[SRC1_REG].upper.i = (int) value;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfrshl32 */
|
|
|
+ printfdbg ("cfrshl32\n");
|
|
|
+ val.us = value;
|
|
|
+ if (val.s > 0)
|
|
|
+ DSPregs[SRC2_REG].lower.i =
|
|
|
+ DSPregs[SRC1_REG].lower.i << value;
|
|
|
+ else
|
|
|
+ DSPregs[SRC2_REG].lower.i =
|
|
|
+ DSPregs[SRC1_REG].lower.i >> -value;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfrshl64 */
|
|
|
+ printfdbg ("cfrshl64\n");
|
|
|
+ val.us = value;
|
|
|
+ if (val.s > 0)
|
|
|
+ mv_setReg64int (SRC2_REG,
|
|
|
+ mv_getReg64int (SRC1_REG) << value);
|
|
|
+ else
|
|
|
+ mv_setReg64int (SRC2_REG,
|
|
|
+ mv_getReg64int (SRC1_REG) >> -value);
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPMCR5 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPMCR6 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword value)
|
|
|
+{
|
|
|
+ switch (BITS (5, 7)) {
|
|
|
+ case 0: /* cfmv32al */
|
|
|
+ cirrus_not_implemented ("cfmv32al");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmv32am */
|
|
|
+ cirrus_not_implemented ("cfmv32am");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfmv32ah */
|
|
|
+ cirrus_not_implemented ("cfmv32ah");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfmv32a */
|
|
|
+ cirrus_not_implemented ("cfmv32a");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfmv64a */
|
|
|
+ cirrus_not_implemented ("cfmv64a");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: /* cfmv32sc */
|
|
|
+ cirrus_not_implemented ("cfmv32sc");
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPMCR6 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPLDC4 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword data)
|
|
|
+{
|
|
|
+ static unsigned words;
|
|
|
+
|
|
|
+ if (type != ARMul_DATA) {
|
|
|
+ words = 0;
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BIT (22)) { /* it's a long access, get two words */
|
|
|
+ /* cfldrd */
|
|
|
+
|
|
|
+ printfdbg
|
|
|
+ ("cfldrd: %x (words = %d) (bigend = %d) DESTREG = %d\n",
|
|
|
+ data, words, state->bigendSig, DEST_REG);
|
|
|
+
|
|
|
+ if (words == 0) {
|
|
|
+ if (state->bigendSig)
|
|
|
+ DSPregs[DEST_REG].upper.i = (int) data;
|
|
|
+ else
|
|
|
+ DSPregs[DEST_REG].lower.i = (int) data;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (state->bigendSig)
|
|
|
+ DSPregs[DEST_REG].lower.i = (int) data;
|
|
|
+ else
|
|
|
+ DSPregs[DEST_REG].upper.i = (int) data;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++words;
|
|
|
+
|
|
|
+ if (words == 2) {
|
|
|
+ printfdbg ("\tmvd%d <-- mem = %g\n", DEST_REG,
|
|
|
+ mv_getRegDouble (DEST_REG));
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return ARMul_INC;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ /* Get just one word. */
|
|
|
+
|
|
|
+ /* cfldrs */
|
|
|
+ printfdbg ("cfldrs\n");
|
|
|
+
|
|
|
+ DSPregs[DEST_REG].upper.i = (int) data;
|
|
|
+
|
|
|
+ printfdbg ("\tmvf%d <-- mem = %f\n", DEST_REG,
|
|
|
+ DSPregs[DEST_REG].upper.f);
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPLDC5 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword data)
|
|
|
+{
|
|
|
+ static unsigned words;
|
|
|
+
|
|
|
+ if (type != ARMul_DATA) {
|
|
|
+ words = 0;
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BIT (22)) {
|
|
|
+ /* It's a long access, get two words. */
|
|
|
+
|
|
|
+ /* cfldr64 */
|
|
|
+ printfdbg ("cfldr64: %d\n", data);
|
|
|
+
|
|
|
+ if (words == 0) {
|
|
|
+ if (state->bigendSig)
|
|
|
+ DSPregs[DEST_REG].upper.i = (int) data;
|
|
|
+ else
|
|
|
+ DSPregs[DEST_REG].lower.i = (int) data;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (state->bigendSig)
|
|
|
+ DSPregs[DEST_REG].lower.i = (int) data;
|
|
|
+ else
|
|
|
+ DSPregs[DEST_REG].upper.i = (int) data;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++words;
|
|
|
+
|
|
|
+ if (words == 2) {
|
|
|
+ printfdbg ("\tmvdx%d <-- mem = %lld\n", DEST_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return ARMul_INC;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ /* Get just one word. */
|
|
|
+
|
|
|
+ /* cfldr32 */
|
|
|
+ printfdbg ("cfldr32 mvfx%d <-- %d\n", DEST_REG, (int) data);
|
|
|
+
|
|
|
+ /* 32bit ints should be sign extended to 64bits when loaded. */
|
|
|
+ mv_setReg64int (DEST_REG, (long long) data);
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPSTC4 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword * data)
|
|
|
+{
|
|
|
+ static unsigned words;
|
|
|
+
|
|
|
+ if (type != ARMul_DATA) {
|
|
|
+ words = 0;
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BIT (22)) {
|
|
|
+ /* It's a long access, get two words. */
|
|
|
+ /* cfstrd */
|
|
|
+ printfdbg ("cfstrd\n");
|
|
|
+
|
|
|
+ if (words == 0) {
|
|
|
+ if (state->bigendSig)
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].upper.i;
|
|
|
+ else
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].lower.i;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (state->bigendSig)
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].lower.i;
|
|
|
+ else
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].upper.i;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++words;
|
|
|
+
|
|
|
+ if (words == 2) {
|
|
|
+ printfdbg ("\tmem = mvd%d = %g\n", DEST_REG,
|
|
|
+ mv_getRegDouble (DEST_REG));
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return ARMul_INC;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ /* Get just one word. */
|
|
|
+ /* cfstrs */
|
|
|
+ printfdbg ("cfstrs mvf%d <-- %f\n", DEST_REG,
|
|
|
+ DSPregs[DEST_REG].upper.f);
|
|
|
+
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].upper.i;
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPSTC5 (ARMul_State * state,
|
|
|
+ unsigned type, ARMword instr, ARMword * data)
|
|
|
+{
|
|
|
+ static unsigned words;
|
|
|
+
|
|
|
+ if (type != ARMul_DATA) {
|
|
|
+ words = 0;
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (BIT (22)) {
|
|
|
+ /* It's a long access, store two words. */
|
|
|
+ /* cfstr64 */
|
|
|
+ printfdbg ("cfstr64\n");
|
|
|
+
|
|
|
+ if (words == 0) {
|
|
|
+ if (state->bigendSig)
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].upper.i;
|
|
|
+ else
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].lower.i;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (state->bigendSig)
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].lower.i;
|
|
|
+ else
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].upper.i;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++words;
|
|
|
+
|
|
|
+ if (words == 2) {
|
|
|
+ printfdbg ("\tmem = mvd%d = %lld\n", DEST_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ return ARMul_INC;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ /* Store just one word. */
|
|
|
+ /* cfstr32 */
|
|
|
+ *data = (ARMword) DSPregs[DEST_REG].lower.i;
|
|
|
+
|
|
|
+ printfdbg ("cfstr32 MEM = %d\n", (int) *data);
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPCDP4 (ARMul_State * state, unsigned type, ARMword instr)
|
|
|
+{
|
|
|
+ int opcode2;
|
|
|
+
|
|
|
+ opcode2 = BITS (5, 7);
|
|
|
+
|
|
|
+ switch (BITS (20, 21)) {
|
|
|
+ case 0:
|
|
|
+ switch (opcode2) {
|
|
|
+ case 0: /* cfcpys */
|
|
|
+ printfdbg ("cfcpys mvf%d = mvf%d = %f\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ DSPregs[SRC1_REG].upper.f);
|
|
|
+ DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfcpyd */
|
|
|
+ printfdbg ("cfcpyd mvd%d = mvd%d = %g\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ mv_getRegDouble (SRC1_REG));
|
|
|
+ mv_setRegDouble (DEST_REG,
|
|
|
+ mv_getRegDouble (SRC1_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfcvtds */
|
|
|
+ printfdbg ("cfcvtds mvf%d = (float) mvd%d = %f\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ (float) mv_getRegDouble (SRC1_REG));
|
|
|
+ DSPregs[DEST_REG].upper.f =
|
|
|
+ (float) mv_getRegDouble (SRC1_REG);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfcvtsd */
|
|
|
+ printfdbg ("cfcvtsd mvd%d = mvf%d = %g\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ (double) DSPregs[SRC1_REG].upper.f);
|
|
|
+ mv_setRegDouble (DEST_REG,
|
|
|
+ (double) DSPregs[SRC1_REG].upper.f);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfcvt32s */
|
|
|
+ printfdbg ("cfcvt32s mvf%d = mvfx%d = %f\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ (float) DSPregs[SRC1_REG].lower.i);
|
|
|
+ DSPregs[DEST_REG].upper.f =
|
|
|
+ (float) DSPregs[SRC1_REG].lower.i;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: /* cfcvt32d */
|
|
|
+ printfdbg ("cfcvt32d mvd%d = mvfx%d = %g\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ (double) DSPregs[SRC1_REG].lower.i);
|
|
|
+ mv_setRegDouble (DEST_REG,
|
|
|
+ (double) DSPregs[SRC1_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 6: /* cfcvt64s */
|
|
|
+ printfdbg ("cfcvt64s mvf%d = mvdx%d = %f\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ (float) mv_getReg64int (SRC1_REG));
|
|
|
+ DSPregs[DEST_REG].upper.f =
|
|
|
+ (float) mv_getReg64int (SRC1_REG);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 7: /* cfcvt64d */
|
|
|
+ printfdbg ("cfcvt64d mvd%d = mvdx%d = %g\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ (double) mv_getReg64int (SRC1_REG));
|
|
|
+ mv_setRegDouble (DEST_REG,
|
|
|
+ (double) mv_getReg64int (SRC1_REG));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1:
|
|
|
+ switch (opcode2) {
|
|
|
+ case 0: /* cfmuls */
|
|
|
+ printfdbg ("cfmuls mvf%d = mvf%d = %f\n",
|
|
|
+ DEST_REG,
|
|
|
+ SRC1_REG,
|
|
|
+ DSPregs[SRC1_REG].upper.f *
|
|
|
+ DSPregs[SRC2_REG].upper.f);
|
|
|
+
|
|
|
+ DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
|
|
|
+ * DSPregs[SRC2_REG].upper.f;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmuld */
|
|
|
+ printfdbg ("cfmuld mvd%d = mvd%d = %g\n",
|
|
|
+ DEST_REG,
|
|
|
+ SRC1_REG,
|
|
|
+ mv_getRegDouble (SRC1_REG) *
|
|
|
+ mv_getRegDouble (SRC2_REG));
|
|
|
+
|
|
|
+ mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
|
|
|
+ * mv_getRegDouble (SRC2_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n",
|
|
|
+ instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ switch (opcode2) {
|
|
|
+ case 0: /* cfabss */
|
|
|
+ DSPregs[DEST_REG].upper.f =
|
|
|
+ (DSPregs[SRC1_REG].upper.f <
|
|
|
+ 0.0F ? -DSPregs[SRC1_REG].upper.
|
|
|
+ f : DSPregs[SRC1_REG].upper.f);
|
|
|
+ printfdbg ("cfabss mvf%d = |mvf%d| = %f\n", DEST_REG,
|
|
|
+ SRC1_REG, DSPregs[DEST_REG].upper.f);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfabsd */
|
|
|
+ mv_setRegDouble (DEST_REG,
|
|
|
+ (mv_getRegDouble (SRC1_REG) < 0.0 ?
|
|
|
+ -mv_getRegDouble (SRC1_REG)
|
|
|
+ : mv_getRegDouble (SRC1_REG)));
|
|
|
+ printfdbg ("cfabsd mvd%d = |mvd%d| = %g\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ mv_getRegDouble (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfnegs */
|
|
|
+ DSPregs[DEST_REG].upper.f =
|
|
|
+ -DSPregs[SRC1_REG].upper.f;
|
|
|
+ printfdbg ("cfnegs mvf%d = -mvf%d = %f\n", DEST_REG,
|
|
|
+ SRC1_REG, DSPregs[DEST_REG].upper.f);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfnegd */
|
|
|
+ mv_setRegDouble (DEST_REG,
|
|
|
+ -mv_getRegDouble (SRC1_REG));
|
|
|
+ printfdbg ("cfnegd mvd%d = -mvd%d = %g\n", DEST_REG,
|
|
|
+ mv_getRegDouble (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfadds */
|
|
|
+ DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
|
|
|
+ + DSPregs[SRC2_REG].upper.f;
|
|
|
+ printfdbg ("cfadds mvf%d = mvf%d + mvf%d = %f\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].upper.f);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: /* cfaddd */
|
|
|
+ mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
|
|
|
+ + mv_getRegDouble (SRC2_REG));
|
|
|
+ printfdbg ("cfaddd: mvd%d = mvd%d + mvd%d = %g\n",
|
|
|
+ DEST_REG,
|
|
|
+ SRC1_REG, SRC2_REG,
|
|
|
+ mv_getRegDouble (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 6: /* cfsubs */
|
|
|
+ DSPregs[DEST_REG].upper.f = DSPregs[SRC1_REG].upper.f
|
|
|
+ - DSPregs[SRC2_REG].upper.f;
|
|
|
+ printfdbg ("cfsubs: mvf%d = mvf%d - mvf%d = %f\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].upper.f);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 7: /* cfsubd */
|
|
|
+ mv_setRegDouble (DEST_REG, mv_getRegDouble (SRC1_REG)
|
|
|
+ - mv_getRegDouble (SRC2_REG));
|
|
|
+ printfdbg ("cfsubd: mvd%d = mvd%d - mvd%d = %g\n",
|
|
|
+ DEST_REG,
|
|
|
+ SRC1_REG, SRC2_REG,
|
|
|
+ mv_getRegDouble (DEST_REG));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPCDP4 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPCDP5 (ARMul_State * state, unsigned type, ARMword instr)
|
|
|
+{
|
|
|
+ int opcode2;
|
|
|
+ char shift;
|
|
|
+
|
|
|
+ opcode2 = BITS (5, 7);
|
|
|
+
|
|
|
+ /* Shift constants are 7bit signed numbers in bits 0..3|5..7. */
|
|
|
+ shift = BITS (0, 3) | (BITS (5, 7)) << 4;
|
|
|
+ if (shift & 0x40)
|
|
|
+ shift |= 0xc0;
|
|
|
+
|
|
|
+ switch (BITS (20, 21)) {
|
|
|
+ case 0:
|
|
|
+ /* cfsh32 */
|
|
|
+ printfdbg ("cfsh32 %s amount=%d\n",
|
|
|
+ shift < 0 ? "right" : "left", shift);
|
|
|
+ if (shift < 0)
|
|
|
+ /* Negative shift is a right shift. */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ DSPregs[SRC1_REG].lower.i >> -shift;
|
|
|
+ else
|
|
|
+ /* Positive shift is a left shift. */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ DSPregs[SRC1_REG].lower.i << shift;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1:
|
|
|
+ switch (opcode2) {
|
|
|
+ case 0: /* cfmul32 */
|
|
|
+ DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
|
|
|
+ * DSPregs[SRC2_REG].lower.i;
|
|
|
+ printfdbg ("cfmul32 mvfx%d = mvfx%d * mvfx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfmul64 */
|
|
|
+ mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
|
|
|
+ * mv_getReg64int (SRC2_REG));
|
|
|
+ printfdbg
|
|
|
+ ("cfmul64 mvdx%d = mvdx%d * mvdx%d = %lld\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfmac32 */
|
|
|
+ DSPregs[DEST_REG].lower.i
|
|
|
+ +=
|
|
|
+ DSPregs[SRC1_REG].lower.i *
|
|
|
+ DSPregs[SRC2_REG].lower.i;
|
|
|
+ printfdbg ("cfmac32 mvfx%d += mvfx%d * mvfx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfmsc32 */
|
|
|
+ DSPregs[DEST_REG].lower.i
|
|
|
+ -=
|
|
|
+ DSPregs[SRC1_REG].lower.i *
|
|
|
+ DSPregs[SRC2_REG].lower.i;
|
|
|
+ printfdbg ("cfmsc32 mvfx%d -= mvfx%d * mvfx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfcvts32 */
|
|
|
+ /* fixme: this should round */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ (int) DSPregs[SRC1_REG].upper.f;
|
|
|
+ printfdbg ("cfcvts32 mvfx%d = mvf%d = %d\n", DEST_REG,
|
|
|
+ SRC1_REG, DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: /* cfcvtd32 */
|
|
|
+ /* fixme: this should round */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ (int) mv_getRegDouble (SRC1_REG);
|
|
|
+ printfdbg ("cfcvtd32 mvdx%d = mvd%d = %d\n", DEST_REG,
|
|
|
+ SRC1_REG, DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 6: /* cftruncs32 */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ (int) DSPregs[SRC1_REG].upper.f;
|
|
|
+ printfdbg ("cftruncs32 mvfx%d = mvf%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 7: /* cftruncd32 */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ (int) mv_getRegDouble (SRC1_REG);
|
|
|
+ printfdbg ("cftruncd32 mvfx%d = mvd%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ /* cfsh64 */
|
|
|
+ printfdbg ("cfsh64\n");
|
|
|
+
|
|
|
+ if (shift < 0)
|
|
|
+ /* Negative shift is a right shift. */
|
|
|
+ mv_setReg64int (DEST_REG,
|
|
|
+ mv_getReg64int (SRC1_REG) >> -shift);
|
|
|
+ else
|
|
|
+ /* Positive shift is a left shift. */
|
|
|
+ mv_setReg64int (DEST_REG,
|
|
|
+ mv_getReg64int (SRC1_REG) << shift);
|
|
|
+ printfdbg ("\t%llx\n", mv_getReg64int (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ switch (opcode2) {
|
|
|
+ case 0: /* cfabs32 */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ (DSPregs[SRC1_REG].lower.i <
|
|
|
+ 0 ? -DSPregs[SRC1_REG].lower.
|
|
|
+ i : DSPregs[SRC1_REG].lower.i);
|
|
|
+ printfdbg ("cfabs32 mvfx%d = |mvfx%d| = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1: /* cfabs64 */
|
|
|
+ mv_setReg64int (DEST_REG,
|
|
|
+ (mv_getReg64int (SRC1_REG) < 0
|
|
|
+ ? -mv_getReg64int (SRC1_REG)
|
|
|
+ : mv_getReg64int (SRC1_REG)));
|
|
|
+ printfdbg ("cfabs64 mvdx%d = |mvdx%d| = %lld\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2: /* cfneg32 */
|
|
|
+ DSPregs[DEST_REG].lower.i =
|
|
|
+ -DSPregs[SRC1_REG].lower.i;
|
|
|
+ printfdbg ("cfneg32 mvfx%d = -mvfx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* cfneg64 */
|
|
|
+ mv_setReg64int (DEST_REG, -mv_getReg64int (SRC1_REG));
|
|
|
+ printfdbg ("cfneg64 mvdx%d = -mvdx%d = %lld\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4: /* cfadd32 */
|
|
|
+ DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
|
|
|
+ + DSPregs[SRC2_REG].lower.i;
|
|
|
+ printfdbg ("cfadd32 mvfx%d = mvfx%d + mvfx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: /* cfadd64 */
|
|
|
+ mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
|
|
|
+ + mv_getReg64int (SRC2_REG));
|
|
|
+ printfdbg
|
|
|
+ ("cfadd64 mvdx%d = mvdx%d + mvdx%d = %lld\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 6: /* cfsub32 */
|
|
|
+ DSPregs[DEST_REG].lower.i = DSPregs[SRC1_REG].lower.i
|
|
|
+ - DSPregs[SRC2_REG].lower.i;
|
|
|
+ printfdbg ("cfsub32 mvfx%d = mvfx%d - mvfx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ DSPregs[DEST_REG].lower.i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 7: /* cfsub64 */
|
|
|
+ mv_setReg64int (DEST_REG, mv_getReg64int (SRC1_REG)
|
|
|
+ - mv_getReg64int (SRC2_REG));
|
|
|
+ printfdbg ("cfsub64 mvdx%d = mvdx%d - mvdx%d = %d\n",
|
|
|
+ DEST_REG, SRC1_REG, SRC2_REG,
|
|
|
+ mv_getReg64int (DEST_REG));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPCDP5 0x%x\n", instr);
|
|
|
+ cirrus_not_implemented ("unknown");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+unsigned
|
|
|
+DSPCDP6 (ARMul_State * state, unsigned type, ARMword instr)
|
|
|
+{
|
|
|
+ int opcode2;
|
|
|
+
|
|
|
+ opcode2 = BITS (5, 7);
|
|
|
+
|
|
|
+ switch (BITS (20, 21)) {
|
|
|
+ case 0:
|
|
|
+ /* cfmadd32 */
|
|
|
+ cirrus_not_implemented ("cfmadd32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 1:
|
|
|
+ /* cfmsub32 */
|
|
|
+ cirrus_not_implemented ("cfmsub32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ /* cfmadda32 */
|
|
|
+ cirrus_not_implemented ("cfmadda32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ /* cfmsuba32 */
|
|
|
+ cirrus_not_implemented ("cfmsuba32");
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ fprintf (stderr, "unknown opcode in DSPCDP6 0x%x\n", instr);
|
|
|
+ }
|
|
|
+
|
|
|
+ return ARMul_DONE;
|
|
|
+}
|
|
|
+
|
|
|
+/* Conversion functions.
|
|
|
+
|
|
|
+ 32-bit integers are stored in the LOWER half of a 64-bit physical
|
|
|
+ register.
|
|
|
+
|
|
|
+ Single precision floats are stored in the UPPER half of a 64-bit
|
|
|
+ physical register. */
|
|
|
+
|
|
|
+static double
|
|
|
+mv_getRegDouble (int regnum)
|
|
|
+{
|
|
|
+ reg_conv.ints[lsw_float_index] = DSPregs[regnum].upper.i;
|
|
|
+ reg_conv.ints[msw_float_index] = DSPregs[regnum].lower.i;
|
|
|
+ return reg_conv.d;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+mv_setRegDouble (int regnum, double val)
|
|
|
+{
|
|
|
+ reg_conv.d = val;
|
|
|
+ DSPregs[regnum].upper.i = reg_conv.ints[lsw_float_index];
|
|
|
+ DSPregs[regnum].lower.i = reg_conv.ints[msw_float_index];
|
|
|
+}
|
|
|
+
|
|
|
+static long long
|
|
|
+mv_getReg64int (int regnum)
|
|
|
+{
|
|
|
+ reg_conv.ints[lsw_int_index] = DSPregs[regnum].lower.i;
|
|
|
+ reg_conv.ints[msw_int_index] = DSPregs[regnum].upper.i;
|
|
|
+ return reg_conv.ll;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+mv_setReg64int (int regnum, long long val)
|
|
|
+{
|
|
|
+ reg_conv.ll = val;
|
|
|
+ DSPregs[regnum].lower.i = reg_conv.ints[lsw_int_index];
|
|
|
+ DSPregs[regnum].upper.i = reg_conv.ints[msw_int_index];
|
|
|
+}
|
|
|
+
|
|
|
+/* Compute LSW in a double and a long long. */
|
|
|
+
|
|
|
+void
|
|
|
+mv_compute_host_endianness (ARMul_State * state)
|
|
|
+{
|
|
|
+ static union
|
|
|
+ {
|
|
|
+ long long ll;
|
|
|
+ int ints[2];
|
|
|
+ int i;
|
|
|
+ double d;
|
|
|
+ float floats[2];
|
|
|
+ float f;
|
|
|
+ } conv;
|
|
|
+
|
|
|
+ /* Calculate where's the LSW in a 64bit int. */
|
|
|
+ conv.ll = 45;
|
|
|
+
|
|
|
+ if (conv.ints[0] == 0) {
|
|
|
+ msw_int_index = 0;
|
|
|
+ lsw_int_index = 1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ assert (conv.ints[1] == 0);
|
|
|
+ msw_int_index = 1;
|
|
|
+ lsw_int_index = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Calculate where's the LSW in a double. */
|
|
|
+ conv.d = 3.0;
|
|
|
+
|
|
|
+ if (conv.ints[0] == 0) {
|
|
|
+ msw_float_index = 0;
|
|
|
+ lsw_float_index = 1;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ assert (conv.ints[1] == 0);
|
|
|
+ msw_float_index = 1;
|
|
|
+ lsw_float_index = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ printfdbg ("lsw_int_index %d\n", lsw_int_index);
|
|
|
+ printfdbg ("lsw_float_index %d\n", lsw_float_index);
|
|
|
+}
|