|  | /*  maverick.c -- Cirrus/DSP co-processor interface. | 
|  | Copyright (C) 2003-2022 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 3 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, see <http://www.gnu.org/licenses/>. */ | 
|  |  | 
|  | /* This must come before any other includes.  */ | 
|  | #include "defs.h" | 
|  |  | 
|  | #include <assert.h> | 
|  | #include "armdefs.h" | 
|  | #include "ansidecl.h" | 
|  | #include "armemu.h" | 
|  | #include "maverick.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 ) | 
|  |  | 
|  | /* These variables are defined here and made extern in maverick.h for use | 
|  | in wrapper.c for now. | 
|  | Eventually the simulator should be made to handle any coprocessor at run | 
|  | time.  */ | 
|  | 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"); | 
|  |  | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | unsigned | 
|  | DSPMRC4 (ARMul_State * state ATTRIBUTE_UNUSED, | 
|  | unsigned      type  ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | unsigned      type  ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | unsigned      type  ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | 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   ATTRIBUTE_UNUSED, | 
|  | 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   ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | 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 ATTRIBUTE_UNUSED, | 
|  | 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, 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) | 
|  | { | 
|  | 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]; | 
|  | } |