From f603c8fe448b391b8356fae23c3a0e6242fa76b5 Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 20 Mar 2003 12:25:07 +0000 Subject: [PATCH] Add Cirrus Maverick support to arm simulator --- include/gdb/ChangeLog | 5 + include/gdb/sim-arm.h | 21 +- sim/arm/ChangeLog | 24 + sim/arm/Makefile.in | 1 + sim/arm/armcopro.c | 70 ++- sim/arm/armdefs.h | 2 + sim/arm/armemu.h | 13 + sim/arm/arminit.c | 5 + sim/arm/configure | 3 +- sim/arm/configure.in | 3 +- sim/arm/maverick.c | 1291 +++++++++++++++++++++++++++++++++++++++++ sim/arm/wrapper.c | 85 ++- 12 files changed, 1490 insertions(+), 33 deletions(-) create mode 100644 sim/arm/maverick.c diff --git a/include/gdb/ChangeLog b/include/gdb/ChangeLog index f60f7b169f7..97c2f443c38 100644 --- a/include/gdb/ChangeLog +++ b/include/gdb/ChangeLog @@ -1,3 +1,8 @@ +2003-03-20 Nick Clifton + + * sim-arm.h (sim_arm_regs): Add Maverick co-processor + registers. + 2003-02-27 Andrew Cagney * remote-sim.h (sim_open, sim_load, sim_create_inferior): Rename diff --git a/include/gdb/sim-arm.h b/include/gdb/sim-arm.h index 6d80700ad7e..fae11f0b16b 100644 --- a/include/gdb/sim-arm.h +++ b/include/gdb/sim-arm.h @@ -1,6 +1,6 @@ /* This file defines the interface between the Arm simulator and GDB. - Copyright 2002 Free Software Foundation, Inc. + Copyright 2002, 2003 Free Software Foundation, Inc. Contributed by Red Hat. @@ -55,7 +55,24 @@ enum sim_arm_regs SIM_ARM_FP6_REGNUM, SIM_ARM_FP7_REGNUM, SIM_ARM_FPS_REGNUM, - SIM_ARM_PS_REGNUM + SIM_ARM_PS_REGNUM, + SIM_ARM_MAVERIC_COP0R0_REGNUM, + SIM_ARM_MAVERIC_COP0R1_REGNUM, + SIM_ARM_MAVERIC_COP0R2_REGNUM, + SIM_ARM_MAVERIC_COP0R3_REGNUM, + SIM_ARM_MAVERIC_COP0R4_REGNUM, + SIM_ARM_MAVERIC_COP0R5_REGNUM, + SIM_ARM_MAVERIC_COP0R6_REGNUM, + SIM_ARM_MAVERIC_COP0R7_REGNUM, + SIM_ARM_MAVERIC_COP0R8_REGNUM, + SIM_ARM_MAVERIC_COP0R9_REGNUM, + SIM_ARM_MAVERIC_COP0R10_REGNUM, + SIM_ARM_MAVERIC_COP0R11_REGNUM, + SIM_ARM_MAVERIC_COP0R12_REGNUM, + SIM_ARM_MAVERIC_COP0R13_REGNUM, + SIM_ARM_MAVERIC_COP0R14_REGNUM, + SIM_ARM_MAVERIC_COP0R15_REGNUM, + SIM_ARM_MAVERIC_DSPSC_REGNUM }; #ifdef __cplusplus diff --git a/sim/arm/ChangeLog b/sim/arm/ChangeLog index 5e4b316ca86..8ae1f70436e 100644 --- a/sim/arm/ChangeLog +++ b/sim/arm/ChangeLog @@ -1,3 +1,27 @@ +2003-02-10 Nick Clifton + + * Contribute support for Cirrus Maverick ARM co-processor, + written by Aldy Hernandez and + Andrew Cagney : + + * maverick.c: New file: Support for Maverick floating point + co-processor. + * Makefile.in: Add maverick.o target. + * configure.in (COPRO): Add maverick.o. + * configure: Regenerate. + * armcopro.c (ARMul_CoProInit): Only initialise co-processors + available on target processor. Add code to initialse Maverick + co-processor support code. + * armdefs.h (ARMul_state): Add is_ep9312 field. + (ARM_ep9312_Prop): Define. + * armemu.h: Add prototypes for Maverick co-processor + functions. + * arminit.c (ARMul_SelectProcessor): Initialise the + co-processor support once the chip has been selected. + * wrapper.c: Add support for Maverick co-processor. + (init): Do not call ARMul_CoProInit. Delays this until the + chip has been selected. + 2003-03-02 Nick Clifton * armos.c (SWIWrite0): Catch big-endian bug when printing diff --git a/sim/arm/Makefile.in b/sim/arm/Makefile.in index 0da765fd703..017a983289d 100644 --- a/sim/arm/Makefile.in +++ b/sim/arm/Makefile.in @@ -31,6 +31,7 @@ SIM_OBJS = armemu26.o armemu32.o arminit.o armos.o armsupp.o \ armos.o: armos.c armdefs.h armos.h armfpe.h armcopro.o: armcopro.c armdefs.h +maverick.o: maverick.c armdefs.h armemu26.o: armemu.c armdefs.h armemu.h $(CC) -c $(srcdir)/armemu.c -o armemu26.o $(ALL_CFLAGS) diff --git a/sim/arm/armcopro.c b/sim/arm/armcopro.c index 2c2ca8505a6..b9747894869 100644 --- a/sim/arm/armcopro.c +++ b/sim/arm/armcopro.c @@ -1322,34 +1322,48 @@ ARMul_CoProInit (ARMul_State * state) /* Install CoPro Instruction handlers here. The format is: - ARMul_CoProAttach (state, CP Number, - Init routine, Exit routine - LDC routine, STC routine, - MRC routine, MCR routine, - CDP routine, - Read Reg routine, Write Reg routine). */ - ARMul_CoProAttach (state, 4, NULL, NULL, - ValLDC, ValSTC, ValMRC, ValMCR, ValCDP, NULL, NULL); - - ARMul_CoProAttach (state, 5, NULL, NULL, - NULL, NULL, ValMRC, ValMCR, IntCDP, NULL, NULL); - - ARMul_CoProAttach (state, 15, MMUInit, NULL, - NULL, NULL, MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); - - ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL, - XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC, - XScale_cp13_MCR, NULL, XScale_cp13_read_reg, - XScale_cp13_write_reg); - - ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL, - XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC, - XScale_cp14_MCR, NULL, XScale_cp14_read_reg, - XScale_cp14_write_reg); - - ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL, - NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR, - NULL, XScale_cp15_read_reg, XScale_cp15_write_reg); + ARMul_CoProAttach (state, CP Number, Init routine, Exit routine + LDC routine, STC routine, MRC routine, MCR routine, + CDP routine, Read Reg routine, Write Reg routine). */ + if (state->is_ep9312) + { + ARMul_CoProAttach (state, 4, NULL, NULL, DSPLDC4, DSPSTC4, + DSPMRC4, DSPMCR4, DSPCDP4, NULL, NULL); + ARMul_CoProAttach (state, 5, NULL, NULL, DSPLDC5, DSPSTC5, + DSPMRC5, DSPMCR5, DSPCDP5, NULL, NULL); + ARMul_CoProAttach (state, 6, NULL, NULL, NULL, NULL, + DSPMRC6, DSPMCR6, DSPCDP6, NULL, NULL); + } + else + { + ARMul_CoProAttach (state, 4, NULL, NULL, ValLDC, ValSTC, + ValMRC, ValMCR, ValCDP, NULL, NULL); + + ARMul_CoProAttach (state, 5, NULL, NULL, NULL, NULL, + ValMRC, ValMCR, IntCDP, NULL, NULL); + } + + if (state->is_XScale) + { + ARMul_CoProAttach (state, 13, XScale_cp13_init, NULL, + XScale_cp13_LDC, XScale_cp13_STC, XScale_cp13_MRC, + XScale_cp13_MCR, NULL, XScale_cp13_read_reg, + XScale_cp13_write_reg); + + ARMul_CoProAttach (state, 14, XScale_cp14_init, NULL, + XScale_cp14_LDC, XScale_cp14_STC, XScale_cp14_MRC, + XScale_cp14_MCR, NULL, XScale_cp14_read_reg, + XScale_cp14_write_reg); + + ARMul_CoProAttach (state, 15, XScale_cp15_init, NULL, + NULL, NULL, XScale_cp15_MRC, XScale_cp15_MCR, + NULL, XScale_cp15_read_reg, XScale_cp15_write_reg); + } + else + { + ARMul_CoProAttach (state, 15, MMUInit, NULL, NULL, NULL, + MMUMRC, MMUMCR, NULL, MMURead, MMUWrite); + } /* No handlers below here. */ diff --git a/sim/arm/armdefs.h b/sim/arm/armdefs.h index fde31251633..0f252226dd9 100644 --- a/sim/arm/armdefs.h +++ b/sim/arm/armdefs.h @@ -135,6 +135,7 @@ struct ARMul_State unsigned is_v5; /* Are we emulating a v5 architecture ? */ unsigned is_v5e; /* Are we emulating a v5e architecture ? */ unsigned is_XScale; /* Are we emulating an XScale architecture ? */ + unsigned is_ep9312; /* Are we emulating a Cirrus Maverick co-processor ? */ unsigned verbose; /* Print various messages like the banner */ }; @@ -162,6 +163,7 @@ struct ARMul_State #define ARM_v5_Prop 0x80 #define ARM_v5e_Prop 0x100 #define ARM_XScale_Prop 0x200 +#define ARM_ep9312_Prop 0x400 /***************************************************************************\ * Macros to extract instruction fields * diff --git a/sim/arm/armemu.h b/sim/arm/armemu.h index 385924bd689..dfaafb03bbc 100644 --- a/sim/arm/armemu.h +++ b/sim/arm/armemu.h @@ -530,3 +530,16 @@ extern void ARMul_CoProAttach (ARMul_State *, unsigned, ARMul_CPInits *, A extern void ARMul_CoProDetach (ARMul_State *, unsigned); extern ARMword read_cp15_reg (unsigned, unsigned, unsigned); +extern unsigned DSPLDC4 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMCR4 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMRC4 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPSTC4 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPCDP4 (ARMul_State *, unsigned, ARMword); +extern unsigned DSPMCR5 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMRC5 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPLDC5 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPSTC5 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPCDP5 (ARMul_State *, unsigned, ARMword); +extern unsigned DSPMCR6 (ARMul_State *, unsigned, ARMword, ARMword); +extern unsigned DSPMRC6 (ARMul_State *, unsigned, ARMword, ARMword *); +extern unsigned DSPCDP6 (ARMul_State *, unsigned, ARMword); diff --git a/sim/arm/arminit.c b/sim/arm/arminit.c index c0312e95239..04399900c95 100644 --- a/sim/arm/arminit.c +++ b/sim/arm/arminit.c @@ -157,6 +157,11 @@ ARMul_SelectProcessor (ARMul_State * state, unsigned properties) state->is_v5 = (properties & ARM_v5_Prop) ? HIGH : LOW; state->is_v5e = (properties & ARM_v5e_Prop) ? HIGH : LOW; state->is_XScale = (properties & ARM_XScale_Prop) ? HIGH : LOW; + state->is_ep9312 = (properties & ARM_ep9312_Prop) ? HIGH : LOW; + + /* Only initialse the coprocessor support once we + know what kind of chip we are dealing with. */ + ARMul_CoProInit (state); } /***************************************************************************\ diff --git a/sim/arm/configure b/sim/arm/configure index 65f0825ff8c..26fd5f5d6d1 100755 --- a/sim/arm/configure +++ b/sim/arm/configure @@ -3534,7 +3534,8 @@ fi done -COPRO=armcopro.o +COPRO="armcopro.o maverick.o" + diff --git a/sim/arm/configure.in b/sim/arm/configure.in index cbfac44e4cd..73fa0a0a643 100644 --- a/sim/arm/configure.in +++ b/sim/arm/configure.in @@ -7,7 +7,8 @@ SIM_AC_COMMON AC_CHECK_HEADERS(unistd.h) -COPRO=armcopro.o +COPRO="armcopro.o maverick.o" + AC_SUBST(COPRO) SIM_AC_OUTPUT diff --git a/sim/arm/maverick.c b/sim/arm/maverick.c new file mode 100644 index 00000000000..82871f90675 --- /dev/null +++ b/sim/arm/maverick.c @@ -0,0 +1,1291 @@ +/* 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 +#include "armdefs.h" +#include "ansidecl.h" +#include "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"); + + exit (1); +} + +static unsigned +DSPInit (ARMul_State * state) +{ + ARMul_ConsolePrint (state, ", DSP present"); + return TRUE; +} + +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, + 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; + long ints[2]; + long 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); +} diff --git a/sim/arm/wrapper.c b/sim/arm/wrapper.c index 244c475eb93..f13d32928b0 100644 --- a/sim/arm/wrapper.c +++ b/sim/arm/wrapper.c @@ -59,6 +59,38 @@ static int big_endian; int stop_simulator; +/* Cirrus DSP registers. + + We need to define these registers outside of maverick.c because + maverick.c might not be linked in unless --target=arm9e-* in which + case wrapper.c will not compile because it tries to access Cirrus + registers. This should all go away once we get the Cirrus and ARM + Coprocessor to coexist in armcopro.c-- aldyh. */ + +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; + static void init () { @@ -71,7 +103,6 @@ init () state->bigendSig = (big_endian ? HIGH : LOW); ARMul_MemoryInit (state, mem_size); ARMul_OSInit (state); - ARMul_CoProInit (state); state->verbose = verbosity; done = 1; } @@ -236,6 +267,10 @@ sim_create_inferior (sd, abfd, argv, env) ARMul_SelectProcessor (state, ARM_v5_Prop | ARM_v5e_Prop | ARM_XScale_Prop); break; + case bfd_mach_arm_ep9312: + ARMul_SelectProcessor (state, ARM_v4_Prop | ARM_ep9312_Prop); + break; + case bfd_mach_arm_5: if (bfd_family_coff (abfd)) { @@ -422,6 +457,30 @@ sim_store_register (sd, rn, memory, length) ARMul_CPSRAltered (state); break; + case SIM_ARM_MAVERIC_COP0R0_REGNUM: + case SIM_ARM_MAVERIC_COP0R1_REGNUM: + case SIM_ARM_MAVERIC_COP0R2_REGNUM: + case SIM_ARM_MAVERIC_COP0R3_REGNUM: + case SIM_ARM_MAVERIC_COP0R4_REGNUM: + case SIM_ARM_MAVERIC_COP0R5_REGNUM: + case SIM_ARM_MAVERIC_COP0R6_REGNUM: + case SIM_ARM_MAVERIC_COP0R7_REGNUM: + case SIM_ARM_MAVERIC_COP0R8_REGNUM: + case SIM_ARM_MAVERIC_COP0R9_REGNUM: + case SIM_ARM_MAVERIC_COP0R10_REGNUM: + case SIM_ARM_MAVERIC_COP0R11_REGNUM: + case SIM_ARM_MAVERIC_COP0R12_REGNUM: + case SIM_ARM_MAVERIC_COP0R13_REGNUM: + case SIM_ARM_MAVERIC_COP0R14_REGNUM: + case SIM_ARM_MAVERIC_COP0R15_REGNUM: + memcpy (& DSPregs [rn - SIM_ARM_MAVERIC_COP0R0_REGNUM], + memory, sizeof (struct maverick_regs)); + return sizeof (struct maverick_regs); + + case SIM_ARM_MAVERIC_DSPSC_REGNUM: + memcpy (&DSPsc, memory, sizeof DSPsc); + return sizeof DSPsc; + default: return 0; } @@ -477,6 +536,30 @@ sim_fetch_register (sd, rn, memory, length) regval = ARMul_GetCPSR (state); break; + case SIM_ARM_MAVERIC_COP0R0_REGNUM: + case SIM_ARM_MAVERIC_COP0R1_REGNUM: + case SIM_ARM_MAVERIC_COP0R2_REGNUM: + case SIM_ARM_MAVERIC_COP0R3_REGNUM: + case SIM_ARM_MAVERIC_COP0R4_REGNUM: + case SIM_ARM_MAVERIC_COP0R5_REGNUM: + case SIM_ARM_MAVERIC_COP0R6_REGNUM: + case SIM_ARM_MAVERIC_COP0R7_REGNUM: + case SIM_ARM_MAVERIC_COP0R8_REGNUM: + case SIM_ARM_MAVERIC_COP0R9_REGNUM: + case SIM_ARM_MAVERIC_COP0R10_REGNUM: + case SIM_ARM_MAVERIC_COP0R11_REGNUM: + case SIM_ARM_MAVERIC_COP0R12_REGNUM: + case SIM_ARM_MAVERIC_COP0R13_REGNUM: + case SIM_ARM_MAVERIC_COP0R14_REGNUM: + case SIM_ARM_MAVERIC_COP0R15_REGNUM: + memcpy (memory, & DSPregs [rn - SIM_ARM_MAVERIC_COP0R0_REGNUM], + sizeof (struct maverick_regs)); + return sizeof (struct maverick_regs); + + case SIM_ARM_MAVERIC_DSPSC_REGNUM: + memcpy (memory, & DSPsc, sizeof DSPsc); + return sizeof DSPsc; + default: return 0; } -- 2.30.2