/* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
Modifications to add arch. v4 support by <jsmith@cygnus.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
+ 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, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ along with this program; if not, see <http://www.gnu.org/licenses/>. */
#include "armdefs.h"
#include "armemu.h"
#include "armos.h"
-
-static ARMword GetDPRegRHS(ARMul_State *state, ARMword instr) ;
-static ARMword GetDPSRegRHS(ARMul_State *state, ARMword instr) ;
-static void WriteR15(ARMul_State *state, ARMword src) ;
-static void WriteSR15(ARMul_State *state, ARMword src) ;
-static ARMword GetLSRegRHS(ARMul_State *state, ARMword instr) ;
-static ARMword GetLS7RHS(ARMul_State *state, ARMword instr) ;
-static unsigned LoadWord(ARMul_State *state, ARMword instr, ARMword address) ;
-static unsigned LoadHalfWord(ARMul_State *state, ARMword instr, ARMword address,int signextend) ;
-static unsigned LoadByte(ARMul_State *state, ARMword instr, ARMword address,int signextend) ;
-static unsigned StoreWord(ARMul_State *state, ARMword instr, ARMword address) ;
-static unsigned StoreHalfWord(ARMul_State *state, ARMword instr, ARMword address) ;
-static unsigned StoreByte(ARMul_State *state, ARMword instr, ARMword address) ;
-static void LoadMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
-static void StoreMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
-static void LoadSMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
-static void StoreSMult(ARMul_State *state, ARMword address, ARMword instr, ARMword WBBase) ;
-static unsigned Multiply64(ARMul_State *state, ARMword instr,int signextend,int scc) ;
-static unsigned MultiplyAdd64(ARMul_State *state, ARMword instr,int signextend,int scc) ;
-
-#define LUNSIGNED (0) /* unsigned operation */
-#define LSIGNED (1) /* signed operation */
-#define LDEFAULT (0) /* default : do nothing */
-#define LSCC (1) /* set condition codes on result */
-
-#ifdef NEED_UI_LOOP_HOOK
-/* How often to run the ui_loop update, when in use */
-#define UI_LOOP_POLL_INTERVAL 0x32000
-
-/* Counter for the ui_loop_hook update */
-static long ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL;
-
-/* Actual hook to call to run through gdb's gui event loop */
-extern int (*ui_loop_hook) (int);
-#endif /* NEED_UI_LOOP_HOOK */
+#include "iwmmxt.h"
+
+static ARMword GetDPRegRHS (ARMul_State *, ARMword);
+static ARMword GetDPSRegRHS (ARMul_State *, ARMword);
+static void WriteR15 (ARMul_State *, ARMword);
+static void WriteSR15 (ARMul_State *, ARMword);
+static void WriteR15Branch (ARMul_State *, ARMword);
+static void WriteR15Load (ARMul_State *, ARMword);
+static ARMword GetLSRegRHS (ARMul_State *, ARMword);
+static ARMword GetLS7RHS (ARMul_State *, ARMword);
+static unsigned LoadWord (ARMul_State *, ARMword, ARMword);
+static unsigned LoadHalfWord (ARMul_State *, ARMword, ARMword, int);
+static unsigned LoadByte (ARMul_State *, ARMword, ARMword, int);
+static unsigned StoreWord (ARMul_State *, ARMword, ARMword);
+static unsigned StoreHalfWord (ARMul_State *, ARMword, ARMword);
+static unsigned StoreByte (ARMul_State *, ARMword, ARMword);
+static void LoadMult (ARMul_State *, ARMword, ARMword, ARMword);
+static void StoreMult (ARMul_State *, ARMword, ARMword, ARMword);
+static void LoadSMult (ARMul_State *, ARMword, ARMword, ARMword);
+static void StoreSMult (ARMul_State *, ARMword, ARMword, ARMword);
+static unsigned Multiply64 (ARMul_State *, ARMword, int, int);
+static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int);
+static void Handle_Load_Double (ARMul_State *, ARMword);
+static void Handle_Store_Double (ARMul_State *, ARMword);
+
+#define LUNSIGNED (0) /* unsigned operation */
+#define LSIGNED (1) /* signed operation */
+#define LDEFAULT (0) /* default : do nothing */
+#define LSCC (1) /* set condition codes on result */
extern int stop_simulator;
-/***************************************************************************\
-* short-hand macros for LDR/STR *
-\***************************************************************************/
+/* Short-hand macros for LDR/STR. */
-/* store post decrement writeback */
+/* Store post decrement writeback. */
#define SHDOWNWB() \
lhs = LHS ; \
- if (StoreHalfWord(state, instr, lhs)) \
- LSBase = lhs - GetLS7RHS(state, instr) ;
+ if (StoreHalfWord (state, instr, lhs)) \
+ LSBase = lhs - GetLS7RHS (state, instr);
-/* store post increment writeback */
+/* Store post increment writeback. */
#define SHUPWB() \
lhs = LHS ; \
- if (StoreHalfWord(state, instr, lhs)) \
- LSBase = lhs + GetLS7RHS(state, instr) ;
+ if (StoreHalfWord (state, instr, lhs)) \
+ LSBase = lhs + GetLS7RHS (state, instr);
-/* store pre decrement */
+/* Store pre decrement. */
#define SHPREDOWN() \
- (void)StoreHalfWord(state, instr, LHS - GetLS7RHS(state, instr)) ;
+ (void)StoreHalfWord (state, instr, LHS - GetLS7RHS (state, instr));
-/* store pre decrement writeback */
+/* Store pre decrement writeback. */
#define SHPREDOWNWB() \
- temp = LHS - GetLS7RHS(state, instr) ; \
- if (StoreHalfWord(state, instr, temp)) \
- LSBase = temp ;
+ temp = LHS - GetLS7RHS (state, instr); \
+ if (StoreHalfWord (state, instr, temp)) \
+ LSBase = temp;
-/* store pre increment */
+/* Store pre increment. */
#define SHPREUP() \
- (void)StoreHalfWord(state, instr, LHS + GetLS7RHS(state, instr)) ;
+ (void)StoreHalfWord (state, instr, LHS + GetLS7RHS (state, instr));
-/* store pre increment writeback */
+/* Store pre increment writeback. */
#define SHPREUPWB() \
- temp = LHS + GetLS7RHS(state, instr) ; \
- if (StoreHalfWord(state, instr, temp)) \
- LSBase = temp ;
+ temp = LHS + GetLS7RHS (state, instr); \
+ if (StoreHalfWord (state, instr, temp)) \
+ LSBase = temp;
-/* load post decrement writeback */
+/* Load post decrement writeback. */
#define LHPOSTDOWN() \
{ \
- int done = 1 ; \
- lhs = LHS ; \
- switch (BITS(5,6)) { \
+ int done = 1; \
+ lhs = LHS; \
+ temp = lhs - GetLS7RHS (state, instr); \
+ \
+ switch (BITS (5, 6)) \
+ { \
case 1: /* H */ \
- if (LoadHalfWord(state,instr,lhs,LUNSIGNED)) \
- LSBase = lhs - GetLS7RHS(state,instr) ; \
- break ; \
+ if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \
+ LSBase = temp; \
+ break; \
case 2: /* SB */ \
- if (LoadByte(state,instr,lhs,LSIGNED)) \
- LSBase = lhs - GetLS7RHS(state,instr) ; \
- break ; \
+ if (LoadByte (state, instr, lhs, LSIGNED)) \
+ LSBase = temp; \
+ break; \
case 3: /* SH */ \
- if (LoadHalfWord(state,instr,lhs,LSIGNED)) \
- LSBase = lhs - GetLS7RHS(state,instr) ; \
- break ; \
- case 0: /* SWP handled elsewhere */ \
+ if (LoadHalfWord (state, instr, lhs, LSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 0: /* SWP handled elsewhere. */ \
default: \
- done = 0 ; \
- break ; \
+ done = 0; \
+ break; \
} \
if (done) \
- break ; \
+ break; \
}
-/* load post increment writeback */
+/* Load post increment writeback. */
#define LHPOSTUP() \
{ \
- int done = 1 ; \
- lhs = LHS ; \
- switch (BITS(5,6)) { \
+ int done = 1; \
+ lhs = LHS; \
+ temp = lhs + GetLS7RHS (state, instr); \
+ \
+ switch (BITS (5, 6)) \
+ { \
case 1: /* H */ \
- if (LoadHalfWord(state,instr,lhs,LUNSIGNED)) \
- LSBase = lhs + GetLS7RHS(state,instr) ; \
- break ; \
+ if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \
+ LSBase = temp; \
+ break; \
case 2: /* SB */ \
- if (LoadByte(state,instr,lhs,LSIGNED)) \
- LSBase = lhs + GetLS7RHS(state,instr) ; \
- break ; \
+ if (LoadByte (state, instr, lhs, LSIGNED)) \
+ LSBase = temp; \
+ break; \
case 3: /* SH */ \
- if (LoadHalfWord(state,instr,lhs,LSIGNED)) \
- LSBase = lhs + GetLS7RHS(state,instr) ; \
- break ; \
- case 0: /* SWP handled elsewhere */ \
+ if (LoadHalfWord (state, instr, lhs, LSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 0: /* SWP handled elsewhere. */ \
default: \
- done = 0 ; \
- break ; \
+ done = 0; \
+ break; \
} \
if (done) \
- break ; \
+ break; \
}
-/* load pre decrement */
-#define LHPREDOWN() \
-{ \
- int done = 1 ; \
- temp = LHS - GetLS7RHS(state,instr) ; \
- switch (BITS(5,6)) { \
- case 1: /* H */ \
- (void)LoadHalfWord(state,instr,temp,LUNSIGNED) ; \
- break ; \
- case 2: /* SB */ \
- (void)LoadByte(state,instr,temp,LSIGNED) ; \
- break ; \
- case 3: /* SH */ \
- (void)LoadHalfWord(state,instr,temp,LSIGNED) ; \
- break ; \
- case 0: /* SWP handled elsewhere */ \
- default: \
- done = 0 ; \
- break ; \
- } \
- if (done) \
- break ; \
+/* Load pre decrement. */
+#define LHPREDOWN() \
+{ \
+ int done = 1; \
+ \
+ temp = LHS - GetLS7RHS (state, instr); \
+ switch (BITS (5, 6)) \
+ { \
+ case 1: /* H */ \
+ (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \
+ break; \
+ case 2: /* SB */ \
+ (void) LoadByte (state, instr, temp, LSIGNED); \
+ break; \
+ case 3: /* SH */ \
+ (void) LoadHalfWord (state, instr, temp, LSIGNED); \
+ break; \
+ case 0: \
+ /* SWP handled elsewhere. */ \
+ default: \
+ done = 0; \
+ break; \
+ } \
+ if (done) \
+ break; \
}
-/* load pre decrement writeback */
-#define LHPREDOWNWB() \
-{ \
- int done = 1 ; \
- temp = LHS - GetLS7RHS(state, instr) ; \
- switch (BITS(5,6)) { \
- case 1: /* H */ \
- if (LoadHalfWord(state,instr,temp,LUNSIGNED)) \
- LSBase = temp ; \
- break ; \
- case 2: /* SB */ \
- if (LoadByte(state,instr,temp,LSIGNED)) \
- LSBase = temp ; \
- break ; \
- case 3: /* SH */ \
- if (LoadHalfWord(state,instr,temp,LSIGNED)) \
- LSBase = temp ; \
- break ; \
- case 0: /* SWP handled elsewhere */ \
- default: \
- done = 0 ; \
- break ; \
- } \
- if (done) \
- break ; \
+/* Load pre decrement writeback. */
+#define LHPREDOWNWB() \
+{ \
+ int done = 1; \
+ \
+ temp = LHS - GetLS7RHS (state, instr); \
+ switch (BITS (5, 6)) \
+ { \
+ case 1: /* H */ \
+ if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 2: /* SB */ \
+ if (LoadByte (state, instr, temp, LSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 3: /* SH */ \
+ if (LoadHalfWord (state, instr, temp, LSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 0: \
+ /* SWP handled elsewhere. */ \
+ default: \
+ done = 0; \
+ break; \
+ } \
+ if (done) \
+ break; \
}
-/* load pre increment */
-#define LHPREUP() \
-{ \
- int done = 1 ; \
- temp = LHS + GetLS7RHS(state,instr) ; \
- switch (BITS(5,6)) { \
- case 1: /* H */ \
- (void)LoadHalfWord(state,instr,temp,LUNSIGNED) ; \
- break ; \
- case 2: /* SB */ \
- (void)LoadByte(state,instr,temp,LSIGNED) ; \
- break ; \
- case 3: /* SH */ \
- (void)LoadHalfWord(state,instr,temp,LSIGNED) ; \
- break ; \
- case 0: /* SWP handled elsewhere */ \
- default: \
- done = 0 ; \
- break ; \
- } \
- if (done) \
- break ; \
+/* Load pre increment. */
+#define LHPREUP() \
+{ \
+ int done = 1; \
+ \
+ temp = LHS + GetLS7RHS (state, instr); \
+ switch (BITS (5, 6)) \
+ { \
+ case 1: /* H */ \
+ (void) LoadHalfWord (state, instr, temp, LUNSIGNED); \
+ break; \
+ case 2: /* SB */ \
+ (void) LoadByte (state, instr, temp, LSIGNED); \
+ break; \
+ case 3: /* SH */ \
+ (void) LoadHalfWord (state, instr, temp, LSIGNED); \
+ break; \
+ case 0: \
+ /* SWP handled elsewhere. */ \
+ default: \
+ done = 0; \
+ break; \
+ } \
+ if (done) \
+ break; \
}
-/* load pre increment writeback */
-#define LHPREUPWB() \
-{ \
- int done = 1 ; \
- temp = LHS + GetLS7RHS(state, instr) ; \
- switch (BITS(5,6)) { \
- case 1: /* H */ \
- if (LoadHalfWord(state,instr,temp,LUNSIGNED)) \
- LSBase = temp ; \
- break ; \
- case 2: /* SB */ \
- if (LoadByte(state,instr,temp,LSIGNED)) \
- LSBase = temp ; \
- break ; \
- case 3: /* SH */ \
- if (LoadHalfWord(state,instr,temp,LSIGNED)) \
- LSBase = temp ; \
- break ; \
- case 0: /* SWP handled elsewhere */ \
- default: \
- done = 0 ; \
- break ; \
- } \
- if (done) \
- break ; \
+/* Load pre increment writeback. */
+#define LHPREUPWB() \
+{ \
+ int done = 1; \
+ \
+ temp = LHS + GetLS7RHS (state, instr); \
+ switch (BITS (5, 6)) \
+ { \
+ case 1: /* H */ \
+ if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 2: /* SB */ \
+ if (LoadByte (state, instr, temp, LSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 3: /* SH */ \
+ if (LoadHalfWord (state, instr, temp, LSIGNED)) \
+ LSBase = temp; \
+ break; \
+ case 0: \
+ /* SWP handled elsewhere. */ \
+ default: \
+ done = 0; \
+ break; \
+ } \
+ if (done) \
+ break; \
}
-/***************************************************************************\
-* EMULATION of ARM6 *
-\***************************************************************************/
-
-/* The PC pipeline value depends on whether ARM or Thumb instructions
- are being executed: */
-ARMword isize;
+/* Attempt to emulate an ARMv6 instruction.
+ Returns non-zero upon success. */
#ifdef MODE32
-ARMword ARMul_Emulate32(register ARMul_State *state)
+static int
+handle_v6_insn (ARMul_State * state, ARMword instr)
{
-#else
-ARMword ARMul_Emulate26(register ARMul_State *state)
+ ARMword val;
+ ARMword Rd;
+ ARMword Rm;
+ ARMword Rn;
+
+ switch (BITS (20, 27))
+ {
+#if 0
+ case 0x03: printf ("Unhandled v6 insn: ldr\n"); break;
+ case 0x04: printf ("Unhandled v6 insn: umaal\n"); break;
+ case 0x06: printf ("Unhandled v6 insn: mls/str\n"); break;
+ case 0x16: printf ("Unhandled v6 insn: smi\n"); break;
+ case 0x18: printf ("Unhandled v6 insn: strex\n"); break;
+ case 0x19: printf ("Unhandled v6 insn: ldrex\n"); break;
+ case 0x1a: printf ("Unhandled v6 insn: strexd\n"); break;
+ case 0x1b: printf ("Unhandled v6 insn: ldrexd\n"); break;
+ case 0x1c: printf ("Unhandled v6 insn: strexb\n"); break;
+ case 0x1d: printf ("Unhandled v6 insn: ldrexb\n"); break;
+ case 0x1e: printf ("Unhandled v6 insn: strexh\n"); break;
+ case 0x1f: printf ("Unhandled v6 insn: ldrexh\n"); break;
+ case 0x32: printf ("Unhandled v6 insn: nop/sev/wfe/wfi/yield\n"); break;
+ case 0x3f: printf ("Unhandled v6 insn: rbit\n"); break;
+#endif
+ case 0x61: printf ("Unhandled v6 insn: sadd/ssub\n"); break;
+ case 0x63: printf ("Unhandled v6 insn: shadd/shsub\n"); break;
+ case 0x6c: printf ("Unhandled v6 insn: uxtb16/uxtab16\n"); break;
+ case 0x70: printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); break;
+ case 0x74: printf ("Unhandled v6 insn: smlald/smlsld\n"); break;
+ case 0x75: printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); break;
+ case 0x78: printf ("Unhandled v6 insn: usad/usada8\n"); break;
+
+ case 0x30:
+ {
+ /* MOVW<c> <Rd>,#<imm16>
+ instr[31,28] = cond
+ instr[27,20] = 0011 0000
+ instr[19,16] = imm4
+ instr[15,12] = Rd
+ instr[11, 0] = imm12. */
+ Rd = BITS (12, 15);
+ val = (BITS (16, 19) << 12) | BITS (0, 11);
+ state->Reg[Rd] = val;
+ return 1;
+ }
+
+ case 0x34:
+ {
+ /* MOVT<c> <Rd>,#<imm16>
+ instr[31,28] = cond
+ instr[27,20] = 0011 0100
+ instr[19,16] = imm4
+ instr[15,12] = Rd
+ instr[11, 0] = imm12. */
+ Rd = BITS (12, 15);
+ val = (BITS (16, 19) << 12) | BITS (0, 11);
+ state->Reg[Rd] &= 0xFFFF;
+ state->Reg[Rd] |= val << 16;
+ return 1;
+ }
+
+ case 0x62:
+ {
+ ARMword val1;
+ ARMword val2;
+ ARMsword n, m, r;
+ int i;
+
+ Rd = BITS (12, 15);
+ Rn = BITS (16, 19);
+ Rm = BITS (0, 3);
+
+ if (Rd == 15 || Rn == 15 || Rm == 15)
+ break;
+
+ val1 = state->Reg[Rn];
+ val2 = state->Reg[Rm];
+
+ switch (BITS (4, 11))
+ {
+ case 0xF1: /* QADD16<c> <Rd>,<Rn>,<Rm>. */
+ state->Reg[Rd] = 0;
+
+ for (i = 0; i < 32; i+= 16)
+ {
+ n = (val1 >> i) & 0xFFFF;
+ if (n & 0x8000)
+ n |= -(1 << 16);
+
+ m = (val2 >> i) & 0xFFFF;
+ if (m & 0x8000)
+ m |= -(1 << 16);
+
+ r = n + m;
+
+ if (r > 0x7FFF)
+ r = 0x7FFF;
+ else if (r < -(0x8000))
+ r = - 0x8000;
+
+ state->Reg[Rd] |= (r & 0xFFFF) << i;
+ }
+ return 1;
+
+ case 0xF3: /* QASX<c> <Rd>,<Rn>,<Rm>. */
+ n = val1 & 0xFFFF;
+ if (n & 0x8000)
+ n |= -(1 << 16);
+
+ m = (val2 >> 16) & 0xFFFF;
+ if (m & 0x8000)
+ m |= -(1 << 16);
+
+ r = n - m;
+
+ if (r > 0x7FFF)
+ r = 0x7FFF;
+ else if (r < -(0x8000))
+ r = - 0x8000;
+
+ state->Reg[Rd] = (r & 0xFFFF);
+
+ n = (val1 >> 16) & 0xFFFF;
+ if (n & 0x8000)
+ n |= -(1 << 16);
+
+ m = val2 & 0xFFFF;
+ if (m & 0x8000)
+ m |= -(1 << 16);
+
+ r = n + m;
+
+ if (r > 0x7FFF)
+ r = 0x7FFF;
+ else if (r < -(0x8000))
+ r = - 0x8000;
+
+ state->Reg[Rd] |= (r & 0xFFFF) << 16;
+ return 1;
+
+ case 0xF5: /* QSAX<c> <Rd>,<Rn>,<Rm>. */
+ n = val1 & 0xFFFF;
+ if (n & 0x8000)
+ n |= -(1 << 16);
+
+ m = (val2 >> 16) & 0xFFFF;
+ if (m & 0x8000)
+ m |= -(1 << 16);
+
+ r = n + m;
+
+ if (r > 0x7FFF)
+ r = 0x7FFF;
+ else if (r < -(0x8000))
+ r = - 0x8000;
+
+ state->Reg[Rd] = (r & 0xFFFF);
+
+ n = (val1 >> 16) & 0xFFFF;
+ if (n & 0x8000)
+ n |= -(1 << 16);
+
+ m = val2 & 0xFFFF;
+ if (m & 0x8000)
+ m |= -(1 << 16);
+
+ r = n - m;
+
+ if (r > 0x7FFF)
+ r = 0x7FFF;
+ else if (r < -(0x8000))
+ r = - 0x8000;
+
+ state->Reg[Rd] |= (r & 0xFFFF) << 16;
+ return 1;
+
+ case 0xF7: /* QSUB16<c> <Rd>,<Rn>,<Rm>. */
+ state->Reg[Rd] = 0;
+
+ for (i = 0; i < 32; i+= 16)
+ {
+ n = (val1 >> i) & 0xFFFF;
+ if (n & 0x8000)
+ n |= -(1 << 16);
+
+ m = (val2 >> i) & 0xFFFF;
+ if (m & 0x8000)
+ m |= -(1 << 16);
+
+ r = n - m;
+
+ if (r > 0x7FFF)
+ r = 0x7FFF;
+ else if (r < -(0x8000))
+ r = - 0x8000;
+
+ state->Reg[Rd] |= (r & 0xFFFF) << i;
+ }
+ return 1;
+
+ case 0xF9: /* QADD8<c> <Rd>,<Rn>,<Rm>. */
+ state->Reg[Rd] = 0;
+
+ for (i = 0; i < 32; i+= 8)
+ {
+ n = (val1 >> i) & 0xFF;
+ if (n & 0x80)
+ n |= - (1 << 8);
+
+ m = (val2 >> i) & 0xFF;
+ if (m & 0x80)
+ m |= - (1 << 8);
+
+ r = n + m;
+
+ if (r > 127)
+ r = 127;
+ else if (r < -128)
+ r = -128;
+
+ state->Reg[Rd] |= (r & 0xFF) << i;
+ }
+ return 1;
+
+ case 0xFF: /* QSUB8<c> <Rd>,<Rn>,<Rm>. */
+ state->Reg[Rd] = 0;
+
+ for (i = 0; i < 32; i+= 8)
+ {
+ n = (val1 >> i) & 0xFF;
+ if (n & 0x80)
+ n |= - (1 << 8);
+
+ m = (val2 >> i) & 0xFF;
+ if (m & 0x80)
+ m |= - (1 << 8);
+
+ r = n - m;
+
+ if (r > 127)
+ r = 127;
+ else if (r < -128)
+ r = -128;
+
+ state->Reg[Rd] |= (r & 0xFF) << i;
+ }
+ return 1;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case 0x65:
+ {
+ ARMword valn;
+ ARMword valm;
+ ARMword res1, res2, res3, res4;
+
+ /* U{ADD|SUB}{8|16}<c> <Rd>, <Rn>, <Rm>
+ instr[31,28] = cond
+ instr[27,20] = 0110 0101
+ instr[19,16] = Rn
+ instr[15,12] = Rd
+ instr[11, 8] = 1111
+ instr[ 7, 4] = opcode: UADD8 (1001), UADD16 (0001), USUB8 (1111), USUB16 (0111)
+ instr[ 3, 0] = Rm. */
+ if (BITS (8, 11) != 0xF)
+ break;
+
+ Rn = BITS (16, 19);
+ Rd = BITS (12, 15);
+ Rm = BITS (0, 3);
+
+ if (Rn == 15 || Rd == 15 || Rm == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ break;
+ }
+
+ valn = state->Reg[Rn];
+ valm = state->Reg[Rm];
+
+ switch (BITS (4, 7))
+ {
+ case 1: /* UADD16. */
+ res1 = (valn & 0xFFFF) + (valm & 0xFFFF);
+ if (res1 > 0xFFFF)
+ state->Cpsr |= (GE0 | GE1);
+ else
+ state->Cpsr &= ~ (GE0 | GE1);
+
+ res2 = (valn >> 16) + (valm >> 16);
+ if (res2 > 0xFFFF)
+ state->Cpsr |= (GE2 | GE3);
+ else
+ state->Cpsr &= ~ (GE2 | GE3);
+
+ state->Reg[Rd] = (res1 & 0xFFFF) | (res2 << 16);
+ return 1;
+
+ case 7: /* USUB16. */
+ res1 = (valn & 0xFFFF) - (valm & 0xFFFF);
+ if (res1 & 0x800000)
+ state->Cpsr |= (GE0 | GE1);
+ else
+ state->Cpsr &= ~ (GE0 | GE1);
+
+ res2 = (valn >> 16) - (valm >> 16);
+ if (res2 & 0x800000)
+ state->Cpsr |= (GE2 | GE3);
+ else
+ state->Cpsr &= ~ (GE2 | GE3);
+
+ state->Reg[Rd] = (res1 & 0xFFFF) | (res2 << 16);
+ return 1;
+
+ case 9: /* UADD8. */
+ res1 = (valn & 0xFF) + (valm & 0xFF);
+ if (res1 > 0xFF)
+ state->Cpsr |= GE0;
+ else
+ state->Cpsr &= ~ GE0;
+
+ res2 = ((valn >> 8) & 0xFF) + ((valm >> 8) & 0xFF);
+ if (res2 > 0xFF)
+ state->Cpsr |= GE1;
+ else
+ state->Cpsr &= ~ GE1;
+
+ res3 = ((valn >> 16) & 0xFF) + ((valm >> 16) & 0xFF);
+ if (res3 > 0xFF)
+ state->Cpsr |= GE2;
+ else
+ state->Cpsr &= ~ GE2;
+
+ res4 = (valn >> 24) + (valm >> 24);
+ if (res4 > 0xFF)
+ state->Cpsr |= GE3;
+ else
+ state->Cpsr &= ~ GE3;
+
+ state->Reg[Rd] = (res1 & 0xFF) | ((res2 << 8) & 0xFF00)
+ | ((res3 << 16) & 0xFF0000) | (res4 << 24);
+ return 1;
+
+ case 15: /* USUB8. */
+ res1 = (valn & 0xFF) - (valm & 0xFF);
+ if (res1 & 0x800000)
+ state->Cpsr |= GE0;
+ else
+ state->Cpsr &= ~ GE0;
+
+ res2 = ((valn >> 8) & 0XFF) - ((valm >> 8) & 0xFF);
+ if (res2 & 0x800000)
+ state->Cpsr |= GE1;
+ else
+ state->Cpsr &= ~ GE1;
+
+ res3 = ((valn >> 16) & 0XFF) - ((valm >> 16) & 0xFF);
+ if (res3 & 0x800000)
+ state->Cpsr |= GE2;
+ else
+ state->Cpsr &= ~ GE2;
+
+ res4 = (valn >> 24) - (valm >> 24) ;
+ if (res4 & 0x800000)
+ state->Cpsr |= GE3;
+ else
+ state->Cpsr &= ~ GE3;
+
+ state->Reg[Rd] = (res1 & 0xFF) | ((res2 << 8) & 0xFF00)
+ | ((res3 << 16) & 0xFF0000) | (res4 << 24);
+ return 1;
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ case 0x68:
+ {
+ ARMword res;
+
+ /* PKHBT<c> <Rd>,<Rn>,<Rm>{,LSL #<imm>}
+ PKHTB<c> <Rd>,<Rn>,<Rm>{,ASR #<imm>}
+ SXTAB16<c> <Rd>,<Rn>,<Rm>{,<rotation>}
+ SXTB16<c> <Rd>,<Rm>{,<rotation>}
+ SEL<c> <Rd>,<Rn>,<Rm>
+
+ instr[31,28] = cond
+ instr[27,20] = 0110 1000
+ instr[19,16] = Rn
+ instr[15,12] = Rd
+ instr[11, 7] = imm5 (PKH), 11111 (SEL), rr000 (SXTAB16 & SXTB16),
+ instr[6] = tb (PKH), 0 (SEL), 1 (SXT)
+ instr[5] = opcode: PKH (0), SEL/SXT (1)
+ instr[4] = 1
+ instr[ 3, 0] = Rm. */
+
+ if (BIT (4) != 1)
+ break;
+
+ if (BIT (5) == 0)
+ {
+ /* FIXME: Add implementation of PKH. */
+ fprintf (stderr, "PKH: NOT YET IMPLEMENTED\n");
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+
+ if (BIT (6) == 1)
+ {
+ /* FIXME: Add implementation of SXT. */
+ fprintf (stderr, "SXT: NOT YET IMPLEMENTED\n");
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+
+ Rn = BITS (16, 19);
+ Rd = BITS (12, 15);
+ Rm = BITS (0, 3);
+ if (Rn == 15 || Rm == 15 || Rd == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ break;
+ }
+
+ res = (state->Reg[(state->Cpsr & GE0) ? Rn : Rm]) & 0xFF;
+ res |= (state->Reg[(state->Cpsr & GE1) ? Rn : Rm]) & 0xFF00;
+ res |= (state->Reg[(state->Cpsr & GE2) ? Rn : Rm]) & 0xFF0000;
+ res |= (state->Reg[(state->Cpsr & GE3) ? Rn : Rm]) & 0xFF000000;
+ state->Reg[Rd] = res;
+ return 1;
+ }
+
+ case 0x6a:
+ {
+ int ror = -1;
+
+ switch (BITS (4, 11))
+ {
+ case 0x07: ror = 0; break;
+ case 0x47: ror = 8; break;
+ case 0x87: ror = 16; break;
+ case 0xc7: ror = 24; break;
+
+ case 0x01:
+ case 0xf3:
+ printf ("Unhandled v6 insn: ssat\n");
+ return 0;
+
+ default:
+ break;
+ }
+
+ if (ror == -1)
+ {
+ if (BITS (4, 6) == 0x7)
+ {
+ printf ("Unhandled v6 insn: ssat\n");
+ return 0;
+ }
+ break;
+ }
+
+ Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF);
+ if (Rm & 0x80)
+ Rm |= 0xffffff00;
+
+ if (BITS (16, 19) == 0xf)
+ /* SXTB */
+ state->Reg[BITS (12, 15)] = Rm;
+ else
+ /* SXTAB */
+ state->Reg[BITS (12, 15)] += Rm;
+ }
+ return 1;
+
+ case 0x6b:
+ {
+ int ror = -1;
+
+ switch (BITS (4, 11))
+ {
+ case 0x07: ror = 0; break;
+ case 0x47: ror = 8; break;
+ case 0x87: ror = 16; break;
+ case 0xc7: ror = 24; break;
+
+ case 0xf3:
+ {
+ /* REV<c> <Rd>,<Rm>
+ instr[31,28] = cond
+ instr[27,20] = 0110 1011
+ instr[19,16] = 1111
+ instr[15,12] = Rd
+ instr[11, 4] = 1111 0011
+ instr[ 3, 0] = Rm. */
+ if (BITS (16, 19) != 0xF)
+ break;
+
+ Rd = BITS (12, 15);
+ Rm = BITS (0, 3);
+ if (Rd == 15 || Rm == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ break;
+ }
+
+ val = state->Reg[Rm] << 24;
+ val |= ((state->Reg[Rm] << 8) & 0xFF0000);
+ val |= ((state->Reg[Rm] >> 8) & 0xFF00);
+ val |= ((state->Reg[Rm] >> 24));
+ state->Reg[Rd] = val;
+ return 1;
+ }
+
+ case 0xfb:
+ {
+ /* REV16<c> <Rd>,<Rm>. */
+ if (BITS (16, 19) != 0xF)
+ break;
+
+ Rd = BITS (12, 15);
+ Rm = BITS (0, 3);
+ if (Rd == 15 || Rm == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ break;
+ }
+
+ val = 0;
+ val |= ((state->Reg[Rm] >> 8) & 0x00FF00FF);
+ val |= ((state->Reg[Rm] << 8) & 0xFF00FF00);
+ state->Reg[Rd] = val;
+ return 1;
+ }
+
+ default:
+ break;
+ }
+
+ if (ror == -1)
+ break;
+
+ Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF);
+ if (Rm & 0x8000)
+ Rm |= 0xffff0000;
+
+ if (BITS (16, 19) == 0xf)
+ /* SXTH */
+ state->Reg[BITS (12, 15)] = Rm;
+ else
+ /* SXTAH */
+ state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm;
+ }
+ return 1;
+
+ case 0x6e:
+ {
+ int ror = -1;
+
+ switch (BITS (4, 11))
+ {
+ case 0x07: ror = 0; break;
+ case 0x47: ror = 8; break;
+ case 0x87: ror = 16; break;
+ case 0xc7: ror = 24; break;
+
+ case 0x01:
+ case 0xf3:
+ printf ("Unhandled v6 insn: usat\n");
+ return 0;
+
+ default:
+ break;
+ }
+
+ if (ror == -1)
+ {
+ if (BITS (4, 6) == 0x7)
+ {
+ printf ("Unhandled v6 insn: usat\n");
+ return 0;
+ }
+ break;
+ }
+
+ Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF);
+
+ if (BITS (16, 19) == 0xf)
+ /* UXTB */
+ state->Reg[BITS (12, 15)] = Rm;
+ else
+ /* UXTAB */
+ state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm;
+ }
+ return 1;
+
+ case 0x6f:
+ {
+ int i;
+ int ror = -1;
+
+ switch (BITS (4, 11))
+ {
+ case 0x07: ror = 0; break;
+ case 0x47: ror = 8; break;
+ case 0x87: ror = 16; break;
+ case 0xc7: ror = 24; break;
+
+ case 0xf3: /* RBIT */
+ if (BITS (16, 19) != 0xF)
+ break;
+ Rd = BITS (12, 15);
+ state->Reg[Rd] = 0;
+ Rm = state->Reg[BITS (0, 3)];
+ for (i = 0; i < 32; i++)
+ if (Rm & (1 << i))
+ state->Reg[Rd] |= (1 << (31 - i));
+ return 1;
+
+ case 0xfb:
+ printf ("Unhandled v6 insn: revsh\n");
+ return 0;
+
+ default:
+ break;
+ }
+
+ if (ror == -1)
+ break;
+
+ Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF);
+
+ if (BITS (16, 19) == 0xf)
+ /* UXT */
+ state->Reg[BITS (12, 15)] = Rm;
+ else
+ /* UXTAH */
+ state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm;
+ }
+ return 1;
+
+ case 0x71:
+ case 0x73:
+ {
+ ARMword valn, valm;
+ /* SDIV<c> <Rd>,<Rn>,<Rm>
+ UDIV<c> <Rd>,<Rn>,<Rm>
+ instr[31,28] = cond
+ instr[27,20] = 0111 0001 (SDIV), 0111 0011 (UDIV)
+ instr[21,21] = sign
+ instr[19,16] = Rn
+ instr[15,12] = 1111
+ instr[11, 8] = Rd
+ instr[ 7, 4] = 1111
+ instr[ 3, 0] = Rm */
+ /* These bit-positions are confusing!
+ instr[15,12] = Rd
+ instr[11, 8] = 1111 */
+
+#if 0 /* This is what I would expect: */
+ Rn = BITS (16, 19);
+ Rd = BITS (8, 11);
+ Rm = BITS (0, 3);
+#else /* This seem to work: */
+ Rd = BITS (16, 19);
+ Rm = BITS (8, 11);
+ Rn = BITS (0, 3);
+#endif
+ if (Rn == 15 || Rd == 15 || Rm == 15
+ || Rn == 13 || Rd == 13 || Rm == 13)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ break;
+ }
+
+ valn = state->Reg[Rn];
+ valm = state->Reg[Rm];
+
+ if (valm == 0)
+ {
+#if 0
+ /* Exceptions: UsageFault, address 20
+ Note: UsageFault is for Cortex-M; I don't know what it would be on non-Cortex-M. */
+ ARMul_Abort (state, address);
+#endif
+ printf ("Unhandled v6 insn: %cDIV divide by zero exception\n", "SU"[BIT(21)]);
+ }
+ else
+ {
+ if(BIT(21))
+ {
+ val = valn / valm;
+ }
+ else
+ {
+ val = ((ARMsword)valn / (ARMsword)valm);
+ }
+ state->Reg[Rd] = val;
+ }
+ return 1;
+ }
+
+ case 0x7c:
+ case 0x7d:
+ {
+ int lsb;
+ int msb;
+ ARMword mask;
+
+ /* BFC<c> <Rd>,#<lsb>,#<width>
+ BFI<c> <Rd>,<Rn>,#<lsb>,#<width>
+
+ instr[31,28] = cond
+ instr[27,21] = 0111 110
+ instr[20,16] = msb
+ instr[15,12] = Rd
+ instr[11, 7] = lsb
+ instr[ 6, 4] = 001 1111
+ instr[ 3, 0] = Rn (BFI) / 1111 (BFC). */
+
+ if (BITS (4, 6) != 0x1)
+ break;
+
+ Rd = BITS (12, 15);
+ if (Rd == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ }
+
+ lsb = BITS (7, 11);
+ msb = BITS (16, 20);
+ if (lsb > msb)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ }
+
+ mask = -(1 << lsb);
+ mask &= ~(-(1 << (msb + 1)));
+ state->Reg[Rd] &= ~ mask;
+
+ Rn = BITS (0, 3);
+ if (Rn != 0xF)
+ {
+ ARMword val = state->Reg[Rn] & ~(-(1 << ((msb + 1) - lsb)));
+ state->Reg[Rd] |= val << lsb;
+ }
+ return 1;
+ }
+ case 0x7b:
+ case 0x7a: /* SBFX<c> <Rd>,<Rn>,#<lsb>,#<width>. */
+ {
+ int lsb;
+ int widthm1;
+ ARMsword sval;
+
+ if (BITS (4, 6) != 0x5)
+ break;
+
+ Rd = BITS (12, 15);
+ if (Rd == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ }
+
+ Rn = BITS (0, 3);
+ if (Rn == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ }
+
+ lsb = BITS (7, 11);
+ widthm1 = BITS (16, 20);
+
+ sval = state->Reg[Rn];
+ sval <<= (31 - (lsb + widthm1));
+ sval >>= (31 - widthm1);
+ state->Reg[Rd] = sval;
+
+ return 1;
+ }
+
+ case 0x7f:
+ case 0x7e:
+ {
+ int lsb;
+ int widthm1;
+
+ /* UBFX<c> <Rd>,<Rn>,#<lsb>,#<width>
+ instr[31,28] = cond
+ instr[27,21] = 0111 111
+ instr[20,16] = widthm1
+ instr[15,12] = Rd
+ instr[11, 7] = lsb
+ instr[ 6, 4] = 101
+ instr[ 3, 0] = Rn. */
+
+ if (BITS (4, 6) != 0x5)
+ break;
+
+ Rd = BITS (12, 15);
+ if (Rd == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ }
+
+ Rn = BITS (0, 3);
+ if (Rn == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ state->Emulate = FALSE;
+ }
+
+ lsb = BITS (7, 11);
+ widthm1 = BITS (16, 20);
+
+ val = state->Reg[Rn];
+ val >>= lsb;
+ val &= ~(-(1 << (widthm1 + 1)));
+
+ state->Reg[Rd] = val;
+
+ return 1;
+ }
+#if 0
+ case 0x84: printf ("Unhandled v6 insn: srs\n"); break;
+#endif
+ default:
+ break;
+ }
+ printf ("Unhandled v6 insn: UNKNOWN: %08x\n", instr);
+ return 0;
+}
+#endif
+
+static void
+handle_VFP_move (ARMul_State * state, ARMword instr)
{
+ switch (BITS (20, 27))
+ {
+ case 0xC4:
+ case 0xC5:
+ switch (BITS (4, 11))
+ {
+ case 0xA1:
+ case 0xA3:
+ {
+ /* VMOV two core <-> two VFP single precision. */
+ int sreg = (BITS (0, 3) << 1) | BIT (5);
+
+ if (BIT (20))
+ {
+ state->Reg[BITS (12, 15)] = VFP_uword (sreg);
+ state->Reg[BITS (16, 19)] = VFP_uword (sreg + 1);
+ }
+ else
+ {
+ VFP_uword (sreg) = state->Reg[BITS (12, 15)];
+ VFP_uword (sreg + 1) = state->Reg[BITS (16, 19)];
+ }
+ }
+ break;
+
+ case 0xB1:
+ case 0xB3:
+ {
+ /* VMOV two core <-> VFP double precision. */
+ int dreg = BITS (0, 3) | (BIT (5) << 4);
+
+ if (BIT (20))
+ {
+ if (trace)
+ fprintf (stderr, " VFP: VMOV: r%d r%d <= d%d\n",
+ BITS (12, 15), BITS (16, 19), dreg);
+
+ state->Reg[BITS (12, 15)] = VFP_dword (dreg);
+ state->Reg[BITS (16, 19)] = VFP_dword (dreg) >> 32;
+ }
+ else
+ {
+ VFP_dword (dreg) = state->Reg[BITS (16, 19)];
+ VFP_dword (dreg) <<= 32;
+ VFP_dword (dreg) |= state->Reg[BITS (12, 15)];
+
+ if (trace)
+ fprintf (stderr, " VFP: VMOV: d%d <= r%d r%d : %g\n",
+ dreg, BITS (16, 19), BITS (12, 15),
+ VFP_dval (dreg));
+ }
+ }
+ break;
+
+ default:
+ fprintf (stderr, "SIM: VFP: Unimplemented move insn %x\n", BITS (20, 27));
+ break;
+ }
+ break;
+
+ case 0xe0:
+ case 0xe1:
+ /* VMOV single core <-> VFP single precision. */
+ if (BITS (0, 6) != 0x10 || BITS (8, 11) != 0xA)
+ fprintf (stderr, "SIM: VFP: Unimplemented move insn %x\n", BITS (20, 27));
+ else
+ {
+ int sreg = (BITS (16, 19) << 1) | BIT (7);
+
+ if (BIT (20))
+ state->Reg[DESTReg] = VFP_uword (sreg);
+ else
+ VFP_uword (sreg) = state->Reg[DESTReg];
+ }
+ break;
+
+ default:
+ fprintf (stderr, "SIM: VFP: Unimplemented move insn %x\n", BITS (20, 27));
+ return;
+ }
+}
+
+/* EMULATION of ARM6. */
+
+ARMword
+#ifdef MODE32
+ARMul_Emulate32 (ARMul_State * state)
+#else
+ARMul_Emulate26 (ARMul_State * state)
#endif
- register ARMword instr, /* the current instruction */
- dest, /* almost the DestBus */
- temp, /* ubiquitous third hand */
- pc ; /* the address of the current instruction */
- ARMword lhs, rhs ; /* almost the ABus and BBus */
- ARMword decoded, loaded ; /* instruction pipeline */
-
-/***************************************************************************\
-* Execute the next instruction *
-\***************************************************************************/
-
- if (state->NextInstr < PRIMEPIPE) {
- decoded = state->decoded ;
- loaded = state->loaded ;
- pc = state->pc ;
+{
+ ARMword instr; /* The current instruction. */
+ ARMword dest = 0; /* Almost the DestBus. */
+ ARMword temp; /* Ubiquitous third hand. */
+ ARMword pc = 0; /* The address of the current instruction. */
+ ARMword lhs; /* Almost the ABus and BBus. */
+ ARMword rhs;
+ ARMword decoded = 0; /* Instruction pipeline. */
+ ARMword loaded = 0;
+
+ /* Execute the next instruction. */
+
+ if (state->NextInstr < PRIMEPIPE)
+ {
+ decoded = state->decoded;
+ loaded = state->loaded;
+ pc = state->pc;
}
- do { /* just keep going */
-#ifdef MODET
- if (TFLAG) {
- isize = 2;
- } else
-#endif
- isize = 4;
- switch (state->NextInstr) {
- case SEQ :
- state->Reg[15] += isize ; /* Advance the pipeline, and an S cycle */
- pc += isize ;
- instr = decoded ;
- decoded = loaded ;
- loaded = ARMul_LoadInstrS(state,pc+(isize * 2),isize) ;
- break ;
-
- case NONSEQ :
- state->Reg[15] += isize ; /* Advance the pipeline, and an N cycle */
- pc += isize ;
- instr = decoded ;
- decoded = loaded ;
- loaded = ARMul_LoadInstrN(state,pc+(isize * 2),isize) ;
- NORMALCYCLE ;
- break ;
-
- case PCINCEDSEQ :
- pc += isize ; /* Program counter advanced, and an S cycle */
- instr = decoded ;
- decoded = loaded ;
- loaded = ARMul_LoadInstrS(state,pc+(isize * 2),isize) ;
- NORMALCYCLE ;
- break ;
-
- case PCINCEDNONSEQ :
- pc += isize ; /* Program counter advanced, and an N cycle */
- instr = decoded ;
- decoded = loaded ;
- loaded = ARMul_LoadInstrN(state,pc+(isize * 2),isize) ;
- NORMALCYCLE ;
- break ;
-
- case RESUME : /* The program counter has been changed */
- pc = state->Reg[15] ;
+ do
+ {
+ /* Just keep going. */
+ isize = INSN_SIZE;
+
+ switch (state->NextInstr)
+ {
+ case SEQ:
+ /* Advance the pipeline, and an S cycle. */
+ state->Reg[15] += isize;
+ pc += isize;
+ instr = decoded;
+ decoded = loaded;
+ loaded = ARMul_LoadInstrS (state, pc + (isize * 2), isize);
+ break;
+
+ case NONSEQ:
+ /* Advance the pipeline, and an N cycle. */
+ state->Reg[15] += isize;
+ pc += isize;
+ instr = decoded;
+ decoded = loaded;
+ loaded = ARMul_LoadInstrN (state, pc + (isize * 2), isize);
+ NORMALCYCLE;
+ break;
+
+ case PCINCEDSEQ:
+ /* Program counter advanced, and an S cycle. */
+ pc += isize;
+ instr = decoded;
+ decoded = loaded;
+ loaded = ARMul_LoadInstrS (state, pc + (isize * 2), isize);
+ NORMALCYCLE;
+ break;
+
+ case PCINCEDNONSEQ:
+ /* Program counter advanced, and an N cycle. */
+ pc += isize;
+ instr = decoded;
+ decoded = loaded;
+ loaded = ARMul_LoadInstrN (state, pc + (isize * 2), isize);
+ NORMALCYCLE;
+ break;
+
+ case RESUME:
+ /* The program counter has been changed. */
+ pc = state->Reg[15];
#ifndef MODE32
- pc = pc & R15PCBITS ;
-#endif
- state->Reg[15] = pc + (isize * 2) ;
- state->Aborted = 0 ;
- instr = ARMul_ReLoadInstr(state,pc,isize) ;
- decoded = ARMul_ReLoadInstr(state,pc + isize,isize) ;
- loaded = ARMul_ReLoadInstr(state,pc + isize * 2,isize) ;
- NORMALCYCLE ;
- break ;
-
- default : /* The program counter has been changed */
- pc = state->Reg[15] ;
+ pc = pc & R15PCBITS;
+#endif
+ state->Reg[15] = pc + (isize * 2);
+ state->Aborted = 0;
+ instr = ARMul_ReLoadInstr (state, pc, isize);
+ decoded = ARMul_ReLoadInstr (state, pc + isize, isize);
+ loaded = ARMul_ReLoadInstr (state, pc + isize * 2, isize);
+ NORMALCYCLE;
+ break;
+
+ default:
+ /* The program counter has been changed. */
+ pc = state->Reg[15];
#ifndef MODE32
- pc = pc & R15PCBITS ;
-#endif
- state->Reg[15] = pc + (isize * 2) ;
- state->Aborted = 0 ;
- instr = ARMul_LoadInstrN(state,pc,isize) ;
- decoded = ARMul_LoadInstrS(state,pc + (isize),isize) ;
- loaded = ARMul_LoadInstrS(state,pc + (isize * 2),isize) ;
- NORMALCYCLE ;
- break ;
- }
- if (state->EventSet)
- ARMul_EnvokeEvent(state) ;
-
-#if 0
- /* Enable this for a helpful bit of debugging when tracing is needed. */
- fprintf (stderr, "pc: %x, instr: %x\n", pc & ~1, instr);
- if (instr == 0) abort ();
-#endif
-
- if (state->Exception) { /* Any exceptions */
- if (state->NresetSig == LOW) {
- ARMul_Abort(state,ARMul_ResetV) ;
- break ;
- }
- else if (!state->NfiqSig && !FFLAG) {
- ARMul_Abort(state,ARMul_FIQV) ;
- break ;
- }
- else if (!state->NirqSig && !IFLAG) {
- ARMul_Abort(state,ARMul_IRQV) ;
- break ;
- }
- }
-
- if (state->CallDebug > 0) {
- instr = ARMul_Debug(state,pc,instr) ;
- if (state->Emulate < ONCE) {
- state->NextInstr = RESUME ;
- break ;
- }
- if (state->Debug) {
- fprintf(stderr,"At %08lx Instr %08lx Mode %02lx\n",pc,instr,state->Mode) ;
- (void)fgetc(stdin) ;
- }
- }
- else
- if (state->Emulate < ONCE) {
- state->NextInstr = RESUME ;
- break ;
- }
-
- state->NumInstrs++ ;
+ pc = pc & R15PCBITS;
+#endif
+ state->Reg[15] = pc + (isize * 2);
+ state->Aborted = 0;
+ instr = ARMul_LoadInstrN (state, pc, isize);
+ decoded = ARMul_LoadInstrS (state, pc + (isize), isize);
+ loaded = ARMul_LoadInstrS (state, pc + (isize * 2), isize);
+ NORMALCYCLE;
+ break;
+ }
-#ifdef MODET
- /* Provide Thumb instruction decoding. If the processor is in Thumb
- mode, then we can simply decode the Thumb instruction, and map it
- to the corresponding ARM instruction (by directly loading the
- instr variable, and letting the normal ARM simulator
- execute). There are some caveats to ensure that the correct
- pipelined PC value is used when executing Thumb code, and also for
- dealing with the BL instruction. */
- if (TFLAG) { /* check if in Thumb mode */
- ARMword new;
- switch (ARMul_ThumbDecode(state,pc,instr,&new)) {
- case t_undefined:
- ARMul_UndefInstr(state,instr); /* This is a Thumb instruction */
- break;
-
- case t_branch: /* already processed */
- goto donext;
-
- case t_decoded: /* ARM instruction available */
- instr = new; /* so continue instruction decoding */
- break;
+ if (state->EventSet)
+ ARMul_EnvokeEvent (state);
+
+ if (! TFLAG && trace)
+ {
+ fprintf (stderr, "pc: %x, ", pc & ~1);
+ if (! disas)
+ fprintf (stderr, "instr: %x\n", instr);
+ }
+
+ if (instr == 0 || pc < 0x10)
+ {
+ ARMul_Abort (state, ARMUndefinedInstrV);
+ state->Emulate = FALSE;
+ }
+
+#if 0 /* Enable this code to help track down stack alignment bugs. */
+ {
+ static ARMword old_sp = -1;
+
+ if (old_sp != state->Reg[13])
+ {
+ old_sp = state->Reg[13];
+ fprintf (stderr, "pc: %08x: SP set to %08x%s\n",
+ pc & ~1, old_sp, (old_sp % 8) ? " [UNALIGNED!]" : "");
+ }
}
- }
#endif
-/***************************************************************************\
-* Check the condition codes *
-\***************************************************************************/
- if ((temp = TOPBITS(28)) == AL)
- goto mainswitch ; /* vile deed in the need for speed */
-
- switch ((int)TOPBITS(28)) { /* check the condition code */
- case AL : temp=TRUE ;
- break ;
- case NV : temp=FALSE ;
- break ;
- case EQ : temp=ZFLAG ;
- break ;
- case NE : temp=!ZFLAG ;
- break ;
- case VS : temp=VFLAG ;
- break ;
- case VC : temp=!VFLAG ;
- break ;
- case MI : temp=NFLAG ;
- break ;
- case PL : temp=!NFLAG ;
- break ;
- case CS : temp=CFLAG ;
- break ;
- case CC : temp=!CFLAG ;
- break ;
- case HI : temp=(CFLAG && !ZFLAG) ;
- break ;
- case LS : temp=(!CFLAG || ZFLAG) ;
- break ;
- case GE : temp=((!NFLAG && !VFLAG) || (NFLAG && VFLAG)) ;
- break ;
- case LT : temp=((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) ;
- break ;
- case GT : temp=((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG)) ;
- break ;
- case LE : temp=((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG ;
- break ;
- } /* cc check */
-
-/***************************************************************************\
-* Actual execution of instructions begins here *
-\***************************************************************************/
-
- if (temp) { /* if the condition codes don't match, stop here */
-mainswitch:
-
- switch ((int)BITS(20,27)) {
-
-/***************************************************************************\
-* Data Processing Register RHS Instructions *
-\***************************************************************************/
-
- case 0x00 : /* AND reg and MUL */
+ if (state->Exception)
+ {
+ /* Any exceptions ? */
+ if (state->NresetSig == LOW)
+ {
+ ARMul_Abort (state, ARMul_ResetV);
+ break;
+ }
+ else if (!state->NfiqSig && !FFLAG)
+ {
+ ARMul_Abort (state, ARMul_FIQV);
+ break;
+ }
+ else if (!state->NirqSig && !IFLAG)
+ {
+ ARMul_Abort (state, ARMul_IRQV);
+ break;
+ }
+ }
+
+ if (state->CallDebug > 0)
+ {
+ if (state->Emulate < ONCE)
+ {
+ state->NextInstr = RESUME;
+ break;
+ }
+ if (state->Debug)
+ {
+ fprintf (stderr, "sim: At %08lx Instr %08lx Mode %02lx\n",
+ (long) pc, (long) instr, (long) state->Mode);
+ (void) fgetc (stdin);
+ }
+ }
+ else if (state->Emulate < ONCE)
+ {
+ state->NextInstr = RESUME;
+ break;
+ }
+
+ state->NumInstrs++;
+
#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, no write-back, down, post indexed */
- SHDOWNWB() ;
- break ;
- }
- /* TODO: CHECK: should 0xD and 0xF generate undefined intruction aborts? */
-#endif
- if (BITS(4,7) == 9) { /* MUL */
- rhs = state->Reg[MULRHSReg] ;
- if (MULLHSReg == MULDESTReg) {
- UNDEF_MULDestEQOp1 ;
- state->Reg[MULDESTReg] = 0 ;
- }
- else if (MULDESTReg != 15)
- state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs ;
- else {
- UNDEF_MULPCDest ;
- }
- for (dest = 0, temp = 0 ; dest < 32 ; dest++)
- if (rhs & (1L << dest))
- temp = dest ; /* mult takes this many/2 I cycles */
- ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
- }
- else { /* AND reg */
- rhs = DPRegRHS ;
- dest = LHS & rhs ;
- WRITEDEST(dest) ;
- }
- break ;
-
- case 0x01 : /* ANDS reg and MULS */
+ /* Provide Thumb instruction decoding. If the processor is in Thumb
+ mode, then we can simply decode the Thumb instruction, and map it
+ to the corresponding ARM instruction (by directly loading the
+ instr variable, and letting the normal ARM simulator
+ execute). There are some caveats to ensure that the correct
+ pipelined PC value is used when executing Thumb code, and also for
+ dealing with the BL instruction. */
+ if (TFLAG)
+ {
+ ARMword new;
+
+ /* Check if in Thumb mode. */
+ switch (ARMul_ThumbDecode (state, pc, instr, &new))
+ {
+ case t_undefined:
+ /* This is a Thumb instruction. */
+ ARMul_UndefInstr (state, instr);
+ goto donext;
+
+ case t_branch:
+ /* Already processed. */
+ goto donext;
+
+ case t_decoded:
+ /* ARM instruction available. */
+ if (disas || trace)
+ {
+ fprintf (stderr, " emulate as: ");
+ if (trace)
+ fprintf (stderr, "%08x ", new);
+ if (! disas)
+ fprintf (stderr, "\n");
+ }
+ instr = new;
+ /* So continue instruction decoding. */
+ break;
+ default:
+ break;
+ }
+ }
+#endif
+ if (disas)
+ print_insn (instr);
+
+ /* Check the condition codes. */
+ if ((temp = TOPBITS (28)) == AL)
+ /* Vile deed in the need for speed. */
+ goto mainswitch;
+
+ /* Check the condition code. */
+ switch ((int) TOPBITS (28))
+ {
+ case AL:
+ temp = TRUE;
+ break;
+ case NV:
+ if (state->is_v5)
+ {
+ if (BITS (25, 27) == 5) /* BLX(1) */
+ {
+ ARMword dest;
+
+ state->Reg[14] = pc + 4;
+
+ /* Force entry into Thumb mode. */
+ dest = pc + 8 + 1;
+ if (BIT (23))
+ dest += (NEGBRANCH + (BIT (24) << 1));
+ else
+ dest += POSBRANCH + (BIT (24) << 1);
+
+ WriteR15Branch (state, dest);
+ goto donext;
+ }
+ else if ((instr & 0xFC70F000) == 0xF450F000)
+ /* The PLD instruction. Ignored. */
+ goto donext;
+ else if ( ((instr & 0xfe500f00) == 0xfc100100)
+ || ((instr & 0xfe500f00) == 0xfc000100))
+ /* wldrw and wstrw are unconditional. */
+ goto mainswitch;
+ else
+ /* UNDEFINED in v5, UNPREDICTABLE in v3, v4, non executed in v1, v2. */
+ ARMul_UndefInstr (state, instr);
+ }
+ temp = FALSE;
+ break;
+ case EQ:
+ temp = ZFLAG;
+ break;
+ case NE:
+ temp = !ZFLAG;
+ break;
+ case VS:
+ temp = VFLAG;
+ break;
+ case VC:
+ temp = !VFLAG;
+ break;
+ case MI:
+ temp = NFLAG;
+ break;
+ case PL:
+ temp = !NFLAG;
+ break;
+ case CS:
+ temp = CFLAG;
+ break;
+ case CC:
+ temp = !CFLAG;
+ break;
+ case HI:
+ temp = (CFLAG && !ZFLAG);
+ break;
+ case LS:
+ temp = (!CFLAG || ZFLAG);
+ break;
+ case GE:
+ temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
+ break;
+ case LT:
+ temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
+ break;
+ case GT:
+ temp = ((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG));
+ break;
+ case LE:
+ temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
+ break;
+ } /* cc check */
+
+ /* Handle the Clock counter here. */
+ if (state->is_XScale)
+ {
+ ARMword cp14r0;
+ int ok;
+
+ ok = state->CPRead[14] (state, 0, & cp14r0);
+
+ if (ok && (cp14r0 & ARMul_CP14_R0_ENABLE))
+ {
+ unsigned long newcycles, nowtime = ARMul_Time (state);
+
+ newcycles = nowtime - state->LastTime;
+ state->LastTime = nowtime;
+
+ if (cp14r0 & ARMul_CP14_R0_CCD)
+ {
+ if (state->CP14R0_CCD == -1)
+ state->CP14R0_CCD = newcycles;
+ else
+ state->CP14R0_CCD += newcycles;
+
+ if (state->CP14R0_CCD >= 64)
+ {
+ newcycles = 0;
+
+ while (state->CP14R0_CCD >= 64)
+ state->CP14R0_CCD -= 64, newcycles++;
+
+ goto check_PMUintr;
+ }
+ }
+ else
+ {
+ ARMword cp14r1;
+ int do_int;
+
+ state->CP14R0_CCD = -1;
+check_PMUintr:
+ do_int = 0;
+ cp14r0 |= ARMul_CP14_R0_FLAG2;
+ (void) state->CPWrite[14] (state, 0, cp14r0);
+
+ ok = state->CPRead[14] (state, 1, & cp14r1);
+
+ /* Coded like this for portability. */
+ while (ok && newcycles)
+ {
+ if (cp14r1 == 0xffffffff)
+ {
+ cp14r1 = 0;
+ do_int = 1;
+ }
+ else
+ cp14r1 ++;
+
+ newcycles --;
+ }
+
+ (void) state->CPWrite[14] (state, 1, cp14r1);
+
+ if (do_int && (cp14r0 & ARMul_CP14_R0_INTEN2))
+ {
+ ARMword temp;
+
+ if (state->CPRead[13] (state, 8, & temp)
+ && (temp & ARMul_CP13_R8_PMUS))
+ ARMul_Abort (state, ARMul_FIQV);
+ else
+ ARMul_Abort (state, ARMul_IRQV);
+ }
+ }
+ }
+ }
+
+ /* Handle hardware instructions breakpoints here. */
+ if (state->is_XScale)
+ {
+ if ( (pc | 3) == (read_cp15_reg (14, 0, 8) | 2)
+ || (pc | 3) == (read_cp15_reg (14, 0, 9) | 2))
+ {
+ if (XScale_debug_moe (state, ARMul_CP14_R10_MOE_IB))
+ ARMul_OSHandleSWI (state, SWI_Breakpoint);
+ }
+ }
+
+ /* Actual execution of instructions begins here. */
+ /* If the condition codes don't match, stop here. */
+ if (temp)
+ {
+ mainswitch:
+
+ if (state->is_XScale)
+ {
+ if (BIT (20) == 0 && BITS (25, 27) == 0)
+ {
+ if (BITS (4, 7) == 0xD)
+ {
+ /* XScale Load Consecutive insn. */
+ ARMword temp = GetLS7RHS (state, instr);
+ ARMword temp2 = BIT (23) ? LHS + temp : LHS - temp;
+ ARMword addr = BIT (24) ? temp2 : LHS;
+
+ if (BIT (12))
+ ARMul_UndefInstr (state, instr);
+ else if (addr & 7)
+ /* Alignment violation. */
+ ARMul_Abort (state, ARMul_DataAbortV);
+ else
+ {
+ int wb = BIT (21) || (! BIT (24));
+
+ state->Reg[BITS (12, 15)] =
+ ARMul_LoadWordN (state, addr);
+ state->Reg[BITS (12, 15) + 1] =
+ ARMul_LoadWordN (state, addr + 4);
+ if (wb)
+ LSBase = temp2;
+ }
+
+ goto donext;
+ }
+ else if (BITS (4, 7) == 0xF)
+ {
+ /* XScale Store Consecutive insn. */
+ ARMword temp = GetLS7RHS (state, instr);
+ ARMword temp2 = BIT (23) ? LHS + temp : LHS - temp;
+ ARMword addr = BIT (24) ? temp2 : LHS;
+
+ if (BIT (12))
+ ARMul_UndefInstr (state, instr);
+ else if (addr & 7)
+ /* Alignment violation. */
+ ARMul_Abort (state, ARMul_DataAbortV);
+ else
+ {
+ ARMul_StoreWordN (state, addr,
+ state->Reg[BITS (12, 15)]);
+ ARMul_StoreWordN (state, addr + 4,
+ state->Reg[BITS (12, 15) + 1]);
+
+ if (BIT (21)|| ! BIT (24))
+ LSBase = temp2;
+ }
+
+ goto donext;
+ }
+ }
+
+ if (ARMul_HandleIwmmxt (state, instr))
+ goto donext;
+ }
+
+ switch ((int) BITS (20, 27))
+ {
+ /* Data Processing Register RHS Instructions. */
+
+ case 0x00: /* AND reg and MUL */
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, no write-back, down, post indexed */
- LHPOSTDOWN() ;
- /* fall through to rest of decoding */
- }
-#endif
- if (BITS(4,7) == 9) { /* MULS */
- rhs = state->Reg[MULRHSReg] ;
- if (MULLHSReg == MULDESTReg) {
- UNDEF_MULDestEQOp1 ;
- state->Reg[MULDESTReg] = 0 ;
- CLEARN ;
- SETZ ;
- }
- else if (MULDESTReg != 15) {
- dest = state->Reg[MULLHSReg] * rhs ;
- ARMul_NegZero(state,dest) ;
- state->Reg[MULDESTReg] = dest ;
- }
- else {
- UNDEF_MULPCDest ;
- }
- for (dest = 0, temp = 0 ; dest < 32 ; dest++)
- if (rhs & (1L << dest))
- temp = dest ; /* mult takes this many/2 I cycles */
- ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
- }
- else { /* ANDS reg */
- rhs = DPSRegRHS ;
- dest = LHS & rhs ;
- WRITESDEST(dest) ;
- }
- break ;
-
- case 0x02 : /* EOR reg and MLA */
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, no write-back, down, post indexed. */
+ SHDOWNWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ if (BITS (4, 7) == 9)
+ {
+ /* MUL */
+ rhs = state->Reg[MULRHSReg];
+ if (MULLHSReg == MULDESTReg)
+ {
+ UNDEF_MULDestEQOp1;
+ state->Reg[MULDESTReg] = 0;
+ }
+ else if (MULDESTReg != 15)
+ state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs;
+ else
+ UNDEF_MULPCDest;
+
+ for (dest = 0, temp = 0; dest < 32; dest ++)
+ if (rhs & (1L << dest))
+ temp = dest;
+
+ /* Mult takes this many/2 I cycles. */
+ ARMul_Icycles (state, ARMul_MultTable[temp], 0L);
+ }
+ else
+ {
+ /* AND reg. */
+ rhs = DPRegRHS;
+ dest = LHS & rhs;
+ WRITEDEST (dest);
+ }
+ break;
+
+ case 0x01: /* ANDS reg and MULS */
#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, write-back, down, post indexed */
- SHDOWNWB() ;
- break ;
- }
-#endif
- if (BITS(4,7) == 9) { /* MLA */
- rhs = state->Reg[MULRHSReg] ;
- if (MULLHSReg == MULDESTReg) {
- UNDEF_MULDestEQOp1 ;
- state->Reg[MULDESTReg] = state->Reg[MULACCReg] ;
- }
- else if (MULDESTReg != 15)
- state->Reg[MULDESTReg] = state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg] ;
- else {
- UNDEF_MULPCDest ;
- }
- for (dest = 0, temp = 0 ; dest < 32 ; dest++)
- if (rhs & (1L << dest))
- temp = dest ; /* mult takes this many/2 I cycles */
- ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
- }
- else {
- rhs = DPRegRHS ;
- dest = LHS ^ rhs ;
- WRITEDEST(dest) ;
- }
- break ;
-
- case 0x03 : /* EORS reg and MLAS */
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, no write-back, down, post indexed. */
+ LHPOSTDOWN ();
+ /* Fall through to rest of decoding. */
+#endif
+ if (BITS (4, 7) == 9)
+ {
+ /* MULS */
+ rhs = state->Reg[MULRHSReg];
+
+ if (MULLHSReg == MULDESTReg)
+ {
+ UNDEF_MULDestEQOp1;
+ state->Reg[MULDESTReg] = 0;
+ CLEARN;
+ SETZ;
+ }
+ else if (MULDESTReg != 15)
+ {
+ dest = state->Reg[MULLHSReg] * rhs;
+ ARMul_NegZero (state, dest);
+ state->Reg[MULDESTReg] = dest;
+ }
+ else
+ UNDEF_MULPCDest;
+
+ for (dest = 0, temp = 0; dest < 32; dest ++)
+ if (rhs & (1L << dest))
+ temp = dest;
+
+ /* Mult takes this many/2 I cycles. */
+ ARMul_Icycles (state, ARMul_MultTable[temp], 0L);
+ }
+ else
+ {
+ /* ANDS reg. */
+ rhs = DPSRegRHS;
+ dest = LHS & rhs;
+ WRITESDEST (dest);
+ }
+ break;
+
+ case 0x02: /* EOR reg and MLA */
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, write-back, down, post-indexed */
- LHPOSTDOWN() ;
- /* fall through to rest of the decoding */
- }
-#endif
- if (BITS(4,7) == 9) { /* MLAS */
- rhs = state->Reg[MULRHSReg] ;
- if (MULLHSReg == MULDESTReg) {
- UNDEF_MULDestEQOp1 ;
- dest = state->Reg[MULACCReg] ;
- ARMul_NegZero(state,dest) ;
- state->Reg[MULDESTReg] = dest ;
- }
- else if (MULDESTReg != 15) {
- dest = state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg] ;
- ARMul_NegZero(state,dest) ;
- state->Reg[MULDESTReg] = dest ;
- }
- else {
- UNDEF_MULPCDest ;
- }
- for (dest = 0, temp = 0 ; dest < 32 ; dest++)
- if (rhs & (1L << dest))
- temp = dest ; /* mult takes this many/2 I cycles */
- ARMul_Icycles(state,ARMul_MultTable[temp],0L) ;
- }
- else { /* EORS Reg */
- rhs = DPSRegRHS ;
- dest = LHS ^ rhs ;
- WRITESDEST(dest) ;
- }
- break ;
-
- case 0x04 : /* SUB reg */
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, write-back, down, post indexed. */
+ SHDOWNWB ();
+ break;
+ }
+#endif
+ if (BITS (4, 7) == 9)
+ { /* MLA */
+ rhs = state->Reg[MULRHSReg];
+ if (MULLHSReg == MULDESTReg)
+ {
+ UNDEF_MULDestEQOp1;
+ state->Reg[MULDESTReg] = state->Reg[MULACCReg];
+ }
+ else if (MULDESTReg != 15)
+ state->Reg[MULDESTReg] =
+ state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg];
+ else
+ UNDEF_MULPCDest;
+
+ for (dest = 0, temp = 0; dest < 32; dest ++)
+ if (rhs & (1L << dest))
+ temp = dest;
+
+ /* Mult takes this many/2 I cycles. */
+ ARMul_Icycles (state, ARMul_MultTable[temp], 0L);
+ }
+ else
+ {
+ rhs = DPRegRHS;
+ dest = LHS ^ rhs;
+ WRITEDEST (dest);
+ }
+ break;
+
+ case 0x03: /* EORS reg and MLAS */
#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, no write-back, down, post indexed */
- SHDOWNWB() ;
- break ;
- }
-#endif
- rhs = DPRegRHS;
- dest = LHS - rhs ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x05 : /* SUBS reg */
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, write-back, down, post-indexed. */
+ LHPOSTDOWN ();
+ /* Fall through to rest of the decoding. */
+#endif
+ if (BITS (4, 7) == 9)
+ {
+ /* MLAS */
+ rhs = state->Reg[MULRHSReg];
+
+ if (MULLHSReg == MULDESTReg)
+ {
+ UNDEF_MULDestEQOp1;
+ dest = state->Reg[MULACCReg];
+ ARMul_NegZero (state, dest);
+ state->Reg[MULDESTReg] = dest;
+ }
+ else if (MULDESTReg != 15)
+ {
+ dest =
+ state->Reg[MULLHSReg] * rhs + state->Reg[MULACCReg];
+ ARMul_NegZero (state, dest);
+ state->Reg[MULDESTReg] = dest;
+ }
+ else
+ UNDEF_MULPCDest;
+
+ for (dest = 0, temp = 0; dest < 32; dest ++)
+ if (rhs & (1L << dest))
+ temp = dest;
+
+ /* Mult takes this many/2 I cycles. */
+ ARMul_Icycles (state, ARMul_MultTable[temp], 0L);
+ }
+ else
+ {
+ /* EORS Reg. */
+ rhs = DPSRegRHS;
+ dest = LHS ^ rhs;
+ WRITESDEST (dest);
+ }
+ break;
+
+ case 0x04: /* SUB reg */
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, no write-back, down, post indexed */
- LHPOSTDOWN() ;
- /* fall through to the rest of the instruction decoding */
- }
-#endif
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = lhs - rhs ;
- if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,lhs,rhs,dest) ;
- ARMul_SubOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x06 : /* RSB reg */
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, no write-back, down, post indexed. */
+ SHDOWNWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ rhs = DPRegRHS;
+ dest = LHS - rhs;
+ WRITEDEST (dest);
+ break;
+
+ case 0x05: /* SUBS reg */
#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, write-back, down, post indexed */
- SHDOWNWB() ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = rhs - LHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x07 : /* RSBS reg */
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, no write-back, down, post indexed. */
+ LHPOSTDOWN ();
+ /* Fall through to the rest of the instruction decoding. */
+#endif
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = lhs - rhs;
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, dest);
+ ARMul_SubOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x06: /* RSB reg */
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, write-back, down, post indexed */
- LHPOSTDOWN() ;
- /* fall through to remainder of instruction decoding */
- }
-#endif
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = rhs - lhs ;
- if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,rhs,lhs,dest) ;
- ARMul_SubOverflow(state,rhs,lhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x08 : /* ADD reg */
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, write-back, down, post indexed. */
+ SHDOWNWB ();
+ break;
+ }
+#endif
+ rhs = DPRegRHS;
+ dest = rhs - LHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x07: /* RSBS reg */
#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, no write-back, up, post indexed */
- SHUPWB() ;
- break ;
- }
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, write-back, down, post indexed. */
+ LHPOSTDOWN ();
+ /* Fall through to remainder of instruction decoding. */
#endif
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = rhs - lhs;
+
+ if ((rhs >= lhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, rhs, lhs, dest);
+ ARMul_SubOverflow (state, rhs, lhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x08: /* ADD reg */
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32 = 64 */
- ARMul_Icycles(state,Multiply64(state,instr,LUNSIGNED,LDEFAULT),0L) ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = LHS + rhs ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x09 : /* ADDS reg */
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, no write-back, up, post indexed. */
+ SHUPWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, no write-back, up, post indexed */
- LHPOSTUP() ;
- /* fall through to remaining instruction decoding */
- }
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32 = 64 */
+ ARMul_Icycles (state,
+ Multiply64 (state, instr, LUNSIGNED,
+ LDEFAULT), 0L);
+ break;
+ }
#endif
+ rhs = DPRegRHS;
+ dest = LHS + rhs;
+ WRITEDEST (dest);
+ break;
+
+ case 0x09: /* ADDS reg */
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,Multiply64(state,instr,LUNSIGNED,LSCC),0L) ;
- break ;
- }
-#endif
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = lhs + rhs ;
- ASSIGNZ(dest==0) ;
- if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
- ASSIGNN(NEG(dest)) ;
- ARMul_AddCarry(state,lhs,rhs,dest) ;
- ARMul_AddOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARN ;
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x0a : /* ADC reg */
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, no write-back, up, post indexed. */
+ LHPOSTUP ();
+ /* Fall through to remaining instruction decoding. */
+#endif
#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, write-back, up, post-indexed */
- SHUPWB() ;
- break ;
- }
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ Multiply64 (state, instr, LUNSIGNED, LSCC),
+ 0L);
+ break;
+ }
#endif
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = lhs + rhs;
+ ASSIGNZ (dest == 0);
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ASSIGNN (NEG (dest));
+ ARMul_AddCarry (state, lhs, rhs, dest);
+ ARMul_AddOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARN;
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x0a: /* ADC reg */
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,MultiplyAdd64(state,instr,LUNSIGNED,LDEFAULT),0L) ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = LHS + rhs + CFLAG ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x0b : /* ADCS reg */
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, write-back, up, post-indexed. */
+ SHUPWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ MultiplyAdd64 (state, instr, LUNSIGNED,
+ LDEFAULT), 0L);
+ break;
+ }
+#endif
+ rhs = DPRegRHS;
+ dest = LHS + rhs + CFLAG;
+ WRITEDEST (dest);
+ break;
+
+ case 0x0b: /* ADCS reg */
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, write-back, up, post indexed */
- LHPOSTUP() ;
- /* fall through to remaining instruction decoding */
- }
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, write-back, up, post indexed. */
+ LHPOSTUP ();
+ /* Fall through to remaining instruction decoding. */
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ MultiplyAdd64 (state, instr, LUNSIGNED,
+ LSCC), 0L);
+ break;
+ }
#endif
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = lhs + rhs + CFLAG;
+ ASSIGNZ (dest == 0);
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ASSIGNN (NEG (dest));
+ ARMul_AddCarry (state, lhs, rhs, dest);
+ ARMul_AddOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARN;
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x0c: /* SBC reg */
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,MultiplyAdd64(state,instr,LUNSIGNED,LSCC),0L) ;
- break ;
- }
-#endif
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = lhs + rhs + CFLAG ;
- ASSIGNZ(dest==0) ;
- if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
- ASSIGNN(NEG(dest)) ;
- ARMul_AddCarry(state,lhs,rhs,dest) ;
- ARMul_AddOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARN ;
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x0c : /* SBC reg */
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, no write-back, up post indexed. */
+ SHUPWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ Multiply64 (state, instr, LSIGNED, LDEFAULT),
+ 0L);
+ break;
+ }
+#endif
+ rhs = DPRegRHS;
+ dest = LHS - rhs - !CFLAG;
+ WRITEDEST (dest);
+ break;
+
+ case 0x0d: /* SBCS reg */
#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, no write-back, up post indexed */
- SHUPWB() ;
- break ;
- }
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, no write-back, up, post indexed. */
+ LHPOSTUP ();
+
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ Multiply64 (state, instr, LSIGNED, LSCC),
+ 0L);
+ break;
+ }
#endif
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = lhs - rhs - !CFLAG;
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, dest);
+ ARMul_SubOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x0e: /* RSC reg */
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,Multiply64(state,instr,LSIGNED,LDEFAULT),0L) ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = LHS - rhs - !CFLAG ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x0d : /* SBCS reg */
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, write-back, up, post indexed. */
+ SHUPWB ();
+ break;
+ }
+
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ MultiplyAdd64 (state, instr, LSIGNED,
+ LDEFAULT), 0L);
+ break;
+ }
+#endif
+ rhs = DPRegRHS;
+ dest = rhs - LHS - !CFLAG;
+ WRITEDEST (dest);
+ break;
+
+ case 0x0f: /* RSCS reg */
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, no write-back, up, post indexed */
- LHPOSTUP() ;
- }
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, write-back, up, post indexed. */
+ LHPOSTUP ();
+ /* Fall through to remaining instruction decoding. */
+
+ if (BITS (4, 7) == 0x9)
+ {
+ /* MULL */
+ /* 32x32=64 */
+ ARMul_Icycles (state,
+ MultiplyAdd64 (state, instr, LSIGNED, LSCC),
+ 0L);
+ break;
+ }
#endif
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = rhs - lhs - !CFLAG;
+
+ if ((rhs >= lhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, rhs, lhs, dest);
+ ARMul_SubOverflow (state, rhs, lhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x10: /* TST reg and MRS CPSR and SWP word. */
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1)
+ {
+ /* ElSegundo SMLAxy insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (8, 11)];
+ ARMword Rn = state->Reg[BITS (12, 15)];
+
+ if (BIT (5))
+ op1 >>= 16;
+ if (BIT (6))
+ op2 >>= 16;
+ op1 &= 0xFFFF;
+ op2 &= 0xFFFF;
+ if (op1 & 0x8000)
+ op1 -= 65536;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+ op1 *= op2;
+
+ if (AddOverflow (op1, Rn, op1 + Rn))
+ SETS;
+ state->Reg[BITS (16, 19)] = op1 + Rn;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QADD insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword result = op1 + op2;
+ if (AddOverflow (op1, op2, result))
+ {
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ SETS;
+ }
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,Multiply64(state,instr,LSIGNED,LSCC),0L) ;
- break ;
- }
-#endif
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = lhs - rhs - !CFLAG ;
- if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,lhs,rhs,dest) ;
- ARMul_SubOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x0e : /* RSC reg */
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, no write-back, down, pre indexed. */
+ SHPREDOWN ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ if (BITS (4, 11) == 9)
+ {
+ /* SWP */
+ UNDEF_SWPPC;
+ temp = LHS;
+ BUSUSEDINCPCS;
+#ifndef MODE32
+ if (VECTORACCESS (temp) || ADDREXCEPT (temp))
+ {
+ INTERNALABORT (temp);
+ (void) ARMul_LoadWordN (state, temp);
+ (void) ARMul_LoadWordN (state, temp);
+ }
+ else
+#endif
+ dest = ARMul_SwapWord (state, temp, state->Reg[RHSReg]);
+ if (temp & 3)
+ DEST = ARMul_Align (state, temp, dest);
+ else
+ DEST = dest;
+ if (state->abortSig || state->Aborted)
+ TAKEABORT;
+ }
+ else if ((BITS (0, 11) == 0) && (LHSReg == 15))
+ { /* MRS CPSR */
+ UNDEF_MRSPC;
+ DEST = ECC | EINT | EMODE;
+ }
+ else
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ UNDEF_Test;
+ }
+ break;
+
+ case 0x11: /* TSTP reg */
#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, write-back, up, post indexed */
- SHUPWB() ;
- break ;
- }
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, no write-back, down, pre indexed. */
+ LHPREDOWN ();
+ /* Continue with remaining instruction decode. */
#endif
+ if (DESTReg == 15)
+ {
+ /* TSTP reg */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ rhs = DPRegRHS;
+ temp = LHS & rhs;
+ SETR15PSR (temp);
+#endif
+ }
+ else
+ {
+ /* TST reg */
+ rhs = DPSRegRHS;
+ dest = LHS & rhs;
+ ARMul_NegZero (state, dest);
+ }
+ break;
+
+ case 0x12: /* TEQ reg and MSR reg to CPSR (ARM6). */
+ if (state->is_v5)
+ {
+ if (BITS (4, 7) == 3)
+ {
+ /* BLX(2) */
+ ARMword temp;
+
+ if (TFLAG)
+ temp = (pc + 2) | 1;
+ else
+ temp = pc + 4;
+
+ WriteR15Branch (state, state->Reg[RHSReg]);
+ state->Reg[14] = temp;
+ break;
+ }
+ }
+
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1
+ && (BIT (5) == 0 || BITS (12, 15) == 0))
+ {
+ /* ElSegundo SMLAWy/SMULWy insn. */
+ ARMdword op1 = state->Reg[BITS (0, 3)];
+ ARMdword op2 = state->Reg[BITS (8, 11)];
+ ARMdword result;
+
+ if (BIT (6))
+ op2 >>= 16;
+ if (op1 & 0x80000000)
+ op1 -= 1ULL << 32;
+ op2 &= 0xFFFF;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+ result = (op1 * op2) >> 16;
+
+ if (BIT (5) == 0)
+ {
+ ARMword Rn = state->Reg[BITS (12, 15)];
+
+ if (AddOverflow (result, Rn, result + Rn))
+ SETS;
+ result += Rn;
+ }
+ state->Reg[BITS (16, 19)] = result;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QSUB insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword result = op1 - op2;
+
+ if (SubOverflow (op1, op2, result))
+ {
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ SETS;
+ }
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,MultiplyAdd64(state,instr,LSIGNED,LDEFAULT),0L) ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = rhs - LHS - !CFLAG ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x0f : /* RSCS reg */
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, write-back, down, pre indexed. */
+ SHPREDOWNWB ();
+ break;
+ }
+ if (BITS (4, 27) == 0x12FFF1)
+ {
+ /* BX */
+ WriteR15Branch (state, state->Reg[RHSReg]);
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ if (state->is_v5)
+ {
+ if (BITS (4, 7) == 0x7)
+ {
+ extern int SWI_vector_installed;
+
+ /* Hardware is allowed to optionally override this
+ instruction and treat it as a breakpoint. Since
+ this is a simulator not hardware, we take the position
+ that if a SWI vector was not installed, then an Abort
+ vector was probably not installed either, and so
+ normally this instruction would be ignored, even if an
+ Abort is generated. This is a bad thing, since GDB
+ uses this instruction for its breakpoints (at least in
+ Thumb mode it does). So intercept the instruction here
+ and generate a breakpoint SWI instead. */
+ if (! SWI_vector_installed)
+ ARMul_OSHandleSWI (state, SWI_Breakpoint);
+ else
+ {
+ /* BKPT - normally this will cause an abort, but on the
+ XScale we must check the DCSR. */
+ XScale_set_fsr_far (state, ARMul_CP15_R5_MMU_EXCPT, pc);
+ if (!XScale_debug_moe (state, ARMul_CP14_R10_MOE_BT))
+ break;
+ }
+
+ /* Force the next instruction to be refetched. */
+ state->NextInstr = RESUME;
+ break;
+ }
+ }
+ if (DESTReg == 15)
+ {
+ /* MSR reg to CPSR. */
+ UNDEF_MSRPC;
+ temp = DPRegRHS;
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, write-back, up, post indexed */
- LHPOSTUP() ;
- /* fall through to remaining instruction decoding */
- }
+ /* Don't allow TBIT to be set by MSR. */
+ temp &= ~ TBIT;
+#endif
+ ARMul_FixCPSR (state, instr, temp);
+ }
+#ifdef MODE32
+ else if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
#endif
+ else
+ UNDEF_Test;
+
+ break;
+
+ case 0x13: /* TEQP reg */
#ifdef MODET
- if (BITS(4,7) == 0x9) { /* MULL */
- /* 32x32=64 */
- ARMul_Icycles(state,MultiplyAdd64(state,instr,LSIGNED,LSCC),0L) ;
- break ;
- }
-#endif
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = rhs - lhs - !CFLAG ;
- if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,rhs,lhs,dest) ;
- ARMul_SubOverflow(state,rhs,lhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x10 : /* TST reg and MRS CPSR and SWP word */
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, write-back, down, pre indexed. */
+ LHPREDOWNWB ();
+ /* Continue with remaining instruction decode. */
+#endif
+ if (DESTReg == 15)
+ {
+ /* TEQP reg */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ rhs = DPRegRHS;
+ temp = LHS ^ rhs;
+ SETR15PSR (temp);
+#endif
+ }
+ else
+ {
+ /* TEQ Reg. */
+ rhs = DPSRegRHS;
+ dest = LHS ^ rhs;
+ ARMul_NegZero (state, dest);
+ }
+ break;
+
+ case 0x14: /* CMP reg and MRS SPSR and SWP byte. */
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1)
+ {
+ /* ElSegundo SMLALxy insn. */
+ ARMdword op1 = state->Reg[BITS (0, 3)];
+ ARMdword op2 = state->Reg[BITS (8, 11)];
+ ARMdword dest;
+
+ if (BIT (5))
+ op1 >>= 16;
+ if (BIT (6))
+ op2 >>= 16;
+ op1 &= 0xFFFF;
+ if (op1 & 0x8000)
+ op1 -= 65536;
+ op2 &= 0xFFFF;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+
+ dest = (ARMdword) state->Reg[BITS (16, 19)] << 32;
+ dest |= state->Reg[BITS (12, 15)];
+ dest += op1 * op2;
+ state->Reg[BITS (12, 15)] = dest;
+ state->Reg[BITS (16, 19)] = dest >> 32;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QDADD insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword op2d = op2 + op2;
+ ARMword result;
+
+ if (AddOverflow (op2, op2, op2d))
+ {
+ SETS;
+ op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
+ }
+
+ result = op1 + op2d;
+ if (AddOverflow (op1, op2d, result))
+ {
+ SETS;
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ }
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, no write-back, down, pre indexed */
- SHPREDOWN() ;
- break ;
- }
-#endif
- if (BITS(4,11) == 9) { /* SWP */
- UNDEF_SWPPC ;
- temp = LHS ;
- BUSUSEDINCPCS ;
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, no write-back, down, pre indexed. */
+ SHPREDOWN ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ if (BITS (4, 11) == 9)
+ {
+ /* SWP */
+ UNDEF_SWPPC;
+ temp = LHS;
+ BUSUSEDINCPCS;
#ifndef MODE32
- if (VECTORACCESS(temp) || ADDREXCEPT(temp)) {
- INTERNALABORT(temp) ;
- (void)ARMul_LoadWordN(state,temp) ;
- (void)ARMul_LoadWordN(state,temp) ;
- }
- else
-#endif
- dest = ARMul_SwapWord(state,temp,state->Reg[RHSReg]) ;
- if (temp & 3)
- DEST = ARMul_Align(state,temp,dest) ;
- else
- DEST = dest ;
- if (state->abortSig || state->Aborted) {
- TAKEABORT ;
- }
- }
- else if ((BITS(0,11)==0) && (LHSReg==15)) { /* MRS CPSR */
- UNDEF_MRSPC ;
- DEST = ECC | EINT | EMODE ;
- }
- else {
- UNDEF_Test ;
- }
- break ;
-
- case 0x11 : /* TSTP reg */
+ if (VECTORACCESS (temp) || ADDREXCEPT (temp))
+ {
+ INTERNALABORT (temp);
+ (void) ARMul_LoadByte (state, temp);
+ (void) ARMul_LoadByte (state, temp);
+ }
+ else
+#endif
+ DEST = ARMul_SwapByte (state, temp, state->Reg[RHSReg]);
+ if (state->abortSig || state->Aborted)
+ TAKEABORT;
+ }
+ else if ((BITS (0, 11) == 0) && (LHSReg == 15))
+ {
+ /* MRS SPSR */
+ UNDEF_MRSPC;
+ DEST = GETSPSR (state->Bank);
+ }
+#ifdef MODE32
+ else if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ else
+ UNDEF_Test;
+
+ break;
+
+ case 0x15: /* CMPP reg. */
+#ifdef MODET
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, no write-back, down, pre indexed. */
+ LHPREDOWN ();
+ /* Continue with remaining instruction decode. */
+#endif
+ if (DESTReg == 15)
+ {
+ /* CMPP reg. */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ rhs = DPRegRHS;
+ temp = LHS - rhs;
+ SETR15PSR (temp);
+#endif
+ }
+ else
+ {
+ /* CMP reg. */
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = lhs - rhs;
+ ARMul_NegZero (state, dest);
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, dest);
+ ARMul_SubOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+ break;
+
+ case 0x16: /* CMN reg and MSR reg to SPSR */
+ if (state->is_v5e)
+ {
+ if (BIT (4) == 0 && BIT (7) == 1 && BITS (12, 15) == 0)
+ {
+ /* ElSegundo SMULxy insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (8, 11)];
+
+ if (BIT (5))
+ op1 >>= 16;
+ if (BIT (6))
+ op2 >>= 16;
+ op1 &= 0xFFFF;
+ op2 &= 0xFFFF;
+ if (op1 & 0x8000)
+ op1 -= 65536;
+ if (op2 & 0x8000)
+ op2 -= 65536;
+
+ state->Reg[BITS (16, 19)] = op1 * op2;
+ break;
+ }
+
+ if (BITS (4, 11) == 5)
+ {
+ /* ElSegundo QDSUB insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ ARMword op2 = state->Reg[BITS (16, 19)];
+ ARMword op2d = op2 + op2;
+ ARMword result;
+
+ if (AddOverflow (op2, op2, op2d))
+ {
+ SETS;
+ op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
+ }
+
+ result = op1 - op2d;
+ if (SubOverflow (op1, op2d, result))
+ {
+ SETS;
+ result = POS (result) ? 0x80000000 : 0x7fffffff;
+ }
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
+
+ if (state->is_v5)
+ {
+ if (BITS (4, 11) == 0xF1 && BITS (16, 19) == 0xF)
+ {
+ /* ARM5 CLZ insn. */
+ ARMword op1 = state->Reg[BITS (0, 3)];
+ int result = 32;
+
+ if (op1)
+ for (result = 0; (op1 & 0x80000000) == 0; op1 <<= 1)
+ result++;
+
+ state->Reg[BITS (12, 15)] = result;
+ break;
+ }
+ }
+#ifdef MODET
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, write-back, down, pre indexed. */
+ SHPREDOWNWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ if (DESTReg == 15)
+ {
+ /* MSR */
+ UNDEF_MSRPC;
+ ARMul_FixSPSR (state, instr, DPRegRHS);
+ }
+ else
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ UNDEF_Test;
+ }
+ break;
+
+ case 0x17: /* CMNP reg */
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, no write-back, down, pre indexed */
- LHPREDOWN() ;
- /* continue with remaining instruction decode */
- }
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, write-back, down, pre indexed. */
+ LHPREDOWNWB ();
+ /* Continue with remaining instruction decoding. */
#endif
- if (DESTReg == 15) { /* TSTP reg */
+ if (DESTReg == 15)
+ {
#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
#else
- rhs = DPRegRHS ;
- temp = LHS & rhs ;
- SETR15PSR(temp) ;
-#endif
- }
- else { /* TST reg */
- rhs = DPSRegRHS ;
- dest = LHS & rhs ;
- ARMul_NegZero(state,dest) ;
- }
- break ;
-
- case 0x12 : /* TEQ reg and MSR reg to CPSR (ARM6) */
+ rhs = DPRegRHS;
+ temp = LHS + rhs;
+ SETR15PSR (temp);
+#endif
+ break;
+ }
+ else
+ {
+ /* CMN reg. */
+ lhs = LHS;
+ rhs = DPRegRHS;
+ dest = lhs + rhs;
+ ASSIGNZ (dest == 0);
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ASSIGNN (NEG (dest));
+ ARMul_AddCarry (state, lhs, rhs, dest);
+ ARMul_AddOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARN;
+ CLEARC;
+ CLEARV;
+ }
+ }
+ break;
+
+ case 0x18: /* ORR reg */
#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, write-back, down, pre indexed */
- SHPREDOWNWB() ;
- break ;
- }
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, no write-back, up, pre indexed. */
+ SHPREUP ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
#endif
+ rhs = DPRegRHS;
+ dest = LHS | rhs;
+ WRITEDEST (dest);
+ break;
+
+ case 0x19: /* ORRS reg */
#ifdef MODET
- if (BITS(4,27)==0x12FFF1) { /* BX */
- /* Branch to the address in RHSReg. If bit0 of
- destination address is 1 then switch to Thumb mode: */
- ARMword addr = state->Reg[RHSReg];
-
- /* If we read the PC then the bottom bit is clear */
- if (RHSReg == 15) addr &= ~1;
-
- /* Enable this for a helpful bit of debugging when
- GDB is not yet fully working...
- fprintf (stderr, "BX at %x to %x (go %s)\n",
- state->Reg[15], addr, (addr & 1) ? "thumb": "arm" ); */
-
- if (addr & (1 << 0)) { /* Thumb bit */
- SETT;
- state->Reg[15] = addr & 0xfffffffe;
- /* NOTE: The other CPSR flag setting blocks do not
- seem to update the state->Cpsr state, but just do
- the explicit flag. The copy from the seperate
- flags to the register must happen later. */
- FLUSHPIPE;
- } else {
- CLEART;
- state->Reg[15] = addr & 0xfffffffc;
- FLUSHPIPE;
- }
- }
-#endif
- if (DESTReg==15 && BITS(17,18)==0) { /* MSR reg to CPSR */
- UNDEF_MSRPC ;
- temp = DPRegRHS ;
- ARMul_FixCPSR(state,instr,temp) ;
- }
- else {
- UNDEF_Test ;
- }
- break ;
-
- case 0x13 : /* TEQP reg */
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, no write-back, up, pre indexed. */
+ LHPREUP ();
+ /* Continue with remaining instruction decoding. */
+#endif
+ rhs = DPSRegRHS;
+ dest = LHS | rhs;
+ WRITESDEST (dest);
+ break;
+
+ case 0x1a: /* MOV reg */
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, write-back, down, pre indexed */
- LHPREDOWNWB() ;
- /* continue with remaining instruction decode */
- }
+ if (BITS (4, 11) == 0xB)
+ {
+ /* STRH register offset, write-back, up, pre indexed. */
+ SHPREUPWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ dest = DPRegRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x1b: /* MOVS reg */
+#ifdef MODET
+ if ((BITS (4, 11) & 0xF9) == 0x9)
+ /* LDR register offset, write-back, up, pre indexed. */
+ LHPREUPWB ();
+ /* Continue with remaining instruction decoding. */
+#endif
+ dest = DPSRegRHS;
+ WRITESDEST (dest);
+ break;
+
+ case 0x1c: /* BIC reg */
+#ifdef MODET
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, no write-back, up, pre indexed. */
+ SHPREUP ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ else if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ rhs = DPRegRHS;
+ dest = LHS & ~rhs;
+ WRITEDEST (dest);
+ break;
+
+ case 0x1d: /* BICS reg */
+#ifdef MODET
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, no write-back, up, pre indexed. */
+ LHPREUP ();
+ /* Continue with instruction decoding. */
+#endif
+ rhs = DPSRegRHS;
+ dest = LHS & ~rhs;
+ WRITESDEST (dest);
+ break;
+
+ case 0x1e: /* MVN reg */
+#ifdef MODET
+ if (BITS (4, 7) == 0xB)
+ {
+ /* STRH immediate offset, write-back, up, pre indexed. */
+ SHPREUPWB ();
+ break;
+ }
+ if (BITS (4, 7) == 0xD)
+ {
+ Handle_Load_Double (state, instr);
+ break;
+ }
+ if (BITS (4, 7) == 0xF)
+ {
+ Handle_Store_Double (state, instr);
+ break;
+ }
+#endif
+ dest = ~DPRegRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x1f: /* MVNS reg */
+#ifdef MODET
+ if ((BITS (4, 7) & 0x9) == 0x9)
+ /* LDR immediate offset, write-back, up, pre indexed. */
+ LHPREUPWB ();
+ /* Continue instruction decoding. */
+#endif
+ dest = ~DPSRegRHS;
+ WRITESDEST (dest);
+ break;
+
+
+ /* Data Processing Immediate RHS Instructions. */
+
+ case 0x20: /* AND immed */
+ dest = LHS & DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x21: /* ANDS immed */
+ DPSImmRHS;
+ dest = LHS & rhs;
+ WRITESDEST (dest);
+ break;
+
+ case 0x22: /* EOR immed */
+ dest = LHS ^ DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x23: /* EORS immed */
+ DPSImmRHS;
+ dest = LHS ^ rhs;
+ WRITESDEST (dest);
+ break;
+
+ case 0x24: /* SUB immed */
+ dest = LHS - DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x25: /* SUBS immed */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = lhs - rhs;
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, dest);
+ ARMul_SubOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x26: /* RSB immed */
+ dest = DPImmRHS - LHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x27: /* RSBS immed */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = rhs - lhs;
+
+ if ((rhs >= lhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, rhs, lhs, dest);
+ ARMul_SubOverflow (state, rhs, lhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x28: /* ADD immed */
+ dest = LHS + DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x29: /* ADDS immed */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = lhs + rhs;
+ ASSIGNZ (dest == 0);
+
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ASSIGNN (NEG (dest));
+ ARMul_AddCarry (state, lhs, rhs, dest);
+ ARMul_AddOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARN;
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x2a: /* ADC immed */
+ dest = LHS + DPImmRHS + CFLAG;
+ WRITEDEST (dest);
+ break;
+
+ case 0x2b: /* ADCS immed */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = lhs + rhs + CFLAG;
+ ASSIGNZ (dest == 0);
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ASSIGNN (NEG (dest));
+ ARMul_AddCarry (state, lhs, rhs, dest);
+ ARMul_AddOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARN;
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x2c: /* SBC immed */
+ dest = LHS - DPImmRHS - !CFLAG;
+ WRITEDEST (dest);
+ break;
+
+ case 0x2d: /* SBCS immed */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = lhs - rhs - !CFLAG;
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, dest);
+ ARMul_SubOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x2e: /* RSC immed */
+ dest = DPImmRHS - LHS - !CFLAG;
+ WRITEDEST (dest);
+ break;
+
+ case 0x2f: /* RSCS immed */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = rhs - lhs - !CFLAG;
+ if ((rhs >= lhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, rhs, lhs, dest);
+ ARMul_SubOverflow (state, rhs, lhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ WRITESDEST (dest);
+ break;
+
+ case 0x30: /* MOVW immed */
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ dest = BITS (0, 11);
+ dest |= (BITS (16, 19) << 12);
+ WRITEDEST (dest);
+ break;
+
+ case 0x31: /* TSTP immed */
+ if (DESTReg == 15)
+ {
+ /* TSTP immed. */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ temp = LHS & DPImmRHS;
+ SETR15PSR (temp);
+#endif
+ }
+ else
+ {
+ /* TST immed. */
+ DPSImmRHS;
+ dest = LHS & rhs;
+ ARMul_NegZero (state, dest);
+ }
+ break;
+
+ case 0x32: /* TEQ immed and MSR immed to CPSR */
+ if (DESTReg == 15)
+ /* MSR immed to CPSR. */
+ ARMul_FixCPSR (state, instr, DPImmRHS);
+#ifdef MODE32
+ else if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ else
+ UNDEF_Test;
+ break;
+
+ case 0x33: /* TEQP immed */
+ if (DESTReg == 15)
+ {
+ /* TEQP immed. */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ temp = LHS ^ DPImmRHS;
+ SETR15PSR (temp);
+#endif
+ }
+ else
+ {
+ DPSImmRHS; /* TEQ immed */
+ dest = LHS ^ rhs;
+ ARMul_NegZero (state, dest);
+ }
+ break;
+
+ case 0x34: /* MOVT immed */
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ DEST &= 0xFFFF;
+ dest = BITS (0, 11);
+ dest |= (BITS (16, 19) << 12);
+ DEST |= (dest << 16);
+ break;
+
+ case 0x35: /* CMPP immed */
+ if (DESTReg == 15)
+ {
+ /* CMPP immed. */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ temp = LHS - DPImmRHS;
+ SETR15PSR (temp);
+#endif
+ break;
+ }
+ else
+ {
+ /* CMP immed. */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = lhs - rhs;
+ ARMul_NegZero (state, dest);
+
+ if ((lhs >= rhs) || ((rhs | lhs) >> 31))
+ {
+ ARMul_SubCarry (state, lhs, rhs, dest);
+ ARMul_SubOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARC;
+ CLEARV;
+ }
+ }
+ break;
+
+ case 0x36: /* CMN immed and MSR immed to SPSR */
+ if (DESTReg == 15)
+ ARMul_FixSPSR (state, instr, DPImmRHS);
+#ifdef MODE32
+ else if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ else
+ UNDEF_Test;
+ break;
+
+ case 0x37: /* CMNP immed. */
+ if (DESTReg == 15)
+ {
+ /* CMNP immed. */
+#ifdef MODE32
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+#else
+ temp = LHS + DPImmRHS;
+ SETR15PSR (temp);
+#endif
+ break;
+ }
+ else
+ {
+ /* CMN immed. */
+ lhs = LHS;
+ rhs = DPImmRHS;
+ dest = lhs + rhs;
+ ASSIGNZ (dest == 0);
+ if ((lhs | rhs) >> 30)
+ {
+ /* Possible C,V,N to set. */
+ ASSIGNN (NEG (dest));
+ ARMul_AddCarry (state, lhs, rhs, dest);
+ ARMul_AddOverflow (state, lhs, rhs, dest);
+ }
+ else
+ {
+ CLEARN;
+ CLEARC;
+ CLEARV;
+ }
+ }
+ break;
+
+ case 0x38: /* ORR immed. */
+ dest = LHS | DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x39: /* ORRS immed. */
+ DPSImmRHS;
+ dest = LHS | rhs;
+ WRITESDEST (dest);
+ break;
+
+ case 0x3a: /* MOV immed. */
+ dest = DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x3b: /* MOVS immed. */
+ DPSImmRHS;
+ WRITESDEST (rhs);
+ break;
+
+ case 0x3c: /* BIC immed. */
+ dest = LHS & ~DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x3d: /* BICS immed. */
+ DPSImmRHS;
+ dest = LHS & ~rhs;
+ WRITESDEST (dest);
+ break;
+
+ case 0x3e: /* MVN immed. */
+ dest = ~DPImmRHS;
+ WRITEDEST (dest);
+ break;
+
+ case 0x3f: /* MVNS immed. */
+ DPSImmRHS;
+ WRITESDEST (~rhs);
+ break;
+
+
+ /* Single Data Transfer Immediate RHS Instructions. */
+
+ case 0x40: /* Store Word, No WriteBack, Post Dec, Immed. */
+ lhs = LHS;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs - LSImmRHS;
+ break;
+
+ case 0x41: /* Load Word, No WriteBack, Post Dec, Immed. */
+ lhs = LHS;
+ if (LoadWord (state, instr, lhs))
+ LSBase = lhs - LSImmRHS;
+ break;
+
+ case 0x42: /* Store Word, WriteBack, Post Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ temp = lhs - LSImmRHS;
+ state->NtransSig = LOW;
+ if (StoreWord (state, instr, lhs))
+ LSBase = temp;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x43: /* Load Word, WriteBack, Post Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (LoadWord (state, instr, lhs))
+ LSBase = lhs - LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x44: /* Store Byte, No WriteBack, Post Dec, Immed. */
+ lhs = LHS;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs - LSImmRHS;
+ break;
+
+ case 0x45: /* Load Byte, No WriteBack, Post Dec, Immed. */
+ lhs = LHS;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = lhs - LSImmRHS;
+ break;
+
+ case 0x46: /* Store Byte, WriteBack, Post Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs - LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x47: /* Load Byte, WriteBack, Post Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = lhs - LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x48: /* Store Word, No WriteBack, Post Inc, Immed. */
+ lhs = LHS;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs + LSImmRHS;
+ break;
+
+ case 0x49: /* Load Word, No WriteBack, Post Inc, Immed. */
+ lhs = LHS;
+ if (LoadWord (state, instr, lhs))
+ LSBase = lhs + LSImmRHS;
+ break;
+
+ case 0x4a: /* Store Word, WriteBack, Post Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs + LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x4b: /* Load Word, WriteBack, Post Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (LoadWord (state, instr, lhs))
+ LSBase = lhs + LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x4c: /* Store Byte, No WriteBack, Post Inc, Immed. */
+ lhs = LHS;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs + LSImmRHS;
+ break;
+
+ case 0x4d: /* Load Byte, No WriteBack, Post Inc, Immed. */
+ lhs = LHS;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = lhs + LSImmRHS;
+ break;
+
+ case 0x4e: /* Store Byte, WriteBack, Post Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs + LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x4f: /* Load Byte, WriteBack, Post Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = lhs + LSImmRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+
+ case 0x50: /* Store Word, No WriteBack, Pre Dec, Immed. */
+ (void) StoreWord (state, instr, LHS - LSImmRHS);
+ break;
+
+ case 0x51: /* Load Word, No WriteBack, Pre Dec, Immed. */
+ (void) LoadWord (state, instr, LHS - LSImmRHS);
+ break;
+
+ case 0x52: /* Store Word, WriteBack, Pre Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS - LSImmRHS;
+ if (StoreWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x53: /* Load Word, WriteBack, Pre Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS - LSImmRHS;
+ if (LoadWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x54: /* Store Byte, No WriteBack, Pre Dec, Immed. */
+ (void) StoreByte (state, instr, LHS - LSImmRHS);
+ break;
+
+ case 0x55: /* Load Byte, No WriteBack, Pre Dec, Immed. */
+ (void) LoadByte (state, instr, LHS - LSImmRHS, LUNSIGNED);
+ break;
+
+ case 0x56: /* Store Byte, WriteBack, Pre Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS - LSImmRHS;
+ if (StoreByte (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x57: /* Load Byte, WriteBack, Pre Dec, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS - LSImmRHS;
+ if (LoadByte (state, instr, temp, LUNSIGNED))
+ LSBase = temp;
+ break;
+
+ case 0x58: /* Store Word, No WriteBack, Pre Inc, Immed. */
+ (void) StoreWord (state, instr, LHS + LSImmRHS);
+ break;
+
+ case 0x59: /* Load Word, No WriteBack, Pre Inc, Immed. */
+ (void) LoadWord (state, instr, LHS + LSImmRHS);
+ break;
+
+ case 0x5a: /* Store Word, WriteBack, Pre Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS + LSImmRHS;
+ if (StoreWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x5b: /* Load Word, WriteBack, Pre Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS + LSImmRHS;
+ if (LoadWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x5c: /* Store Byte, No WriteBack, Pre Inc, Immed. */
+ (void) StoreByte (state, instr, LHS + LSImmRHS);
+ break;
+
+ case 0x5d: /* Load Byte, No WriteBack, Pre Inc, Immed. */
+ (void) LoadByte (state, instr, LHS + LSImmRHS, LUNSIGNED);
+ break;
+
+ case 0x5e: /* Store Byte, WriteBack, Pre Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS + LSImmRHS;
+ if (StoreByte (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x5f: /* Load Byte, WriteBack, Pre Inc, Immed. */
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ temp = LHS + LSImmRHS;
+ if (LoadByte (state, instr, temp, LUNSIGNED))
+ LSBase = temp;
+ break;
+
+
+ /* Single Data Transfer Register RHS Instructions. */
+
+ case 0x60: /* Store Word, No WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs - LSRegRHS;
+ break;
+
+ case 0x61: /* Load Word, No WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs - LSRegRHS;
+ if (LoadWord (state, instr, lhs))
+ LSBase = temp;
+ break;
+
+ case 0x62: /* Store Word, WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs - LSRegRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x63: /* Load Word, WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs - LSRegRHS;
+ state->NtransSig = LOW;
+ if (LoadWord (state, instr, lhs))
+ LSBase = temp;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x64: /* Store Byte, No WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs - LSRegRHS;
+ break;
+
+ case 0x65: /* Load Byte, No WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs - LSRegRHS;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = temp;
+ break;
+
+ case 0x66: /* Store Byte, WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs - LSRegRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x67: /* Load Byte, WriteBack, Post Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs - LSRegRHS;
+ state->NtransSig = LOW;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = temp;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs + LSRegRHS;
+ break;
+
+ case 0x69: /* Load Word, No WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs + LSRegRHS;
+ if (LoadWord (state, instr, lhs))
+ LSBase = temp;
+ break;
+
+ case 0x6a: /* Store Word, WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreWord (state, instr, lhs))
+ LSBase = lhs + LSRegRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x6b: /* Load Word, WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs + LSRegRHS;
+ state->NtransSig = LOW;
+ if (LoadWord (state, instr, lhs))
+ LSBase = temp;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x6c: /* Store Byte, No WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs + LSRegRHS;
+ break;
+
+ case 0x6d: /* Load Byte, No WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs + LSRegRHS;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = temp;
+ break;
+
+ case 0x6e: /* Store Byte, WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ state->NtransSig = LOW;
+ if (StoreByte (state, instr, lhs))
+ LSBase = lhs + LSRegRHS;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+ case 0x6f: /* Load Byte, WriteBack, Post Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ lhs = LHS;
+ temp = lhs + LSRegRHS;
+ state->NtransSig = LOW;
+ if (LoadByte (state, instr, lhs, LUNSIGNED))
+ LSBase = temp;
+ state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
+ break;
+
+
+ case 0x70: /* Store Word, No WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) StoreWord (state, instr, LHS - LSRegRHS);
+ break;
+
+ case 0x71: /* Load Word, No WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) LoadWord (state, instr, LHS - LSRegRHS);
+ break;
+
+ case 0x72: /* Store Word, WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS - LSRegRHS;
+ if (StoreWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x73: /* Load Word, WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS - LSRegRHS;
+ if (LoadWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x74: /* Store Byte, No WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) StoreByte (state, instr, LHS - LSRegRHS);
+ break;
+
+ case 0x75: /* Load Byte, No WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) LoadByte (state, instr, LHS - LSRegRHS, LUNSIGNED);
+ break;
+
+ case 0x76: /* Store Byte, WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS - LSRegRHS;
+ if (StoreByte (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x77: /* Load Byte, WriteBack, Pre Dec, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS - LSRegRHS;
+ if (LoadByte (state, instr, temp, LUNSIGNED))
+ LSBase = temp;
+ break;
+
+ case 0x78: /* Store Word, No WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) StoreWord (state, instr, LHS + LSRegRHS);
+ break;
+
+ case 0x79: /* Load Word, No WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) LoadWord (state, instr, LHS + LSRegRHS);
+ break;
+
+ case 0x7a: /* Store Word, WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS + LSRegRHS;
+ if (StoreWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x7b: /* Load Word, WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS + LSRegRHS;
+ if (LoadWord (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x7c: /* Store Byte, No WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) StoreByte (state, instr, LHS + LSRegRHS);
+ break;
+
+ case 0x7d: /* Load Byte, No WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ (void) LoadByte (state, instr, LHS + LSRegRHS, LUNSIGNED);
+ break;
+
+ case 0x7e: /* Store Byte, WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+#ifdef MODE32
+ if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS + LSRegRHS;
+ if (StoreByte (state, instr, temp))
+ LSBase = temp;
+ break;
+
+ case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */
+ if (BIT (4))
+ {
+ /* Check for the special breakpoint opcode.
+ This value should correspond to the value defined
+ as ARM_BE_BREAKPOINT in gdb/arm/tm-arm.h. */
+ if (BITS (0, 19) == 0xfdefe)
+ {
+ if (!ARMul_OSHandleSWI (state, SWI_Breakpoint))
+ ARMul_Abort (state, ARMul_SWIV);
+ }
+#ifdef MODE32
+ else if (state->is_v6
+ && handle_v6_insn (state, instr))
+ break;
+#endif
+ else
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ UNDEF_LSRBaseEQOffWb;
+ UNDEF_LSRBaseEQDestWb;
+ UNDEF_LSRPCBaseWb;
+ UNDEF_LSRPCOffWb;
+ temp = LHS + LSRegRHS;
+ if (LoadByte (state, instr, temp, LUNSIGNED))
+ LSBase = temp;
+ break;
+
+
+ /* Multiple Data Transfer Instructions. */
+
+ case 0x80: /* Store, No WriteBack, Post Dec. */
+ STOREMULT (instr, LSBase - LSMNumRegs + 4L, 0L);
+ break;
+
+ case 0x81: /* Load, No WriteBack, Post Dec. */
+ LOADMULT (instr, LSBase - LSMNumRegs + 4L, 0L);
+ break;
+
+ case 0x82: /* Store, WriteBack, Post Dec. */
+ temp = LSBase - LSMNumRegs;
+ STOREMULT (instr, temp + 4L, temp);
+ break;
+
+ case 0x83: /* Load, WriteBack, Post Dec. */
+ temp = LSBase - LSMNumRegs;
+ LOADMULT (instr, temp + 4L, temp);
+ break;
+
+ case 0x84: /* Store, Flags, No WriteBack, Post Dec. */
+ STORESMULT (instr, LSBase - LSMNumRegs + 4L, 0L);
+ break;
+
+ case 0x85: /* Load, Flags, No WriteBack, Post Dec. */
+ LOADSMULT (instr, LSBase - LSMNumRegs + 4L, 0L);
+ break;
+
+ case 0x86: /* Store, Flags, WriteBack, Post Dec. */
+ temp = LSBase - LSMNumRegs;
+ STORESMULT (instr, temp + 4L, temp);
+ break;
+
+ case 0x87: /* Load, Flags, WriteBack, Post Dec. */
+ temp = LSBase - LSMNumRegs;
+ LOADSMULT (instr, temp + 4L, temp);
+ break;
+
+ case 0x88: /* Store, No WriteBack, Post Inc. */
+ STOREMULT (instr, LSBase, 0L);
+ break;
+
+ case 0x89: /* Load, No WriteBack, Post Inc. */
+ LOADMULT (instr, LSBase, 0L);
+ break;
+
+ case 0x8a: /* Store, WriteBack, Post Inc. */
+ temp = LSBase;
+ STOREMULT (instr, temp, temp + LSMNumRegs);
+ break;
+
+ case 0x8b: /* Load, WriteBack, Post Inc. */
+ temp = LSBase;
+ LOADMULT (instr, temp, temp + LSMNumRegs);
+ break;
+
+ case 0x8c: /* Store, Flags, No WriteBack, Post Inc. */
+ STORESMULT (instr, LSBase, 0L);
+ break;
+
+ case 0x8d: /* Load, Flags, No WriteBack, Post Inc. */
+ LOADSMULT (instr, LSBase, 0L);
+ break;
+
+ case 0x8e: /* Store, Flags, WriteBack, Post Inc. */
+ temp = LSBase;
+ STORESMULT (instr, temp, temp + LSMNumRegs);
+ break;
+
+ case 0x8f: /* Load, Flags, WriteBack, Post Inc. */
+ temp = LSBase;
+ LOADSMULT (instr, temp, temp + LSMNumRegs);
+ break;
+
+ case 0x90: /* Store, No WriteBack, Pre Dec. */
+ STOREMULT (instr, LSBase - LSMNumRegs, 0L);
+ break;
+
+ case 0x91: /* Load, No WriteBack, Pre Dec. */
+ LOADMULT (instr, LSBase - LSMNumRegs, 0L);
+ break;
+
+ case 0x92: /* Store, WriteBack, Pre Dec. */
+ temp = LSBase - LSMNumRegs;
+ STOREMULT (instr, temp, temp);
+ break;
+
+ case 0x93: /* Load, WriteBack, Pre Dec. */
+ temp = LSBase - LSMNumRegs;
+ LOADMULT (instr, temp, temp);
+ break;
+
+ case 0x94: /* Store, Flags, No WriteBack, Pre Dec. */
+ STORESMULT (instr, LSBase - LSMNumRegs, 0L);
+ break;
+
+ case 0x95: /* Load, Flags, No WriteBack, Pre Dec. */
+ LOADSMULT (instr, LSBase - LSMNumRegs, 0L);
+ break;
+
+ case 0x96: /* Store, Flags, WriteBack, Pre Dec. */
+ temp = LSBase - LSMNumRegs;
+ STORESMULT (instr, temp, temp);
+ break;
+
+ case 0x97: /* Load, Flags, WriteBack, Pre Dec. */
+ temp = LSBase - LSMNumRegs;
+ LOADSMULT (instr, temp, temp);
+ break;
+
+ case 0x98: /* Store, No WriteBack, Pre Inc. */
+ STOREMULT (instr, LSBase + 4L, 0L);
+ break;
+
+ case 0x99: /* Load, No WriteBack, Pre Inc. */
+ LOADMULT (instr, LSBase + 4L, 0L);
+ break;
+
+ case 0x9a: /* Store, WriteBack, Pre Inc. */
+ temp = LSBase;
+ STOREMULT (instr, temp + 4L, temp + LSMNumRegs);
+ break;
+
+ case 0x9b: /* Load, WriteBack, Pre Inc. */
+ temp = LSBase;
+ LOADMULT (instr, temp + 4L, temp + LSMNumRegs);
+ break;
+
+ case 0x9c: /* Store, Flags, No WriteBack, Pre Inc. */
+ STORESMULT (instr, LSBase + 4L, 0L);
+ break;
+
+ case 0x9d: /* Load, Flags, No WriteBack, Pre Inc. */
+ LOADSMULT (instr, LSBase + 4L, 0L);
+ break;
+
+ case 0x9e: /* Store, Flags, WriteBack, Pre Inc. */
+ temp = LSBase;
+ STORESMULT (instr, temp + 4L, temp + LSMNumRegs);
+ break;
+
+ case 0x9f: /* Load, Flags, WriteBack, Pre Inc. */
+ temp = LSBase;
+ LOADSMULT (instr, temp + 4L, temp + LSMNumRegs);
+ break;
+
+
+ /* Branch forward. */
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0xa5:
+ case 0xa6:
+ case 0xa7:
+ state->Reg[15] = pc + 8 + POSBRANCH;
+ FLUSHPIPE;
+ break;
+
+
+ /* Branch backward. */
+ case 0xa8:
+ case 0xa9:
+ case 0xaa:
+ case 0xab:
+ case 0xac:
+ case 0xad:
+ case 0xae:
+ case 0xaf:
+ state->Reg[15] = pc + 8 + NEGBRANCH;
+ FLUSHPIPE;
+ break;
+
+ /* Branch and Link forward. */
+ case 0xb0:
+ case 0xb1:
+ case 0xb2:
+ case 0xb3:
+ case 0xb4:
+ case 0xb5:
+ case 0xb6:
+ case 0xb7:
+ /* Put PC into Link. */
+#ifdef MODE32
+ state->Reg[14] = pc + 4;
+#else
+ state->Reg[14] = (pc + 4) | ECC | ER15INT | EMODE;
#endif
- if (DESTReg == 15) { /* TEQP reg */
+ state->Reg[15] = pc + 8 + POSBRANCH;
+ FLUSHPIPE;
+ if (trace_funcs)
+ fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
+ break;
+
+ /* Branch and Link backward. */
+ case 0xb8:
+ case 0xb9:
+ case 0xba:
+ case 0xbb:
+ case 0xbc:
+ case 0xbd:
+ case 0xbe:
+ case 0xbf:
+ /* Put PC into Link. */
#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
+ state->Reg[14] = pc + 4;
#else
- rhs = DPRegRHS ;
- temp = LHS ^ rhs ;
- SETR15PSR(temp) ;
-#endif
- }
- else { /* TEQ Reg */
- rhs = DPSRegRHS ;
- dest = LHS ^ rhs ;
- ARMul_NegZero(state,dest) ;
- }
- break ;
-
- case 0x14 : /* CMP reg and MRS SPSR and SWP byte */
+ state->Reg[14] = (pc + 4) | ECC | ER15INT | EMODE;
+#endif
+ state->Reg[15] = pc + 8 + NEGBRANCH;
+ FLUSHPIPE;
+ if (trace_funcs)
+ fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
+ break;
+
+ /* Co-Processor Data Transfers. */
+ case 0xc4:
+ if (state->is_v5)
+ {
+ if (CPNum == 10 || CPNum == 11)
+ handle_VFP_move (state, instr);
+ /* Reading from R15 is UNPREDICTABLE. */
+ else if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
+ ARMul_UndefInstr (state, instr);
+ /* Is access to coprocessor 0 allowed ? */
+ else if (! CP_ACCESS_ALLOWED (state, CPNum))
+ ARMul_UndefInstr (state, instr);
+ /* Special treatment for XScale coprocessors. */
+ else if (state->is_XScale)
+ {
+ /* Only opcode 0 is supported. */
+ if (BITS (4, 7) != 0x00)
+ ARMul_UndefInstr (state, instr);
+ /* Only coporcessor 0 is supported. */
+ else if (CPNum != 0x00)
+ ARMul_UndefInstr (state, instr);
+ /* Only accumulator 0 is supported. */
+ else if (BITS (0, 3) != 0x00)
+ ARMul_UndefInstr (state, instr);
+ else
+ {
+ /* XScale MAR insn. Move two registers into accumulator. */
+ state->Accumulator = state->Reg[BITS (12, 15)];
+ state->Accumulator += (ARMdword) state->Reg[BITS (16, 19)] << 32;
+ }
+ }
+ else
+ /* FIXME: Not sure what to do for other v5 processors. */
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ /* Drop through. */
+
+ case 0xc0: /* Store , No WriteBack , Post Dec. */
+ ARMul_STC (state, instr, LHS);
+ break;
+
+ case 0xc5:
+ if (state->is_v5)
+ {
+ if (CPNum == 10 || CPNum == 11)
+ handle_VFP_move (state, instr);
+ /* Writes to R15 are UNPREDICATABLE. */
+ else if (DESTReg == 15 || LHSReg == 15)
+ ARMul_UndefInstr (state, instr);
+ /* Is access to the coprocessor allowed ? */
+ else if (! CP_ACCESS_ALLOWED (state, CPNum))
+ ARMul_UndefInstr (state, instr);
+ /* Special handling for XScale coprcoessors. */
+ else if (state->is_XScale)
+ {
+ /* Only opcode 0 is supported. */
+ if (BITS (4, 7) != 0x00)
+ ARMul_UndefInstr (state, instr);
+ /* Only coprocessor 0 is supported. */
+ else if (CPNum != 0x00)
+ ARMul_UndefInstr (state, instr);
+ /* Only accumulator 0 is supported. */
+ else if (BITS (0, 3) != 0x00)
+ ARMul_UndefInstr (state, instr);
+ else
+ {
+ /* XScale MRA insn. Move accumulator into two registers. */
+ ARMword t1 = (state->Accumulator >> 32) & 255;
+
+ if (t1 & 128)
+ t1 -= 256;
+
+ state->Reg[BITS (12, 15)] = state->Accumulator;
+ state->Reg[BITS (16, 19)] = t1;
+ break;
+ }
+ }
+ else
+ /* FIXME: Not sure what to do for other v5 processors. */
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ /* Drop through. */
+
+ case 0xc1: /* Load , No WriteBack , Post Dec. */
+ ARMul_LDC (state, instr, LHS);
+ break;
+
+ case 0xc2:
+ case 0xc6: /* Store , WriteBack , Post Dec. */
+ lhs = LHS;
+ state->Base = lhs - LSCOff;
+ ARMul_STC (state, instr, lhs);
+ break;
+
+ case 0xc3:
+ case 0xc7: /* Load , WriteBack , Post Dec. */
+ lhs = LHS;
+ state->Base = lhs - LSCOff;
+ ARMul_LDC (state, instr, lhs);
+ break;
+
+ case 0xc8:
+ case 0xcc: /* Store , No WriteBack , Post Inc. */
+ ARMul_STC (state, instr, LHS);
+ break;
+
+ case 0xc9:
+ case 0xcd: /* Load , No WriteBack , Post Inc. */
+ ARMul_LDC (state, instr, LHS);
+ break;
+
+ case 0xca:
+ case 0xce: /* Store , WriteBack , Post Inc. */
+ lhs = LHS;
+ state->Base = lhs + LSCOff;
+ ARMul_STC (state, instr, LHS);
+ break;
+
+ case 0xcb:
+ case 0xcf: /* Load , WriteBack , Post Inc. */
+ lhs = LHS;
+ state->Base = lhs + LSCOff;
+ ARMul_LDC (state, instr, LHS);
+ break;
+
+ case 0xd0:
+ case 0xd4: /* Store , No WriteBack , Pre Dec. */
+ ARMul_STC (state, instr, LHS - LSCOff);
+ break;
+
+ case 0xd1:
+ case 0xd5: /* Load , No WriteBack , Pre Dec. */
+ ARMul_LDC (state, instr, LHS - LSCOff);
+ break;
+
+ case 0xd2:
+ case 0xd6: /* Store , WriteBack , Pre Dec. */
+ lhs = LHS - LSCOff;
+ state->Base = lhs;
+ ARMul_STC (state, instr, lhs);
+ break;
+
+ case 0xd3:
+ case 0xd7: /* Load , WriteBack , Pre Dec. */
+ lhs = LHS - LSCOff;
+ state->Base = lhs;
+ ARMul_LDC (state, instr, lhs);
+ break;
+
+ case 0xd8:
+ case 0xdc: /* Store , No WriteBack , Pre Inc. */
+ ARMul_STC (state, instr, LHS + LSCOff);
+ break;
+
+ case 0xd9:
+ case 0xdd: /* Load , No WriteBack , Pre Inc. */
+ ARMul_LDC (state, instr, LHS + LSCOff);
+ break;
+
+ case 0xda:
+ case 0xde: /* Store , WriteBack , Pre Inc. */
+ lhs = LHS + LSCOff;
+ state->Base = lhs;
+ ARMul_STC (state, instr, lhs);
+ break;
+
+ case 0xdb:
+ case 0xdf: /* Load , WriteBack , Pre Inc. */
+ lhs = LHS + LSCOff;
+ state->Base = lhs;
+ ARMul_LDC (state, instr, lhs);
+ break;
+
+
+ /* Co-Processor Register Transfers (MCR) and Data Ops. */
+
+ case 0xe2:
+ if (! CP_ACCESS_ALLOWED (state, CPNum))
+ {
+ ARMul_UndefInstr (state, instr);
+ break;
+ }
+ if (state->is_XScale)
+ switch (BITS (18, 19))
+ {
+ case 0x0:
+ if (BITS (4, 11) == 1 && BITS (16, 17) == 0)
+ {
+ /* XScale MIA instruction. Signed multiplication of
+ two 32 bit values and addition to 40 bit accumulator. */
+ ARMsdword Rm = state->Reg[MULLHSReg];
+ ARMsdword Rs = state->Reg[MULACCReg];
+
+ if (Rm & (1 << 31))
+ Rm -= 1ULL << 32;
+ if (Rs & (1 << 31))
+ Rs -= 1ULL << 32;
+ state->Accumulator += Rm * Rs;
+ goto donext;
+ }
+ break;
+
+ case 0x2:
+ if (BITS (4, 11) == 1 && BITS (16, 17) == 0)
+ {
+ /* XScale MIAPH instruction. */
+ ARMword t1 = state->Reg[MULLHSReg] >> 16;
+ ARMword t2 = state->Reg[MULACCReg] >> 16;
+ ARMword t3 = state->Reg[MULLHSReg] & 0xffff;
+ ARMword t4 = state->Reg[MULACCReg] & 0xffff;
+ ARMsdword t5;
+
+ if (t1 & (1 << 15))
+ t1 -= 1 << 16;
+ if (t2 & (1 << 15))
+ t2 -= 1 << 16;
+ if (t3 & (1 << 15))
+ t3 -= 1 << 16;
+ if (t4 & (1 << 15))
+ t4 -= 1 << 16;
+ t1 *= t2;
+ t5 = t1;
+ if (t5 & (1 << 31))
+ t5 -= 1ULL << 32;
+ state->Accumulator += t5;
+ t3 *= t4;
+ t5 = t3;
+ if (t5 & (1 << 31))
+ t5 -= 1ULL << 32;
+ state->Accumulator += t5;
+ goto donext;
+ }
+ break;
+
+ case 0x3:
+ if (BITS (4, 11) == 1)
+ {
+ /* XScale MIAxy instruction. */
+ ARMword t1;
+ ARMword t2;
+ ARMsdword t5;
+
+ if (BIT (17))
+ t1 = state->Reg[MULLHSReg] >> 16;
+ else
+ t1 = state->Reg[MULLHSReg] & 0xffff;
+
+ if (BIT (16))
+ t2 = state->Reg[MULACCReg] >> 16;
+ else
+ t2 = state->Reg[MULACCReg] & 0xffff;
+
+ if (t1 & (1 << 15))
+ t1 -= 1 << 16;
+ if (t2 & (1 << 15))
+ t2 -= 1 << 16;
+ t1 *= t2;
+ t5 = t1;
+ if (t5 & (1 << 31))
+ t5 -= 1ULL << 32;
+ state->Accumulator += t5;
+ goto donext;
+ }
+ break;
+
+ default:
+ break;
+ }
+ /* Drop through. */
+
+ case 0xe0:
+ case 0xe4:
+ case 0xe6:
+ case 0xe8:
+ case 0xea:
+ case 0xec:
+ case 0xee:
+ if (BIT (4))
+ {
+ if (CPNum == 10 || CPNum == 11)
+ handle_VFP_move (state, instr);
+ /* MCR. */
+ else if (DESTReg == 15)
+ {
+ UNDEF_MCRPC;
+#ifdef MODE32
+ ARMul_MCR (state, instr, state->Reg[15] + isize);
+#else
+ ARMul_MCR (state, instr, ECC | ER15INT | EMODE |
+ ((state->Reg[15] + isize) & R15PCBITS));
+#endif
+ }
+ else
+ ARMul_MCR (state, instr, DEST);
+ }
+ else
+ /* CDP Part 1. */
+ ARMul_CDP (state, instr);
+ break;
+
+
+ /* Co-Processor Register Transfers (MRC) and Data Ops. */
+ case 0xe1:
+ case 0xe3:
+ case 0xe5:
+ case 0xe7:
+ case 0xe9:
+ case 0xeb:
+ case 0xed:
+ case 0xef:
+ if (BIT (4))
+ {
+ if (CPNum == 10 || CPNum == 11)
+ {
+ switch (BITS (20, 27))
+ {
+ case 0xEF:
+ if (BITS (16, 19) == 0x1
+ && BITS (0, 11) == 0xA10)
+ {
+ /* VMRS */
+ if (DESTReg == 15)
+ {
+ ARMul_SetCPSR (state, (state->FPSCR & 0xF0000000)
+ | (ARMul_GetCPSR (state) & 0x0FFFFFFF));
+
+ if (trace)
+ fprintf (stderr, " VFP: VMRS: set flags to %c%c%c%c\n",
+ ARMul_GetCPSR (state) & NBIT ? 'N' : '-',
+ ARMul_GetCPSR (state) & ZBIT ? 'Z' : '-',
+ ARMul_GetCPSR (state) & CBIT ? 'C' : '-',
+ ARMul_GetCPSR (state) & VBIT ? 'V' : '-');
+ }
+ else
+ {
+ state->Reg[DESTReg] = state->FPSCR;
+
+ if (trace)
+ fprintf (stderr, " VFP: VMRS: r%d = %x\n", DESTReg, state->Reg[DESTReg]);
+ }
+ }
+ else
+ fprintf (stderr, "SIM: VFP: Unimplemented: Compare op\n");
+ break;
+
+ case 0xE0:
+ case 0xE1:
+ /* VMOV reg <-> single precision. */
+ if (BITS (0,6) != 0x10 || BITS (8,11) != 0xA)
+ fprintf (stderr, "SIM: VFP: Unimplemented: move op\n");
+ else if (BIT (20))
+ state->Reg[BITS (12, 15)] = VFP_uword (BITS (16, 19) << 1 | BIT (7));
+ else
+ VFP_uword (BITS (16, 19) << 1 | BIT (7)) = state->Reg[BITS (12, 15)];
+ break;
+
+ default:
+ fprintf (stderr, "SIM: VFP: Unimplemented: CDP op\n");
+ break;
+ }
+ }
+ else
+ {
+ /* MRC */
+ temp = ARMul_MRC (state, instr);
+ if (DESTReg == 15)
+ {
+ ASSIGNN ((temp & NBIT) != 0);
+ ASSIGNZ ((temp & ZBIT) != 0);
+ ASSIGNC ((temp & CBIT) != 0);
+ ASSIGNV ((temp & VBIT) != 0);
+ }
+ else
+ DEST = temp;
+ }
+ }
+ else
+ /* CDP Part 2. */
+ ARMul_CDP (state, instr);
+ break;
+
+
+ /* SWI instruction. */
+ case 0xf0:
+ case 0xf1:
+ case 0xf2:
+ case 0xf3:
+ case 0xf4:
+ case 0xf5:
+ case 0xf6:
+ case 0xf7:
+ case 0xf8:
+ case 0xf9:
+ case 0xfa:
+ case 0xfb:
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ case 0xff:
+ if (instr == ARMul_ABORTWORD && state->AbortAddr == pc)
+ {
+ /* A prefetch abort. */
+ XScale_set_fsr_far (state, ARMul_CP15_R5_MMU_EXCPT, pc);
+ ARMul_Abort (state, ARMul_PrefetchAbortV);
+ break;
+ }
+
+ if (!ARMul_OSHandleSWI (state, BITS (0, 23)))
+ ARMul_Abort (state, ARMul_SWIV);
+
+ break;
+ }
+ }
+
#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, no write-back, down, pre indexed */
- SHPREDOWN() ;
- break ;
- }
-#endif
- if (BITS(4,11) == 9) { /* SWP */
- UNDEF_SWPPC ;
- temp = LHS ;
- BUSUSEDINCPCS ;
+ donext:
+#endif
+
+ if (state->Emulate == ONCE)
+ state->Emulate = STOP;
+ /* If we have changed mode, allow the PC to advance before stopping. */
+ else if (state->Emulate == CHANGEMODE)
+ continue;
+ else if (state->Emulate != RUN)
+ break;
+ }
+ while (!stop_simulator);
+
+ state->decoded = decoded;
+ state->loaded = loaded;
+ state->pc = pc;
+
+ return pc;
+}
+
+/* This routine evaluates most Data Processing register RHS's with the S
+ bit clear. It is intended to be called from the macro DPRegRHS, which
+ filters the common case of an unshifted register with in line code. */
+
+static ARMword
+GetDPRegRHS (ARMul_State * state, ARMword instr)
+{
+ ARMword shamt, base;
+
+ base = RHSReg;
+ if (BIT (4))
+ {
+ /* Shift amount in a register. */
+ UNDEF_Shift;
+ INCPC;
#ifndef MODE32
- if (VECTORACCESS(temp) || ADDREXCEPT(temp)) {
- INTERNALABORT(temp) ;
- (void)ARMul_LoadByte(state,temp) ;
- (void)ARMul_LoadByte(state,temp) ;
- }
- else
-#endif
- DEST = ARMul_SwapByte(state,temp,state->Reg[RHSReg]) ;
- if (state->abortSig || state->Aborted) {
- TAKEABORT ;
- }
- }
- else if ((BITS(0,11)==0) && (LHSReg==15)) { /* MRS SPSR */
- UNDEF_MRSPC ;
- DEST = GETSPSR(state->Bank) ;
- }
- else {
- UNDEF_Test ;
- }
- break ;
-
- case 0x15 : /* CMPP reg */
+ if (base == 15)
+ base = ECC | ER15INT | R15PC | EMODE;
+ else
+#endif
+ base = state->Reg[base];
+ ARMul_Icycles (state, 1, 0L);
+ shamt = state->Reg[BITS (8, 11)] & 0xff;
+ switch ((int) BITS (5, 6))
+ {
+ case LSL:
+ if (shamt == 0)
+ return (base);
+ else if (shamt >= 32)
+ return (0);
+ else
+ return (base << shamt);
+ case LSR:
+ if (shamt == 0)
+ return (base);
+ else if (shamt >= 32)
+ return (0);
+ else
+ return (base >> shamt);
+ case ASR:
+ if (shamt == 0)
+ return (base);
+ else if (shamt >= 32)
+ return ((ARMword) ((ARMsword) base >> 31L));
+ else
+ return ((ARMword) ((ARMsword) base >> (int) shamt));
+ case ROR:
+ shamt &= 0x1f;
+ if (shamt == 0)
+ return (base);
+ else
+ return ((base << (32 - shamt)) | (base >> shamt));
+ }
+ }
+ else
+ {
+ /* Shift amount is a constant. */
+#ifndef MODE32
+ if (base == 15)
+ base = ECC | ER15INT | R15PC | EMODE;
+ else
+#endif
+ base = state->Reg[base];
+ shamt = BITS (7, 11);
+ switch ((int) BITS (5, 6))
+ {
+ case LSL:
+ return (base << shamt);
+ case LSR:
+ if (shamt == 0)
+ return (0);
+ else
+ return (base >> shamt);
+ case ASR:
+ if (shamt == 0)
+ return ((ARMword) ((ARMsword) base >> 31L));
+ else
+ return ((ARMword) ((ARMsword) base >> (int) shamt));
+ case ROR:
+ if (shamt == 0)
+ /* It's an RRX. */
+ return ((base >> 1) | (CFLAG << 31));
+ else
+ return ((base << (32 - shamt)) | (base >> shamt));
+ }
+ }
+
+ return 0;
+}
+
+/* This routine evaluates most Logical Data Processing register RHS's
+ with the S bit set. It is intended to be called from the macro
+ DPSRegRHS, which filters the common case of an unshifted register
+ with in line code. */
+
+static ARMword
+GetDPSRegRHS (ARMul_State * state, ARMword instr)
+{
+ ARMword shamt, base;
+
+ base = RHSReg;
+ if (BIT (4))
+ {
+ /* Shift amount in a register. */
+ UNDEF_Shift;
+ INCPC;
+#ifndef MODE32
+ if (base == 15)
+ base = ECC | ER15INT | R15PC | EMODE;
+ else
+#endif
+ base = state->Reg[base];
+ ARMul_Icycles (state, 1, 0L);
+ shamt = state->Reg[BITS (8, 11)] & 0xff;
+ switch ((int) BITS (5, 6))
+ {
+ case LSL:
+ if (shamt == 0)
+ return (base);
+ else if (shamt == 32)
+ {
+ ASSIGNC (base & 1);
+ return (0);
+ }
+ else if (shamt > 32)
+ {
+ CLEARC;
+ return (0);
+ }
+ else
+ {
+ ASSIGNC ((base >> (32 - shamt)) & 1);
+ return (base << shamt);
+ }
+ case LSR:
+ if (shamt == 0)
+ return (base);
+ else if (shamt == 32)
+ {
+ ASSIGNC (base >> 31);
+ return (0);
+ }
+ else if (shamt > 32)
+ {
+ CLEARC;
+ return (0);
+ }
+ else
+ {
+ ASSIGNC ((base >> (shamt - 1)) & 1);
+ return (base >> shamt);
+ }
+ case ASR:
+ if (shamt == 0)
+ return (base);
+ else if (shamt >= 32)
+ {
+ ASSIGNC (base >> 31L);
+ return ((ARMword) ((ARMsword) base >> 31L));
+ }
+ else
+ {
+ ASSIGNC ((ARMword) ((ARMsword) base >> (int) (shamt - 1)) & 1);
+ return ((ARMword) ((ARMsword) base >> (int) shamt));
+ }
+ case ROR:
+ if (shamt == 0)
+ return (base);
+ shamt &= 0x1f;
+ if (shamt == 0)
+ {
+ ASSIGNC (base >> 31);
+ return (base);
+ }
+ else
+ {
+ ASSIGNC ((base >> (shamt - 1)) & 1);
+ return ((base << (32 - shamt)) | (base >> shamt));
+ }
+ }
+ }
+ else
+ {
+ /* Shift amount is a constant. */
+#ifndef MODE32
+ if (base == 15)
+ base = ECC | ER15INT | R15PC | EMODE;
+ else
+#endif
+ base = state->Reg[base];
+ shamt = BITS (7, 11);
+
+ switch ((int) BITS (5, 6))
+ {
+ case LSL:
+ ASSIGNC ((base >> (32 - shamt)) & 1);
+ return (base << shamt);
+ case LSR:
+ if (shamt == 0)
+ {
+ ASSIGNC (base >> 31);
+ return (0);
+ }
+ else
+ {
+ ASSIGNC ((base >> (shamt - 1)) & 1);
+ return (base >> shamt);
+ }
+ case ASR:
+ if (shamt == 0)
+ {
+ ASSIGNC (base >> 31L);
+ return ((ARMword) ((ARMsword) base >> 31L));
+ }
+ else
+ {
+ ASSIGNC ((ARMword) ((ARMsword) base >> (int) (shamt - 1)) & 1);
+ return ((ARMword) ((ARMsword) base >> (int) shamt));
+ }
+ case ROR:
+ if (shamt == 0)
+ {
+ /* It's an RRX. */
+ shamt = CFLAG;
+ ASSIGNC (base & 1);
+ return ((base >> 1) | (shamt << 31));
+ }
+ else
+ {
+ ASSIGNC ((base >> (shamt - 1)) & 1);
+ return ((base << (32 - shamt)) | (base >> shamt));
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* This routine handles writes to register 15 when the S bit is not set. */
+
+static void
+WriteR15 (ARMul_State * state, ARMword src)
+{
+ /* The ARM documentation states that the two least significant bits
+ are discarded when setting PC, except in the cases handled by
+ WriteR15Branch() below. It's probably an oversight: in THUMB
+ mode, the second least significant bit should probably not be
+ discarded. */
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, no write-back, down, pre indexed */
- LHPREDOWN() ;
- /* continue with remaining instruction decode */
- }
+ if (TFLAG)
+ src &= 0xfffffffe;
+ else
#endif
- if (DESTReg == 15) { /* CMPP reg */
+ src &= 0xfffffffc;
+
#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
+ state->Reg[15] = src & PCBITS;
#else
- rhs = DPRegRHS ;
- temp = LHS - rhs ;
- SETR15PSR(temp) ;
-#endif
- }
- else { /* CMP reg */
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = lhs - rhs ;
- ARMul_NegZero(state,dest) ;
- if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,lhs,rhs,dest) ;
- ARMul_SubOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- }
- break ;
-
- case 0x16 : /* CMN reg and MSR reg to SPSR */
-#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, write-back, down, pre indexed */
- SHPREDOWNWB() ;
- break ;
- }
-#endif
- if (DESTReg==15 && BITS(17,18)==0) { /* MSR */
- UNDEF_MSRPC ;
- ARMul_FixSPSR(state,instr,DPRegRHS);
- }
- else {
- UNDEF_Test ;
- }
- break ;
-
- case 0x17 : /* CMNP reg */
+ state->Reg[15] = (src & R15PCBITS) | ECC | ER15INT | EMODE;
+ ARMul_R15Altered (state);
+#endif
+
+ FLUSHPIPE;
+ if (trace_funcs)
+ fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
+}
+
+/* This routine handles writes to register 15 when the S bit is set. */
+
+static void
+WriteSR15 (ARMul_State * state, ARMword src)
+{
+#ifdef MODE32
+ if (state->Bank > 0)
+ {
+ state->Cpsr = state->Spsr[state->Bank];
+ ARMul_CPSRAltered (state);
+ }
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, write-back, down, pre indexed */
- LHPREDOWNWB() ;
- /* continue with remaining instruction decoding */
- }
+ if (TFLAG)
+ src &= 0xfffffffe;
+ else
#endif
- if (DESTReg == 15) {
-#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
+ src &= 0xfffffffc;
+ state->Reg[15] = src & PCBITS;
#else
- rhs = DPRegRHS ;
- temp = LHS + rhs ;
- SETR15PSR(temp) ;
-#endif
- break ;
- }
- else { /* CMN reg */
- lhs = LHS ;
- rhs = DPRegRHS ;
- dest = lhs + rhs ;
- ASSIGNZ(dest==0) ;
- if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
- ASSIGNN(NEG(dest)) ;
- ARMul_AddCarry(state,lhs,rhs,dest) ;
- ARMul_AddOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARN ;
- CLEARC ;
- CLEARV ;
- }
- }
- break ;
-
- case 0x18 : /* ORR reg */
-#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, no write-back, up, pre indexed */
- SHPREUP() ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = LHS | rhs ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x19 : /* ORRS reg */
#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, no write-back, up, pre indexed */
- LHPREUP() ;
- /* continue with remaining instruction decoding */
- }
-#endif
- rhs = DPSRegRHS ;
- dest = LHS | rhs ;
- WRITESDEST(dest) ;
- break ;
-
- case 0x1a : /* MOV reg */
-#ifdef MODET
- if (BITS(4,11) == 0xB) {
- /* STRH register offset, write-back, up, pre indexed */
- SHPREUPWB() ;
- break ;
- }
+ if (TFLAG)
+ /* ARMul_R15Altered would have to support it. */
+ abort ();
+ else
#endif
- dest = DPRegRHS ;
- WRITEDEST(dest) ;
- break ;
+ src &= 0xfffffffc;
- case 0x1b : /* MOVS reg */
-#ifdef MODET
- if ((BITS(4,11) & 0xF9) == 0x9) {
- /* LDR register offset, write-back, up, pre indexed */
- LHPREUPWB() ;
- /* continue with remaining instruction decoding */
- }
-#endif
- dest = DPSRegRHS ;
- WRITESDEST(dest) ;
- break ;
+ if (state->Bank == USERBANK)
+ state->Reg[15] = (src & (CCBITS | R15PCBITS)) | ER15INT | EMODE;
+ else
+ state->Reg[15] = src;
- case 0x1c : /* BIC reg */
-#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, no write-back, up, pre indexed */
- SHPREUP() ;
- break ;
- }
-#endif
- rhs = DPRegRHS ;
- dest = LHS & ~rhs ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x1d : /* BICS reg */
-#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, no write-back, up, pre indexed */
- LHPREUP() ;
- /* continue with instruction decoding */
- }
-#endif
- rhs = DPSRegRHS ;
- dest = LHS & ~rhs ;
- WRITESDEST(dest) ;
- break ;
-
- case 0x1e : /* MVN reg */
-#ifdef MODET
- if (BITS(4,7) == 0xB) {
- /* STRH immediate offset, write-back, up, pre indexed */
- SHPREUPWB() ;
- break ;
- }
+ ARMul_R15Altered (state);
#endif
- dest = ~DPRegRHS ;
- WRITEDEST(dest) ;
- break ;
+ FLUSHPIPE;
+ if (trace_funcs)
+ fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
+}
+
+/* In machines capable of running in Thumb mode, BX, BLX, LDR and LDM
+ will switch to Thumb mode if the least significant bit is set. */
- case 0x1f : /* MVNS reg */
+static void
+WriteR15Branch (ARMul_State * state, ARMword src)
+{
#ifdef MODET
- if ((BITS(4,7) & 0x9) == 0x9) {
- /* LDR immediate offset, write-back, up, pre indexed */
- LHPREUPWB() ;
- /* continue instruction decoding */
- }
-#endif
- dest = ~DPSRegRHS ;
- WRITESDEST(dest) ;
- break ;
-
-/***************************************************************************\
-* Data Processing Immediate RHS Instructions *
-\***************************************************************************/
-
- case 0x20 : /* AND immed */
- dest = LHS & DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x21 : /* ANDS immed */
- DPSImmRHS ;
- dest = LHS & rhs ;
- WRITESDEST(dest) ;
- break ;
-
- case 0x22 : /* EOR immed */
- dest = LHS ^ DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x23 : /* EORS immed */
- DPSImmRHS ;
- dest = LHS ^ rhs ;
- WRITESDEST(dest) ;
- break ;
-
- case 0x24 : /* SUB immed */
- dest = LHS - DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x25 : /* SUBS immed */
- lhs = LHS ;
- rhs = DPImmRHS ;
- dest = lhs - rhs ;
- if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,lhs,rhs,dest) ;
- ARMul_SubOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x26 : /* RSB immed */
- dest = DPImmRHS - LHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x27 : /* RSBS immed */
- lhs = LHS ;
- rhs = DPImmRHS ;
- dest = rhs - lhs ;
- if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,rhs,lhs,dest) ;
- ARMul_SubOverflow(state,rhs,lhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x28 : /* ADD immed */
- dest = LHS + DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x29 : /* ADDS immed */
- lhs = LHS ;
- rhs = DPImmRHS ;
- dest = lhs + rhs ;
- ASSIGNZ(dest==0) ;
- if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
- ASSIGNN(NEG(dest)) ;
- ARMul_AddCarry(state,lhs,rhs,dest) ;
- ARMul_AddOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARN ;
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x2a : /* ADC immed */
- dest = LHS + DPImmRHS + CFLAG ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x2b : /* ADCS immed */
- lhs = LHS ;
- rhs = DPImmRHS ;
- dest = lhs + rhs + CFLAG ;
- ASSIGNZ(dest==0) ;
- if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
- ASSIGNN(NEG(dest)) ;
- ARMul_AddCarry(state,lhs,rhs,dest) ;
- ARMul_AddOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARN ;
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x2c : /* SBC immed */
- dest = LHS - DPImmRHS - !CFLAG ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x2d : /* SBCS immed */
- lhs = LHS ;
- rhs = DPImmRHS ;
- dest = lhs - rhs - !CFLAG ;
- if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,lhs,rhs,dest) ;
- ARMul_SubOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x2e : /* RSC immed */
- dest = DPImmRHS - LHS - !CFLAG ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x2f : /* RSCS immed */
- lhs = LHS ;
- rhs = DPImmRHS ;
- dest = rhs - lhs - !CFLAG ;
- if ((rhs >= lhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,rhs,lhs,dest) ;
- ARMul_SubOverflow(state,rhs,lhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- WRITESDEST(dest) ;
- break ;
-
- case 0x30 : /* TST immed */
- UNDEF_Test ;
- break ;
-
- case 0x31 : /* TSTP immed */
- if (DESTReg == 15) { /* TSTP immed */
-#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
-#else
- temp = LHS & DPImmRHS ;
- SETR15PSR(temp) ;
-#endif
- }
- else {
- DPSImmRHS ; /* TST immed */
- dest = LHS & rhs ;
- ARMul_NegZero(state,dest) ;
- }
- break ;
-
- case 0x32 : /* TEQ immed and MSR immed to CPSR */
- if (DESTReg==15 && BITS(17,18)==0) { /* MSR immed to CPSR */
- ARMul_FixCPSR(state,instr,DPImmRHS) ;
- }
- else {
- UNDEF_Test ;
- }
- break ;
-
- case 0x33 : /* TEQP immed */
- if (DESTReg == 15) { /* TEQP immed */
-#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
-#else
- temp = LHS ^ DPImmRHS ;
- SETR15PSR(temp) ;
-#endif
- }
- else {
- DPSImmRHS ; /* TEQ immed */
- dest = LHS ^ rhs ;
- ARMul_NegZero(state,dest) ;
- }
- break ;
-
- case 0x34 : /* CMP immed */
- UNDEF_Test ;
- break ;
-
- case 0x35 : /* CMPP immed */
- if (DESTReg == 15) { /* CMPP immed */
-#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
-#else
- temp = LHS - DPImmRHS ;
- SETR15PSR(temp) ;
-#endif
- break ;
- }
- else {
- lhs = LHS ; /* CMP immed */
- rhs = DPImmRHS ;
- dest = lhs - rhs ;
- ARMul_NegZero(state,dest) ;
- if ((lhs >= rhs) || ((rhs | lhs) >> 31)) {
- ARMul_SubCarry(state,lhs,rhs,dest) ;
- ARMul_SubOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARC ;
- CLEARV ;
- }
- }
- break ;
-
- case 0x36 : /* CMN immed and MSR immed to SPSR */
- if (DESTReg==15 && BITS(17,18)==0) /* MSR */
- ARMul_FixSPSR(state, instr, DPImmRHS) ;
- else {
- UNDEF_Test ;
- }
- break ;
-
- case 0x37 : /* CMNP immed */
- if (DESTReg == 15) { /* CMNP immed */
-#ifdef MODE32
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
-#else
- temp = LHS + DPImmRHS ;
- SETR15PSR(temp) ;
-#endif
- break ;
- }
- else {
- lhs = LHS ; /* CMN immed */
- rhs = DPImmRHS ;
- dest = lhs + rhs ;
- ASSIGNZ(dest==0) ;
- if ((lhs | rhs) >> 30) { /* possible C,V,N to set */
- ASSIGNN(NEG(dest)) ;
- ARMul_AddCarry(state,lhs,rhs,dest) ;
- ARMul_AddOverflow(state,lhs,rhs,dest) ;
- }
- else {
- CLEARN ;
- CLEARC ;
- CLEARV ;
- }
- }
- break ;
-
- case 0x38 : /* ORR immed */
- dest = LHS | DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x39 : /* ORRS immed */
- DPSImmRHS ;
- dest = LHS | rhs ;
- WRITESDEST(dest) ;
- break ;
-
- case 0x3a : /* MOV immed */
- dest = DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x3b : /* MOVS immed */
- DPSImmRHS ;
- WRITESDEST(rhs) ;
- break ;
-
- case 0x3c : /* BIC immed */
- dest = LHS & ~DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x3d : /* BICS immed */
- DPSImmRHS ;
- dest = LHS & ~rhs ;
- WRITESDEST(dest) ;
- break ;
-
- case 0x3e : /* MVN immed */
- dest = ~DPImmRHS ;
- WRITEDEST(dest) ;
- break ;
-
- case 0x3f : /* MVNS immed */
- DPSImmRHS ;
- WRITESDEST(~rhs) ;
- break ;
-
-/***************************************************************************\
-* Single Data Transfer Immediate RHS Instructions *
-\***************************************************************************/
-
- case 0x40 : /* Store Word, No WriteBack, Post Dec, Immed */
- lhs = LHS ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs - LSImmRHS ;
- break ;
-
- case 0x41 : /* Load Word, No WriteBack, Post Dec, Immed */
- lhs = LHS ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs - LSImmRHS ;
- break ;
-
- case 0x42 : /* Store Word, WriteBack, Post Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- temp = lhs - LSImmRHS ;
- state->NtransSig = LOW ;
- if (StoreWord(state,instr,lhs))
- LSBase = temp ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x43 : /* Load Word, WriteBack, Post Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs - LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x44 : /* Store Byte, No WriteBack, Post Dec, Immed */
- lhs = LHS ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs - LSImmRHS ;
- break ;
-
- case 0x45 : /* Load Byte, No WriteBack, Post Dec, Immed */
- lhs = LHS ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs - LSImmRHS ;
- break ;
-
- case 0x46 : /* Store Byte, WriteBack, Post Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs - LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x47 : /* Load Byte, WriteBack, Post Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs - LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x48 : /* Store Word, No WriteBack, Post Inc, Immed */
- lhs = LHS ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs + LSImmRHS ;
- break ;
-
- case 0x49 : /* Load Word, No WriteBack, Post Inc, Immed */
- lhs = LHS ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs + LSImmRHS ;
- break ;
-
- case 0x4a : /* Store Word, WriteBack, Post Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs + LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x4b : /* Load Word, WriteBack, Post Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs + LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x4c : /* Store Byte, No WriteBack, Post Inc, Immed */
- lhs = LHS ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs + LSImmRHS ;
- break ;
-
- case 0x4d : /* Load Byte, No WriteBack, Post Inc, Immed */
- lhs = LHS ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs + LSImmRHS ;
- break ;
-
- case 0x4e : /* Store Byte, WriteBack, Post Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs + LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x4f : /* Load Byte, WriteBack, Post Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs + LSImmRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
-
- case 0x50 : /* Store Word, No WriteBack, Pre Dec, Immed */
- (void)StoreWord(state,instr,LHS - LSImmRHS) ;
- break ;
-
- case 0x51 : /* Load Word, No WriteBack, Pre Dec, Immed */
- (void)LoadWord(state,instr,LHS - LSImmRHS) ;
- break ;
-
- case 0x52 : /* Store Word, WriteBack, Pre Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS - LSImmRHS ;
- if (StoreWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x53 : /* Load Word, WriteBack, Pre Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS - LSImmRHS ;
- if (LoadWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x54 : /* Store Byte, No WriteBack, Pre Dec, Immed */
- (void)StoreByte(state,instr,LHS - LSImmRHS) ;
- break ;
-
- case 0x55 : /* Load Byte, No WriteBack, Pre Dec, Immed */
- (void)LoadByte(state,instr,LHS - LSImmRHS,LUNSIGNED) ;
- break ;
-
- case 0x56 : /* Store Byte, WriteBack, Pre Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS - LSImmRHS ;
- if (StoreByte(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x57 : /* Load Byte, WriteBack, Pre Dec, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS - LSImmRHS ;
- if (LoadByte(state,instr,temp,LUNSIGNED))
- LSBase = temp ;
- break ;
-
- case 0x58 : /* Store Word, No WriteBack, Pre Inc, Immed */
- (void)StoreWord(state,instr,LHS + LSImmRHS) ;
- break ;
-
- case 0x59 : /* Load Word, No WriteBack, Pre Inc, Immed */
- (void)LoadWord(state,instr,LHS + LSImmRHS) ;
- break ;
-
- case 0x5a : /* Store Word, WriteBack, Pre Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS + LSImmRHS ;
- if (StoreWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x5b : /* Load Word, WriteBack, Pre Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS + LSImmRHS ;
- if (LoadWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x5c : /* Store Byte, No WriteBack, Pre Inc, Immed */
- (void)StoreByte(state,instr,LHS + LSImmRHS) ;
- break ;
-
- case 0x5d : /* Load Byte, No WriteBack, Pre Inc, Immed */
- (void)LoadByte(state,instr,LHS + LSImmRHS,LUNSIGNED) ;
- break ;
-
- case 0x5e : /* Store Byte, WriteBack, Pre Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS + LSImmRHS ;
- if (StoreByte(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x5f : /* Load Byte, WriteBack, Pre Inc, Immed */
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- temp = LHS + LSImmRHS ;
- if (LoadByte(state,instr,temp,LUNSIGNED))
- LSBase = temp ;
- break ;
-
-/***************************************************************************\
-* Single Data Transfer Register RHS Instructions *
-\***************************************************************************/
-
- case 0x60 : /* Store Word, No WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs - LSRegRHS ;
- break ;
-
- case 0x61 : /* Load Word, No WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs - LSRegRHS ;
- break ;
-
- case 0x62 : /* Store Word, WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs - LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x63 : /* Load Word, WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs - LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x64 : /* Store Byte, No WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs - LSRegRHS ;
- break ;
-
- case 0x65 : /* Load Byte, No WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs - LSRegRHS ;
- break ;
-
- case 0x66 : /* Store Byte, WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs - LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x67 : /* Load Byte, WriteBack, Post Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs - LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x68 : /* Store Word, No WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs + LSRegRHS ;
- break ;
-
- case 0x69 : /* Load Word, No WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs + LSRegRHS ;
- break ;
-
- case 0x6a : /* Store Word, WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreWord(state,instr,lhs))
- LSBase = lhs + LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x6b : /* Load Word, WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadWord(state,instr,lhs))
- LSBase = lhs + LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x6c : /* Store Byte, No WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs + LSRegRHS ;
- break ;
-
- case 0x6d : /* Load Byte, No WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs + LSRegRHS ;
- break ;
-
- case 0x6e : /* Store Byte, WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (StoreByte(state,instr,lhs))
- LSBase = lhs + LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
- case 0x6f : /* Load Byte, WriteBack, Post Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- lhs = LHS ;
- state->NtransSig = LOW ;
- if (LoadByte(state,instr,lhs,LUNSIGNED))
- LSBase = lhs + LSRegRHS ;
- state->NtransSig = (state->Mode & 3)?HIGH:LOW ;
- break ;
-
-
- case 0x70 : /* Store Word, No WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)StoreWord(state,instr,LHS - LSRegRHS) ;
- break ;
-
- case 0x71 : /* Load Word, No WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)LoadWord(state,instr,LHS - LSRegRHS) ;
- break ;
-
- case 0x72 : /* Store Word, WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS - LSRegRHS ;
- if (StoreWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x73 : /* Load Word, WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS - LSRegRHS ;
- if (LoadWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x74 : /* Store Byte, No WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)StoreByte(state,instr,LHS - LSRegRHS) ;
- break ;
-
- case 0x75 : /* Load Byte, No WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)LoadByte(state,instr,LHS - LSRegRHS,LUNSIGNED) ;
- break ;
-
- case 0x76 : /* Store Byte, WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS - LSRegRHS ;
- if (StoreByte(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x77 : /* Load Byte, WriteBack, Pre Dec, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS - LSRegRHS ;
- if (LoadByte(state,instr,temp,LUNSIGNED))
- LSBase = temp ;
- break ;
-
- case 0x78 : /* Store Word, No WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)StoreWord(state,instr,LHS + LSRegRHS) ;
- break ;
-
- case 0x79 : /* Load Word, No WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)LoadWord(state,instr,LHS + LSRegRHS) ;
- break ;
-
- case 0x7a : /* Store Word, WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS + LSRegRHS ;
- if (StoreWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x7b : /* Load Word, WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS + LSRegRHS ;
- if (LoadWord(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x7c : /* Store Byte, No WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)StoreByte(state,instr,LHS + LSRegRHS) ;
- break ;
-
- case 0x7d : /* Load Byte, No WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- (void)LoadByte(state,instr,LHS + LSRegRHS,LUNSIGNED) ;
- break ;
-
- case 0x7e : /* Store Byte, WriteBack, Pre Inc, Reg */
- if (BIT(4)) {
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS + LSRegRHS ;
- if (StoreByte(state,instr,temp))
- LSBase = temp ;
- break ;
-
- case 0x7f : /* Load Byte, WriteBack, Pre Inc, Reg */
- if (BIT(4))
- {
- /* Check for the special breakpoint opcode.
- This value should correspond to the value defined
- as ARM_BE_BREAKPOINT in gdb/arm-tdep.c. */
- if (BITS (0,19) == 0xfdefe)
- {
- if (! ARMul_OSHandleSWI (state, SWI_Breakpoint))
- ARMul_Abort (state, ARMul_SWIV);
- }
- else
- ARMul_UndefInstr(state,instr) ;
- break ;
- }
- UNDEF_LSRBaseEQOffWb ;
- UNDEF_LSRBaseEQDestWb ;
- UNDEF_LSRPCBaseWb ;
- UNDEF_LSRPCOffWb ;
- temp = LHS + LSRegRHS ;
- if (LoadByte(state,instr,temp,LUNSIGNED))
- LSBase = temp ;
- break ;
-
-/***************************************************************************\
-* Multiple Data Transfer Instructions *
-\***************************************************************************/
-
- case 0x80 : /* Store, No WriteBack, Post Dec */
- STOREMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
- break ;
-
- case 0x81 : /* Load, No WriteBack, Post Dec */
- LOADMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
- break ;
-
- case 0x82 : /* Store, WriteBack, Post Dec */
- temp = LSBase - LSMNumRegs ;
- STOREMULT(instr,temp + 4L,temp) ;
- break ;
-
- case 0x83 : /* Load, WriteBack, Post Dec */
- temp = LSBase - LSMNumRegs ;
- LOADMULT(instr,temp + 4L,temp) ;
- break ;
-
- case 0x84 : /* Store, Flags, No WriteBack, Post Dec */
- STORESMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
- break ;
-
- case 0x85 : /* Load, Flags, No WriteBack, Post Dec */
- LOADSMULT(instr,LSBase - LSMNumRegs + 4L,0L) ;
- break ;
-
- case 0x86 : /* Store, Flags, WriteBack, Post Dec */
- temp = LSBase - LSMNumRegs ;
- STORESMULT(instr,temp + 4L,temp) ;
- break ;
-
- case 0x87 : /* Load, Flags, WriteBack, Post Dec */
- temp = LSBase - LSMNumRegs ;
- LOADSMULT(instr,temp + 4L,temp) ;
- break ;
-
-
- case 0x88 : /* Store, No WriteBack, Post Inc */
- STOREMULT(instr,LSBase,0L) ;
- break ;
-
- case 0x89 : /* Load, No WriteBack, Post Inc */
- LOADMULT(instr,LSBase,0L) ;
- break ;
-
- case 0x8a : /* Store, WriteBack, Post Inc */
- temp = LSBase ;
- STOREMULT(instr,temp,temp + LSMNumRegs) ;
- break ;
-
- case 0x8b : /* Load, WriteBack, Post Inc */
- temp = LSBase ;
- LOADMULT(instr,temp,temp + LSMNumRegs) ;
- break ;
-
- case 0x8c : /* Store, Flags, No WriteBack, Post Inc */
- STORESMULT(instr,LSBase,0L) ;
- break ;
-
- case 0x8d : /* Load, Flags, No WriteBack, Post Inc */
- LOADSMULT(instr,LSBase,0L) ;
- break ;
-
- case 0x8e : /* Store, Flags, WriteBack, Post Inc */
- temp = LSBase ;
- STORESMULT(instr,temp,temp + LSMNumRegs) ;
- break ;
-
- case 0x8f : /* Load, Flags, WriteBack, Post Inc */
- temp = LSBase ;
- LOADSMULT(instr,temp,temp + LSMNumRegs) ;
- break ;
-
-
- case 0x90 : /* Store, No WriteBack, Pre Dec */
- STOREMULT(instr,LSBase - LSMNumRegs,0L) ;
- break ;
-
- case 0x91 : /* Load, No WriteBack, Pre Dec */
- LOADMULT(instr,LSBase - LSMNumRegs,0L) ;
- break ;
-
- case 0x92 : /* Store, WriteBack, Pre Dec */
- temp = LSBase - LSMNumRegs ;
- STOREMULT(instr,temp,temp) ;
- break ;
-
- case 0x93 : /* Load, WriteBack, Pre Dec */
- temp = LSBase - LSMNumRegs ;
- LOADMULT(instr,temp,temp) ;
- break ;
-
- case 0x94 : /* Store, Flags, No WriteBack, Pre Dec */
- STORESMULT(instr,LSBase - LSMNumRegs,0L) ;
- break ;
-
- case 0x95 : /* Load, Flags, No WriteBack, Pre Dec */
- LOADSMULT(instr,LSBase - LSMNumRegs,0L) ;
- break ;
-
- case 0x96 : /* Store, Flags, WriteBack, Pre Dec */
- temp = LSBase - LSMNumRegs ;
- STORESMULT(instr,temp,temp) ;
- break ;
-
- case 0x97 : /* Load, Flags, WriteBack, Pre Dec */
- temp = LSBase - LSMNumRegs ;
- LOADSMULT(instr,temp,temp) ;
- break ;
-
-
- case 0x98 : /* Store, No WriteBack, Pre Inc */
- STOREMULT(instr,LSBase + 4L,0L) ;
- break ;
-
- case 0x99 : /* Load, No WriteBack, Pre Inc */
- LOADMULT(instr,LSBase + 4L,0L) ;
- break ;
-
- case 0x9a : /* Store, WriteBack, Pre Inc */
- temp = LSBase ;
- STOREMULT(instr,temp + 4L,temp + LSMNumRegs) ;
- break ;
-
- case 0x9b : /* Load, WriteBack, Pre Inc */
- temp = LSBase ;
- LOADMULT(instr,temp + 4L,temp + LSMNumRegs) ;
- break ;
-
- case 0x9c : /* Store, Flags, No WriteBack, Pre Inc */
- STORESMULT(instr,LSBase + 4L,0L) ;
- break ;
-
- case 0x9d : /* Load, Flags, No WriteBack, Pre Inc */
- LOADSMULT(instr,LSBase + 4L,0L) ;
- break ;
-
- case 0x9e : /* Store, Flags, WriteBack, Pre Inc */
- temp = LSBase ;
- STORESMULT(instr,temp + 4L,temp + LSMNumRegs) ;
- break ;
-
- case 0x9f : /* Load, Flags, WriteBack, Pre Inc */
- temp = LSBase ;
- LOADSMULT(instr,temp + 4L,temp + LSMNumRegs) ;
- break ;
-
-/***************************************************************************\
-* Branch forward *
-\***************************************************************************/
-
- case 0xa0 : case 0xa1 : case 0xa2 : case 0xa3 :
- case 0xa4 : case 0xa5 : case 0xa6 : case 0xa7 :
- state->Reg[15] = pc + 8 + POSBRANCH ;
- FLUSHPIPE ;
- break ;
-
-/***************************************************************************\
-* Branch backward *
-\***************************************************************************/
-
- case 0xa8 : case 0xa9 : case 0xaa : case 0xab :
- case 0xac : case 0xad : case 0xae : case 0xaf :
- state->Reg[15] = pc + 8 + NEGBRANCH ;
- FLUSHPIPE ;
- break ;
-
-/***************************************************************************\
-* Branch and Link forward *
-\***************************************************************************/
-
- case 0xb0 : case 0xb1 : case 0xb2 : case 0xb3 :
- case 0xb4 : case 0xb5 : case 0xb6 : case 0xb7 :
-#ifdef MODE32
- state->Reg[14] = pc + 4 ; /* put PC into Link */
+ if (src & 1)
+ {
+ /* Thumb bit. */
+ SETT;
+ state->Reg[15] = src & 0xfffffffe;
+ }
+ else
+ {
+ CLEART;
+ state->Reg[15] = src & 0xfffffffc;
+ }
+ FLUSHPIPE;
+ if (trace_funcs)
+ fprintf (stderr, " pc changed to %x\n", state->Reg[15]);
#else
- state->Reg[14] = pc + 4 | ECC | ER15INT | EMODE ; /* put PC into Link */
+ WriteR15 (state, src);
#endif
- state->Reg[15] = pc + 8 + POSBRANCH ;
- FLUSHPIPE ;
- break ;
+}
-/***************************************************************************\
-* Branch and Link backward *
-\***************************************************************************/
+/* Before ARM_v5 LDR and LDM of pc did not change mode. */
- case 0xb8 : case 0xb9 : case 0xba : case 0xbb :
- case 0xbc : case 0xbd : case 0xbe : case 0xbf :
-#ifdef MODE32
- state->Reg[14] = pc + 4 ; /* put PC into Link */
-#else
- state->Reg[14] = (pc + 4) | ECC | ER15INT | EMODE ; /* put PC into Link */
-#endif
- state->Reg[15] = pc + 8 + NEGBRANCH ;
- FLUSHPIPE ;
- break ;
-
-/***************************************************************************\
-* Co-Processor Data Transfers *
-\***************************************************************************/
-
- case 0xc0 :
- case 0xc4 : /* Store , No WriteBack , Post Dec */
- ARMul_STC(state,instr,LHS) ;
- break ;
-
- case 0xc1 :
- case 0xc5 : /* Load , No WriteBack , Post Dec */
- ARMul_LDC(state,instr,LHS) ;
- break ;
-
- case 0xc2 :
- case 0xc6 : /* Store , WriteBack , Post Dec */
- lhs = LHS ;
- state->Base = lhs - LSCOff ;
- ARMul_STC(state,instr,lhs) ;
- break ;
-
- case 0xc3 :
- case 0xc7 : /* Load , WriteBack , Post Dec */
- lhs = LHS ;
- state->Base = lhs - LSCOff ;
- ARMul_LDC(state,instr,lhs) ;
- break ;
-
- case 0xc8 :
- case 0xcc : /* Store , No WriteBack , Post Inc */
- ARMul_STC(state,instr,LHS) ;
- break ;
-
- case 0xc9 :
- case 0xcd : /* Load , No WriteBack , Post Inc */
- ARMul_LDC(state,instr,LHS) ;
- break ;
-
- case 0xca :
- case 0xce : /* Store , WriteBack , Post Inc */
- lhs = LHS ;
- state->Base = lhs + LSCOff ;
- ARMul_STC(state,instr,LHS) ;
- break ;
-
- case 0xcb :
- case 0xcf : /* Load , WriteBack , Post Inc */
- lhs = LHS ;
- state->Base = lhs + LSCOff ;
- ARMul_LDC(state,instr,LHS) ;
- break ;
-
-
- case 0xd0 :
- case 0xd4 : /* Store , No WriteBack , Pre Dec */
- ARMul_STC(state,instr,LHS - LSCOff) ;
- break ;
-
- case 0xd1 :
- case 0xd5 : /* Load , No WriteBack , Pre Dec */
- ARMul_LDC(state,instr,LHS - LSCOff) ;
- break ;
-
- case 0xd2 :
- case 0xd6 : /* Store , WriteBack , Pre Dec */
- lhs = LHS - LSCOff ;
- state->Base = lhs ;
- ARMul_STC(state,instr,lhs) ;
- break ;
-
- case 0xd3 :
- case 0xd7 : /* Load , WriteBack , Pre Dec */
- lhs = LHS - LSCOff ;
- state->Base = lhs ;
- ARMul_LDC(state,instr,lhs) ;
- break ;
-
- case 0xd8 :
- case 0xdc : /* Store , No WriteBack , Pre Inc */
- ARMul_STC(state,instr,LHS + LSCOff) ;
- break ;
-
- case 0xd9 :
- case 0xdd : /* Load , No WriteBack , Pre Inc */
- ARMul_LDC(state,instr,LHS + LSCOff) ;
- break ;
-
- case 0xda :
- case 0xde : /* Store , WriteBack , Pre Inc */
- lhs = LHS + LSCOff ;
- state->Base = lhs ;
- ARMul_STC(state,instr,lhs) ;
- break ;
-
- case 0xdb :
- case 0xdf : /* Load , WriteBack , Pre Inc */
- lhs = LHS + LSCOff ;
- state->Base = lhs ;
- ARMul_LDC(state,instr,lhs) ;
- break ;
-
-/***************************************************************************\
-* Co-Processor Register Transfers (MCR) and Data Ops *
-\***************************************************************************/
-
- case 0xe0 : case 0xe2 : case 0xe4 : case 0xe6 :
- case 0xe8 : case 0xea : case 0xec : case 0xee :
- if (BIT(4)) { /* MCR */
- if (DESTReg == 15) {
- UNDEF_MCRPC ;
-#ifdef MODE32
- ARMul_MCR(state,instr,state->Reg[15] + isize) ;
-#else
- ARMul_MCR(state,instr,ECC | ER15INT | EMODE |
- ((state->Reg[15] + isize) & R15PCBITS) ) ;
-#endif
- }
- else
- ARMul_MCR(state,instr,DEST) ;
- }
- else /* CDP Part 1 */
- ARMul_CDP(state,instr) ;
- break ;
-
-/***************************************************************************\
-* Co-Processor Register Transfers (MRC) and Data Ops *
-\***************************************************************************/
-
- case 0xe1 : case 0xe3 : case 0xe5 : case 0xe7 :
- case 0xe9 : case 0xeb : case 0xed : case 0xef :
- if (BIT(4)) { /* MRC */
- temp = ARMul_MRC(state,instr) ;
- if (DESTReg == 15) {
- ASSIGNN((temp & NBIT) != 0) ;
- ASSIGNZ((temp & ZBIT) != 0) ;
- ASSIGNC((temp & CBIT) != 0) ;
- ASSIGNV((temp & VBIT) != 0) ;
- }
- else
- DEST = temp ;
- }
- else /* CDP Part 2 */
- ARMul_CDP(state,instr) ;
- break ;
-
-/***************************************************************************\
-* SWI instruction *
-\***************************************************************************/
-
- case 0xf0 : case 0xf1 : case 0xf2 : case 0xf3 :
- case 0xf4 : case 0xf5 : case 0xf6 : case 0xf7 :
- case 0xf8 : case 0xf9 : case 0xfa : case 0xfb :
- case 0xfc : case 0xfd : case 0xfe : case 0xff :
- if (instr == ARMul_ABORTWORD && state->AbortAddr == pc) { /* a prefetch abort */
- ARMul_Abort(state,ARMul_PrefetchAbortV) ;
- break ;
- }
-
- if (!ARMul_OSHandleSWI(state,BITS(0,23))) {
- ARMul_Abort(state,ARMul_SWIV) ;
- }
- break ;
- } /* 256 way main switch */
- } /* if temp */
+static void
+WriteR15Load (ARMul_State * state, ARMword src)
+{
+ if (state->is_v5)
+ WriteR15Branch (state, src);
+ else
+ WriteR15 (state, src);
+}
-#ifdef MODET
-donext:
-#endif
+/* This routine evaluates most Load and Store register RHS's. It is
+ intended to be called from the macro LSRegRHS, which filters the
+ common case of an unshifted register with in line code. */
-#ifdef NEED_UI_LOOP_HOOK
- if (ui_loop_hook != NULL && ui_loop_hook_counter-- < 0)
- {
- ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL;
- ui_loop_hook (0);
- }
-#endif /* NEED_UI_LOOP_HOOK */
-
- if (state->Emulate == ONCE)
- state->Emulate = STOP;
- else if (state->Emulate != RUN)
- break;
- } while (!stop_simulator) ; /* do loop */
-
- state->decoded = decoded ;
- state->loaded = loaded ;
- state->pc = pc ;
- return(pc) ;
- } /* Emulate 26/32 in instruction based mode */
-
-
-/***************************************************************************\
-* This routine evaluates most Data Processing register RHS's with the S *
-* bit clear. It is intended to be called from the macro DPRegRHS, which *
-* filters the common case of an unshifted register with in line code *
-\***************************************************************************/
-
-static ARMword GetDPRegRHS(ARMul_State *state, ARMword instr)
-{ARMword shamt , base ;
-
- base = RHSReg ;
- if (BIT(4)) { /* shift amount in a register */
- UNDEF_Shift ;
- INCPC ;
-#ifndef MODE32
- if (base == 15)
- base = ECC | ER15INT | R15PC | EMODE ;
- else
-#endif
- base = state->Reg[base] ;
- ARMul_Icycles(state,1,0L) ;
- shamt = state->Reg[BITS(8,11)] & 0xff ;
- switch ((int)BITS(5,6)) {
- case LSL : if (shamt == 0)
- return(base) ;
- else if (shamt >= 32)
- return(0) ;
- else
- return(base << shamt) ;
- case LSR : if (shamt == 0)
- return(base) ;
- else if (shamt >= 32)
- return(0) ;
- else
- return(base >> shamt) ;
- case ASR : if (shamt == 0)
- return(base) ;
- else if (shamt >= 32)
- return((ARMword)((long int)base >> 31L)) ;
- else
- return((ARMword)((long int)base >> (int)shamt)) ;
- case ROR : shamt &= 0x1f ;
- if (shamt == 0)
- return(base) ;
- else
- return((base << (32 - shamt)) | (base >> shamt)) ;
- }
- }
- else { /* shift amount is a constant */
-#ifndef MODE32
- if (base == 15)
- base = ECC | ER15INT | R15PC | EMODE ;
- else
-#endif
- base = state->Reg[base] ;
- shamt = BITS(7,11) ;
- switch ((int)BITS(5,6)) {
- case LSL : return(base<<shamt) ;
- case LSR : if (shamt == 0)
- return(0) ;
- else
- return(base >> shamt) ;
- case ASR : if (shamt == 0)
- return((ARMword)((long int)base >> 31L)) ;
- else
- return((ARMword)((long int)base >> (int)shamt)) ;
- case ROR : if (shamt==0) /* its an RRX */
- return((base >> 1) | (CFLAG << 31)) ;
- else
- return((base << (32 - shamt)) | (base >> shamt)) ;
- }
- }
- return(0) ; /* just to shut up lint */
- }
-/***************************************************************************\
-* This routine evaluates most Logical Data Processing register RHS's *
-* with the S bit set. It is intended to be called from the macro *
-* DPSRegRHS, which filters the common case of an unshifted register *
-* with in line code *
-\***************************************************************************/
-
-static ARMword GetDPSRegRHS(ARMul_State *state, ARMword instr)
-{ARMword shamt , base ;
-
- base = RHSReg ;
- if (BIT(4)) { /* shift amount in a register */
- UNDEF_Shift ;
- INCPC ;
-#ifndef MODE32
- if (base == 15)
- base = ECC | ER15INT | R15PC | EMODE ;
- else
-#endif
- base = state->Reg[base] ;
- ARMul_Icycles(state,1,0L) ;
- shamt = state->Reg[BITS(8,11)] & 0xff ;
- switch ((int)BITS(5,6)) {
- case LSL : if (shamt == 0)
- return(base) ;
- else if (shamt == 32) {
- ASSIGNC(base & 1) ;
- return(0) ;
- }
- else if (shamt > 32) {
- CLEARC ;
- return(0) ;
- }
- else {
- ASSIGNC((base >> (32-shamt)) & 1) ;
- return(base << shamt) ;
- }
- case LSR : if (shamt == 0)
- return(base) ;
- else if (shamt == 32) {
- ASSIGNC(base >> 31) ;
- return(0) ;
- }
- else if (shamt > 32) {
- CLEARC ;
- return(0) ;
- }
- else {
- ASSIGNC((base >> (shamt - 1)) & 1) ;
- return(base >> shamt) ;
- }
- case ASR : if (shamt == 0)
- return(base) ;
- else if (shamt >= 32) {
- ASSIGNC(base >> 31L) ;
- return((ARMword)((long int)base >> 31L)) ;
- }
- else {
- ASSIGNC((ARMword)((long int)base >> (int)(shamt-1)) & 1) ;
- return((ARMword)((long int)base >> (int)shamt)) ;
- }
- case ROR : if (shamt == 0)
- return(base) ;
- shamt &= 0x1f ;
- if (shamt == 0) {
- ASSIGNC(base >> 31) ;
- return(base) ;
- }
- else {
- ASSIGNC((base >> (shamt-1)) & 1) ;
- return((base << (32-shamt)) | (base >> shamt)) ;
- }
- }
- }
- else { /* shift amount is a constant */
+static ARMword
+GetLSRegRHS (ARMul_State * state, ARMword instr)
+{
+ ARMword shamt, base;
+
+ base = RHSReg;
#ifndef MODE32
- if (base == 15)
- base = ECC | ER15INT | R15PC | EMODE ;
- else
-#endif
- base = state->Reg[base] ;
- shamt = BITS(7,11) ;
- switch ((int)BITS(5,6)) {
- case LSL : ASSIGNC((base >> (32-shamt)) & 1) ;
- return(base << shamt) ;
- case LSR : if (shamt == 0) {
- ASSIGNC(base >> 31) ;
- return(0) ;
- }
- else {
- ASSIGNC((base >> (shamt - 1)) & 1) ;
- return(base >> shamt) ;
- }
- case ASR : if (shamt == 0) {
- ASSIGNC(base >> 31L) ;
- return((ARMword)((long int)base >> 31L)) ;
- }
- else {
- ASSIGNC((ARMword)((long int)base >> (int)(shamt-1)) & 1) ;
- return((ARMword)((long int)base >> (int)shamt)) ;
- }
- case ROR : if (shamt == 0) { /* its an RRX */
- shamt = CFLAG ;
- ASSIGNC(base & 1) ;
- return((base >> 1) | (shamt << 31)) ;
- }
- else {
- ASSIGNC((base >> (shamt - 1)) & 1) ;
- return((base << (32-shamt)) | (base >> shamt)) ;
- }
- }
+ if (base == 15)
+ /* Now forbidden, but ... */
+ base = ECC | ER15INT | R15PC | EMODE;
+ else
+#endif
+ base = state->Reg[base];
+
+ shamt = BITS (7, 11);
+ switch ((int) BITS (5, 6))
+ {
+ case LSL:
+ return (base << shamt);
+ case LSR:
+ if (shamt == 0)
+ return (0);
+ else
+ return (base >> shamt);
+ case ASR:
+ if (shamt == 0)
+ return ((ARMword) ((ARMsword) base >> 31L));
+ else
+ return ((ARMword) ((ARMsword) base >> (int) shamt));
+ case ROR:
+ if (shamt == 0)
+ /* It's an RRX. */
+ return ((base >> 1) | (CFLAG << 31));
+ else
+ return ((base << (32 - shamt)) | (base >> shamt));
+ default:
+ break;
}
- return(0) ; /* just to shut up lint */
- }
+ return 0;
+}
-/***************************************************************************\
-* This routine handles writes to register 15 when the S bit is not set. *
-\***************************************************************************/
+/* This routine evaluates the ARM7T halfword and signed transfer RHS's. */
-static void WriteR15(ARMul_State *state, ARMword src)
+static ARMword
+GetLS7RHS (ARMul_State * state, ARMword instr)
{
- /* The ARM documentation implies (but doe snot state) that the bottom bit of the PC is never set */
-#ifdef MODE32
- state->Reg[15] = src & PCBITS & ~ 0x1 ;
-#else
- state->Reg[15] = (src & R15PCBITS & ~ 0x1) | ECC | ER15INT | EMODE ;
- ARMul_R15Altered(state) ;
+ if (BIT (22) == 0)
+ {
+ /* Register. */
+#ifndef MODE32
+ if (RHSReg == 15)
+ /* Now forbidden, but ... */
+ return ECC | ER15INT | R15PC | EMODE;
#endif
- FLUSHPIPE ;
- }
+ return state->Reg[RHSReg];
+ }
-/***************************************************************************\
-* This routine handles writes to register 15 when the S bit is set. *
-\***************************************************************************/
+ /* Immediate. */
+ return BITS (0, 3) | (BITS (8, 11) << 4);
+}
+
+/* This function does the work of loading a word for a LDR instruction. */
-static void WriteSR15(ARMul_State *state, ARMword src)
+static unsigned
+LoadWord (ARMul_State * state, ARMword instr, ARMword address)
{
-#ifdef MODE32
- state->Reg[15] = src & PCBITS ;
- if (state->Bank > 0) {
- state->Cpsr = state->Spsr[state->Bank] ;
- ARMul_CPSRAltered(state) ;
- }
-#else
- if (state->Bank == USERBANK)
- state->Reg[15] = (src & (CCBITS | R15PCBITS)) | ER15INT | EMODE ;
- else
- state->Reg[15] = src ;
- ARMul_R15Altered(state) ;
-#endif
- FLUSHPIPE ;
- }
+ ARMword dest;
-/***************************************************************************\
-* This routine evaluates most Load and Store register RHS's. It is *
-* intended to be called from the macro LSRegRHS, which filters the *
-* common case of an unshifted register with in line code *
-\***************************************************************************/
+ BUSUSEDINCPCS;
+#ifndef MODE32
+ if (ADDREXCEPT (address))
+ INTERNALABORT (address);
+#endif
-static ARMword GetLSRegRHS(ARMul_State *state, ARMword instr)
-{ARMword shamt, base ;
+ dest = ARMul_LoadWordN (state, address);
- base = RHSReg ;
-#ifndef MODE32
- if (base == 15)
- base = ECC | ER15INT | R15PC | EMODE ; /* Now forbidden, but .... */
- else
-#endif
- base = state->Reg[base] ;
-
- shamt = BITS(7,11) ;
- switch ((int)BITS(5,6)) {
- case LSL : return(base << shamt) ;
- case LSR : if (shamt == 0)
- return(0) ;
- else
- return(base >> shamt) ;
- case ASR : if (shamt == 0)
- return((ARMword)((long int)base >> 31L)) ;
- else
- return((ARMword)((long int)base >> (int)shamt)) ;
- case ROR : if (shamt==0) /* its an RRX */
- return((base >> 1) | (CFLAG << 31)) ;
- else
- return((base << (32-shamt)) | (base >> shamt)) ;
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return state->lateabtSig;
}
- return(0) ; /* just to shut up lint */
- }
+ if (address & 3)
+ dest = ARMul_Align (state, address, dest);
+ WRITEDESTB (dest);
+ ARMul_Icycles (state, 1, 0L);
+
+ return (DESTReg != LHSReg);
+}
-/***************************************************************************\
-* This routine evaluates the ARM7T halfword and signed transfer RHS's. *
-\***************************************************************************/
+#ifdef MODET
+/* This function does the work of loading a halfword. */
-static ARMword GetLS7RHS(ARMul_State *state, ARMword instr)
+static unsigned
+LoadHalfWord (ARMul_State * state, ARMword instr, ARMword address,
+ int signextend)
{
- if (BIT(22) == 0) { /* register */
+ ARMword dest;
+
+ BUSUSEDINCPCS;
#ifndef MODE32
- if (RHSReg == 15)
- return ECC | ER15INT | R15PC | EMODE ; /* Now forbidden, but ... */
+ if (ADDREXCEPT (address))
+ INTERNALABORT (address);
#endif
- return state->Reg[RHSReg] ;
+ dest = ARMul_LoadHalfWord (state, address);
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return state->lateabtSig;
}
+ UNDEF_LSRBPC;
+ if (signextend)
+ if (dest & 1 << (16 - 1))
+ dest = (dest & ((1 << 16) - 1)) - (1 << 16);
+
+ WRITEDEST (dest);
+ ARMul_Icycles (state, 1, 0L);
+ return (DESTReg != LHSReg);
+}
- /* else immediate */
- return BITS(0,3) | (BITS(8,11) << 4) ;
- }
+#endif /* MODET */
-/***************************************************************************\
-* This function does the work of loading a word for a LDR instruction. *
-\***************************************************************************/
+/* This function does the work of loading a byte for a LDRB instruction. */
-static unsigned LoadWord(ARMul_State *state, ARMword instr, ARMword address)
+static unsigned
+LoadByte (ARMul_State * state, ARMword instr, ARMword address, int signextend)
{
- ARMword dest ;
+ ARMword dest;
- BUSUSEDINCPCS ;
+ BUSUSEDINCPCS;
#ifndef MODE32
- if (ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- }
+ if (ADDREXCEPT (address))
+ INTERNALABORT (address);
#endif
- dest = ARMul_LoadWordN(state,address) ;
- if (state->Aborted) {
- TAKEABORT ;
- return(state->lateabtSig) ;
+ dest = ARMul_LoadByte (state, address);
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return state->lateabtSig;
}
- if (address & 3)
- dest = ARMul_Align(state,address,dest) ;
- WRITEDEST(dest) ;
- ARMul_Icycles(state,1,0L) ;
+ UNDEF_LSRBPC;
+ if (signextend)
+ if (dest & 1 << (8 - 1))
+ dest = (dest & ((1 << 8) - 1)) - (1 << 8);
+
+ WRITEDEST (dest);
+ ARMul_Icycles (state, 1, 0L);
- return(DESTReg != LHSReg) ;
+ return (DESTReg != LHSReg);
}
-#ifdef MODET
-/***************************************************************************\
-* This function does the work of loading a halfword. *
-\***************************************************************************/
+/* This function does the work of loading two words for a LDRD instruction. */
-static unsigned LoadHalfWord(ARMul_State *state, ARMword instr, ARMword address,int signextend)
+static void
+Handle_Load_Double (ARMul_State * state, ARMword instr)
{
- ARMword dest ;
+ ARMword dest_reg;
+ ARMword addr_reg;
+ ARMword write_back = BIT (21);
+ ARMword immediate = BIT (22);
+ ARMword add_to_base = BIT (23);
+ ARMword pre_indexed = BIT (24);
+ ARMword offset;
+ ARMword addr;
+ ARMword sum;
+ ARMword base;
+ ARMword value1;
+ ARMword value2;
+
+ BUSUSEDINCPCS;
+
+ /* If the writeback bit is set, the pre-index bit must be clear. */
+ if (write_back && ! pre_indexed)
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
+ }
- BUSUSEDINCPCS ;
-#ifndef MODE32
- if (ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
+ /* Extract the base address register. */
+ addr_reg = LHSReg;
+
+ /* Extract the destination register and check it. */
+ dest_reg = DESTReg;
+
+ /* Destination register must be even. */
+ if ((dest_reg & 1)
+ /* Destination register cannot be LR. */
+ || (dest_reg == 14))
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
}
+
+ /* Compute the base address. */
+ base = state->Reg[addr_reg];
+
+ /* Compute the offset. */
+ offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state->Reg[RHSReg];
+
+ /* Compute the sum of the two. */
+ if (add_to_base)
+ sum = base + offset;
+ else
+ sum = base - offset;
+
+ /* If this is a pre-indexed mode use the sum. */
+ if (pre_indexed)
+ addr = sum;
+ else
+ addr = base;
+
+ if (state->is_v6 && (addr & 0x3) == 0)
+ /* Word alignment is enough for v6. */
+ ;
+ /* The address must be aligned on a 8 byte boundary. */
+ else if (addr & 0x7)
+ {
+#ifdef ABORTS
+ ARMul_DATAABORT (addr);
+#else
+ ARMul_UndefInstr (state, instr);
#endif
- dest = ARMul_LoadHalfWord(state,address) ;
- if (state->Aborted) {
- TAKEABORT ;
- return(state->lateabtSig) ;
+ return;
}
- UNDEF_LSRBPC ;
- if (signextend)
- {
- if (dest & 1 << (16 - 1))
- dest = (dest & ((1 << 16) - 1)) - (1 << 16) ;
- }
- WRITEDEST(dest) ;
- ARMul_Icycles(state,1,0L) ;
- return(DESTReg != LHSReg) ;
+
+ /* For pre indexed or post indexed addressing modes,
+ check that the destination registers do not overlap
+ the address registers. */
+ if ((! pre_indexed || write_back)
+ && ( addr_reg == dest_reg
+ || addr_reg == dest_reg + 1))
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
+ }
+
+ /* Load the words. */
+ value1 = ARMul_LoadWordN (state, addr);
+ value2 = ARMul_LoadWordN (state, addr + 4);
+
+ /* Check for data aborts. */
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return;
+ }
+
+ ARMul_Icycles (state, 2, 0L);
+
+ /* Store the values. */
+ state->Reg[dest_reg] = value1;
+ state->Reg[dest_reg + 1] = value2;
+
+ /* Do the post addressing and writeback. */
+ if (! pre_indexed)
+ addr = sum;
+
+ if (! pre_indexed || write_back)
+ state->Reg[addr_reg] = addr;
}
-#endif /* MODET */
-/***************************************************************************\
-* This function does the work of loading a byte for a LDRB instruction. *
-\***************************************************************************/
+/* This function does the work of storing two words for a STRD instruction. */
-static unsigned LoadByte(ARMul_State *state, ARMword instr, ARMword address,int signextend)
+static void
+Handle_Store_Double (ARMul_State * state, ARMword instr)
{
- ARMword dest ;
+ ARMword src_reg;
+ ARMword addr_reg;
+ ARMword write_back = BIT (21);
+ ARMword immediate = BIT (22);
+ ARMword add_to_base = BIT (23);
+ ARMword pre_indexed = BIT (24);
+ ARMword offset;
+ ARMword addr;
+ ARMword sum;
+ ARMword base;
+
+ BUSUSEDINCPCS;
+
+ /* If the writeback bit is set, the pre-index bit must be clear. */
+ if (write_back && ! pre_indexed)
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
+ }
- BUSUSEDINCPCS ;
-#ifndef MODE32
- if (ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
+ /* Extract the base address register. */
+ addr_reg = LHSReg;
+
+ /* Base register cannot be PC. */
+ if (addr_reg == 15)
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
+ }
+
+ /* Extract the source register. */
+ src_reg = DESTReg;
+
+ /* Source register must be even. */
+ if (src_reg & 1)
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
}
+
+ /* Compute the base address. */
+ base = state->Reg[addr_reg];
+
+ /* Compute the offset. */
+ offset = immediate ? ((BITS (8, 11) << 4) | BITS (0, 3)) : state->Reg[RHSReg];
+
+ /* Compute the sum of the two. */
+ if (add_to_base)
+ sum = base + offset;
+ else
+ sum = base - offset;
+
+ /* If this is a pre-indexed mode use the sum. */
+ if (pre_indexed)
+ addr = sum;
+ else
+ addr = base;
+
+ /* The address must be aligned on a 8 byte boundary. */
+ if (state->is_v6 && (addr & 0x3) == 0)
+ /* Word alignment is enough for v6. */
+ ;
+ else if (addr & 0x7)
+ {
+#ifdef ABORTS
+ ARMul_DATAABORT (addr);
+#else
+ ARMul_UndefInstr (state, instr);
#endif
- dest = ARMul_LoadByte(state,address) ;
- if (state->Aborted) {
- TAKEABORT ;
- return(state->lateabtSig) ;
+ return;
+ }
+
+ /* For pre indexed or post indexed addressing modes,
+ check that the destination registers do not overlap
+ the address registers. */
+ if ((! pre_indexed || write_back)
+ && ( addr_reg == src_reg
+ || addr_reg == src_reg + 1))
+ {
+ ARMul_UndefInstr (state, instr);
+ return;
+ }
+
+ /* Load the words. */
+ ARMul_StoreWordN (state, addr, state->Reg[src_reg]);
+ ARMul_StoreWordN (state, addr + 4, state->Reg[src_reg + 1]);
+
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return;
}
- UNDEF_LSRBPC ;
- if (signextend)
- {
- if (dest & 1 << (8 - 1))
- dest = (dest & ((1 << 8) - 1)) - (1 << 8) ;
- }
- WRITEDEST(dest) ;
- ARMul_Icycles(state,1,0L) ;
- return(DESTReg != LHSReg) ;
+
+ /* Do the post addressing and writeback. */
+ if (! pre_indexed)
+ addr = sum;
+
+ if (! pre_indexed || write_back)
+ state->Reg[addr_reg] = addr;
}
-/***************************************************************************\
-* This function does the work of storing a word from a STR instruction. *
-\***************************************************************************/
+/* This function does the work of storing a word from a STR instruction. */
-static unsigned StoreWord(ARMul_State *state, ARMword instr, ARMword address)
-{BUSUSEDINCPCN ;
+static unsigned
+StoreWord (ARMul_State * state, ARMword instr, ARMword address)
+{
+ BUSUSEDINCPCN;
#ifndef MODE32
- if (DESTReg == 15)
- state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
+ if (DESTReg == 15)
+ state->Reg[15] = ECC | ER15INT | R15PC | EMODE;
#endif
#ifdef MODE32
- ARMul_StoreWordN(state,address,DEST) ;
+ ARMul_StoreWordN (state, address, DEST);
#else
- if (VECTORACCESS(address) || ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- (void)ARMul_LoadWordN(state,address) ;
+ if (VECTORACCESS (address) || ADDREXCEPT (address))
+ {
+ INTERNALABORT (address);
+ (void) ARMul_LoadWordN (state, address);
}
- else
- ARMul_StoreWordN(state,address,DEST) ;
+ else
+ ARMul_StoreWordN (state, address, DEST);
#endif
- if (state->Aborted) {
- TAKEABORT ;
- return(state->lateabtSig) ;
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return state->lateabtSig;
}
- return(TRUE) ;
+ return TRUE;
}
#ifdef MODET
-/***************************************************************************\
-* This function does the work of storing a byte for a STRH instruction. *
-\***************************************************************************/
+/* This function does the work of storing a byte for a STRH instruction. */
-static unsigned StoreHalfWord(ARMul_State *state, ARMword instr, ARMword address)
-{BUSUSEDINCPCN ;
+static unsigned
+StoreHalfWord (ARMul_State * state, ARMword instr, ARMword address)
+{
+ BUSUSEDINCPCN;
#ifndef MODE32
- if (DESTReg == 15)
- state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
+ if (DESTReg == 15)
+ state->Reg[15] = ECC | ER15INT | R15PC | EMODE;
#endif
#ifdef MODE32
- ARMul_StoreHalfWord(state,address,DEST);
+ ARMul_StoreHalfWord (state, address, DEST);
#else
- if (VECTORACCESS(address) || ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- (void)ARMul_LoadHalfWord(state,address) ;
+ if (VECTORACCESS (address) || ADDREXCEPT (address))
+ {
+ INTERNALABORT (address);
+ (void) ARMul_LoadHalfWord (state, address);
}
- else
- ARMul_StoreHalfWord(state,address,DEST) ;
+ else
+ ARMul_StoreHalfWord (state, address, DEST);
#endif
- if (state->Aborted) {
- TAKEABORT ;
- return(state->lateabtSig) ;
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return state->lateabtSig;
}
-
- return(TRUE) ;
+ return TRUE;
}
+
#endif /* MODET */
-/***************************************************************************\
-* This function does the work of storing a byte for a STRB instruction. *
-\***************************************************************************/
+/* This function does the work of storing a byte for a STRB instruction. */
-static unsigned StoreByte(ARMul_State *state, ARMword instr, ARMword address)
-{BUSUSEDINCPCN ;
+static unsigned
+StoreByte (ARMul_State * state, ARMword instr, ARMword address)
+{
+ BUSUSEDINCPCN;
#ifndef MODE32
- if (DESTReg == 15)
- state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
+ if (DESTReg == 15)
+ state->Reg[15] = ECC | ER15INT | R15PC | EMODE;
#endif
#ifdef MODE32
- ARMul_StoreByte(state,address,DEST) ;
+ ARMul_StoreByte (state, address, DEST);
#else
- if (VECTORACCESS(address) || ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- (void)ARMul_LoadByte(state,address) ;
+ if (VECTORACCESS (address) || ADDREXCEPT (address))
+ {
+ INTERNALABORT (address);
+ (void) ARMul_LoadByte (state, address);
}
- else
- ARMul_StoreByte(state,address,DEST) ;
+ else
+ ARMul_StoreByte (state, address, DEST);
#endif
- if (state->Aborted) {
- TAKEABORT ;
- return(state->lateabtSig) ;
+ if (state->Aborted)
+ {
+ TAKEABORT;
+ return state->lateabtSig;
}
- UNDEF_LSRBPC ;
- return(TRUE) ;
+ UNDEF_LSRBPC;
+ return TRUE;
}
-/***************************************************************************\
-* This function does the work of loading the registers listed in an LDM *
-* instruction, when the S bit is clear. The code here is always increment *
-* after, it's up to the caller to get the input address correct and to *
-* handle base register modification. *
-\***************************************************************************/
-
-static void LoadMult(ARMul_State *state, ARMword instr,
- ARMword address, ARMword WBBase)
-{ARMword dest, temp ;
-
- UNDEF_LSMNoRegs ;
- UNDEF_LSMPCBase ;
- UNDEF_LSMBaseInListWb ;
- BUSUSEDINCPCS ;
+/* This function does the work of loading the registers listed in an LDM
+ instruction, when the S bit is clear. The code here is always increment
+ after, it's up to the caller to get the input address correct and to
+ handle base register modification. */
+
+static void
+LoadMult (ARMul_State * state, ARMword instr, ARMword address, ARMword WBBase)
+{
+ ARMword dest, temp;
+
+ UNDEF_LSMNoRegs;
+ UNDEF_LSMPCBase;
+ UNDEF_LSMBaseInListWb;
+ BUSUSEDINCPCS;
#ifndef MODE32
- if (ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- }
-#endif
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
-
- for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
- dest = ARMul_LoadWordN(state,address) ;
- if (!state->abortSig && !state->Aborted)
- state->Reg[temp++] = dest ;
- else
- if (!state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
-
- for (; temp < 16 ; temp++) /* S cycles from here on */
- if (BIT(temp)) { /* load this register */
- address += 4 ;
- dest = ARMul_LoadWordS(state,address) ;
- if (!state->abortSig && !state->Aborted)
- state->Reg[temp] = dest ;
- else
- if (!state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
- }
-
- if (BIT(15)) { /* PC is in the reg list */
-#ifdef MODE32
- state->Reg[15] = PC ;
+ if (ADDREXCEPT (address))
+ INTERNALABORT (address);
#endif
- FLUSHPIPE ;
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+
+ /* N cycle first. */
+ for (temp = 0; !BIT (temp); temp++)
+ ;
+
+ dest = ARMul_LoadWordN (state, address);
+
+ if (!state->abortSig && !state->Aborted)
+ state->Reg[temp++] = dest;
+ else if (!state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
}
- ARMul_Icycles(state,1,0L) ; /* to write back the final register */
+ /* S cycles from here on. */
+ for (; temp < 16; temp ++)
+ if (BIT (temp))
+ {
+ /* Load this register. */
+ address += 4;
+ dest = ARMul_LoadWordS (state, address);
+
+ if (!state->abortSig && !state->Aborted)
+ state->Reg[temp] = dest;
+ else if (!state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
+ }
+ }
+
+ if (BIT (15) && !state->Aborted)
+ /* PC is in the reg list. */
+ WriteR15Load (state, PC);
- if (state->Aborted) {
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
- TAKEABORT ;
+ /* To write back the final register. */
+ ARMul_Icycles (state, 1, 0L);
+
+ if (state->Aborted)
+ {
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+ TAKEABORT;
}
- }
-
-/***************************************************************************\
-* This function does the work of loading the registers listed in an LDM *
-* instruction, when the S bit is set. The code here is always increment *
-* after, it's up to the caller to get the input address correct and to *
-* handle base register modification. *
-\***************************************************************************/
-
-static void LoadSMult(ARMul_State *state, ARMword instr,
- ARMword address, ARMword WBBase)
-{ARMword dest, temp ;
-
- UNDEF_LSMNoRegs ;
- UNDEF_LSMPCBase ;
- UNDEF_LSMBaseInListWb ;
- BUSUSEDINCPCS ;
+}
+
+/* This function does the work of loading the registers listed in an LDM
+ instruction, when the S bit is set. The code here is always increment
+ after, it's up to the caller to get the input address correct and to
+ handle base register modification. */
+
+static void
+LoadSMult (ARMul_State * state,
+ ARMword instr,
+ ARMword address,
+ ARMword WBBase)
+{
+ ARMword dest, temp;
+
+ UNDEF_LSMNoRegs;
+ UNDEF_LSMPCBase;
+ UNDEF_LSMBaseInListWb;
+
+ BUSUSEDINCPCS;
+
#ifndef MODE32
- if (ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- }
+ if (ADDREXCEPT (address))
+ INTERNALABORT (address);
#endif
- if (!BIT(15) && state->Bank != USERBANK) {
- (void)ARMul_SwitchMode(state,state->Mode,USER26MODE) ; /* temporary reg bank switch */
- UNDEF_LSMUserBankWb ;
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+
+ if (!BIT (15) && state->Bank != USERBANK)
+ {
+ /* Temporary reg bank switch. */
+ (void) ARMul_SwitchMode (state, state->Mode, USER26MODE);
+ UNDEF_LSMUserBankWb;
+ }
+
+ /* N cycle first. */
+ for (temp = 0; !BIT (temp); temp ++)
+ ;
+
+ dest = ARMul_LoadWordN (state, address);
+
+ if (!state->abortSig)
+ state->Reg[temp++] = dest;
+ else if (!state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
}
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
-
- for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
- dest = ARMul_LoadWordN(state,address) ;
- if (!state->abortSig)
- state->Reg[temp++] = dest ;
- else
- if (!state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
-
- for (; temp < 16 ; temp++) /* S cycles from here on */
- if (BIT(temp)) { /* load this register */
- address += 4 ;
- dest = ARMul_LoadWordS(state,address) ;
- if (!state->abortSig || state->Aborted)
- state->Reg[temp] = dest ;
- else
- if (!state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
- }
-
- if (BIT(15)) { /* PC is in the reg list */
+ /* S cycles from here on. */
+ for (; temp < 16; temp++)
+ if (BIT (temp))
+ {
+ /* Load this register. */
+ address += 4;
+ dest = ARMul_LoadWordS (state, address);
+
+ if (!state->abortSig && !state->Aborted)
+ state->Reg[temp] = dest;
+ else if (!state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
+ }
+ }
+
+ if (BIT (15) && !state->Aborted)
+ {
+ /* PC is in the reg list. */
#ifdef MODE32
- if (state->Mode != USER26MODE && state->Mode != USER32MODE) {
- state->Cpsr = GETSPSR(state->Bank) ;
- ARMul_CPSRAltered(state) ;
- }
- state->Reg[15] = PC ;
+ if (state->Mode != USER26MODE && state->Mode != USER32MODE)
+ {
+ state->Cpsr = GETSPSR (state->Bank);
+ ARMul_CPSRAltered (state);
+ }
+
+ WriteR15 (state, PC);
#else
- if (state->Mode == USER26MODE || state->Mode == USER32MODE) { /* protect bits in user mode */
- ASSIGNN((state->Reg[15] & NBIT) != 0) ;
- ASSIGNZ((state->Reg[15] & ZBIT) != 0) ;
- ASSIGNC((state->Reg[15] & CBIT) != 0) ;
- ASSIGNV((state->Reg[15] & VBIT) != 0) ;
- }
- else
- ARMul_R15Altered(state) ;
-#endif
- FLUSHPIPE ;
+ if (state->Mode == USER26MODE || state->Mode == USER32MODE)
+ {
+ /* Protect bits in user mode. */
+ ASSIGNN ((state->Reg[15] & NBIT) != 0);
+ ASSIGNZ ((state->Reg[15] & ZBIT) != 0);
+ ASSIGNC ((state->Reg[15] & CBIT) != 0);
+ ASSIGNV ((state->Reg[15] & VBIT) != 0);
+ }
+ else
+ ARMul_R15Altered (state);
+
+ FLUSHPIPE;
+#endif
}
- if (!BIT(15) && state->Mode != USER26MODE && state->Mode != USER32MODE)
- (void)ARMul_SwitchMode(state,USER26MODE,state->Mode) ; /* restore the correct bank */
+ if (!BIT (15) && state->Mode != USER26MODE && state->Mode != USER32MODE)
+ /* Restore the correct bank. */
+ (void) ARMul_SwitchMode (state, USER26MODE, state->Mode);
- ARMul_Icycles(state,1,0L) ; /* to write back the final register */
+ /* To write back the final register. */
+ ARMul_Icycles (state, 1, 0L);
- if (state->Aborted) {
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
- TAKEABORT ;
- }
+ if (state->Aborted)
+ {
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+ TAKEABORT;
+ }
}
-/***************************************************************************\
-* This function does the work of storing the registers listed in an STM *
-* instruction, when the S bit is clear. The code here is always increment *
-* after, it's up to the caller to get the input address correct and to *
-* handle base register modification. *
-\***************************************************************************/
+/* This function does the work of storing the registers listed in an STM
+ instruction, when the S bit is clear. The code here is always increment
+ after, it's up to the caller to get the input address correct and to
+ handle base register modification. */
+
+static void
+StoreMult (ARMul_State * state,
+ ARMword instr,
+ ARMword address,
+ ARMword WBBase)
+{
+ ARMword temp;
-static void StoreMult(ARMul_State *state, ARMword instr,
- ARMword address, ARMword WBBase)
-{ARMword temp ;
+ UNDEF_LSMNoRegs;
+ UNDEF_LSMPCBase;
+ UNDEF_LSMBaseInListWb;
- UNDEF_LSMNoRegs ;
- UNDEF_LSMPCBase ;
- UNDEF_LSMBaseInListWb ;
- if (!TFLAG) {
- BUSUSEDINCPCN ; /* N-cycle, increment the PC and update the NextInstr state */
- }
+ if (!TFLAG)
+ /* N-cycle, increment the PC and update the NextInstr state. */
+ BUSUSEDINCPCN;
#ifndef MODE32
- if (VECTORACCESS(address) || ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
- }
- if (BIT(15))
- PATCHR15 ;
+ if (VECTORACCESS (address) || ADDREXCEPT (address))
+ INTERNALABORT (address);
+
+ if (BIT (15))
+ PATCHR15;
#endif
- for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
+ /* N cycle first. */
+ for (temp = 0; !BIT (temp); temp ++)
+ ;
+
#ifdef MODE32
- ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
+ ARMul_StoreWordN (state, address, state->Reg[temp++]);
#else
- if (state->Aborted) {
- (void)ARMul_LoadWordN(state,address) ;
- for ( ; temp < 16 ; temp++) /* Fake the Stores as Loads */
- if (BIT(temp)) { /* save this register */
- address += 4 ;
- (void)ARMul_LoadWordS(state,address) ;
- }
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
- TAKEABORT ;
- return ;
+ if (state->Aborted)
+ {
+ (void) ARMul_LoadWordN (state, address);
+
+ /* Fake the Stores as Loads. */
+ for (; temp < 16; temp++)
+ if (BIT (temp))
+ {
+ /* Save this register. */
+ address += 4;
+ (void) ARMul_LoadWordS (state, address);
+ }
+
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+ TAKEABORT;
+ return;
}
- else
- ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
-#endif
- if (state->abortSig && !state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
-
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
-
- for ( ; temp < 16 ; temp++) /* S cycles from here on */
- if (BIT(temp)) { /* save this register */
- address += 4 ;
- ARMul_StoreWordS(state,address,state->Reg[temp]) ;
- if (state->abortSig && !state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
- }
- if (state->Aborted) {
- TAKEABORT ;
- }
- }
-
-/***************************************************************************\
-* This function does the work of storing the registers listed in an STM *
-* instruction when the S bit is set. The code here is always increment *
-* after, it's up to the caller to get the input address correct and to *
-* handle base register modification. *
-\***************************************************************************/
-
-static void StoreSMult(ARMul_State *state, ARMword instr,
- ARMword address, ARMword WBBase)
-{ARMword temp ;
-
- UNDEF_LSMNoRegs ;
- UNDEF_LSMPCBase ;
- UNDEF_LSMBaseInListWb ;
- BUSUSEDINCPCN ;
-#ifndef MODE32
- if (VECTORACCESS(address) || ADDREXCEPT(address)) {
- INTERNALABORT(address) ;
+ else
+ ARMul_StoreWordN (state, address, state->Reg[temp++]);
+#endif
+
+ if (state->abortSig && !state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
}
- if (BIT(15))
- PATCHR15 ;
+
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+
+ /* S cycles from here on. */
+ for (; temp < 16; temp ++)
+ if (BIT (temp))
+ {
+ /* Save this register. */
+ address += 4;
+
+ ARMul_StoreWordS (state, address, state->Reg[temp]);
+
+ if (state->abortSig && !state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
+ }
+ }
+
+ if (state->Aborted)
+ TAKEABORT;
+}
+
+/* This function does the work of storing the registers listed in an STM
+ instruction when the S bit is set. The code here is always increment
+ after, it's up to the caller to get the input address correct and to
+ handle base register modification. */
+
+static void
+StoreSMult (ARMul_State * state,
+ ARMword instr,
+ ARMword address,
+ ARMword WBBase)
+{
+ ARMword temp;
+
+ UNDEF_LSMNoRegs;
+ UNDEF_LSMPCBase;
+ UNDEF_LSMBaseInListWb;
+
+ BUSUSEDINCPCN;
+
+#ifndef MODE32
+ if (VECTORACCESS (address) || ADDREXCEPT (address))
+ INTERNALABORT (address);
+
+ if (BIT (15))
+ PATCHR15;
#endif
- if (state->Bank != USERBANK) {
- (void)ARMul_SwitchMode(state,state->Mode,USER26MODE) ; /* Force User Bank */
- UNDEF_LSMUserBankWb ;
+ if (state->Bank != USERBANK)
+ {
+ /* Force User Bank. */
+ (void) ARMul_SwitchMode (state, state->Mode, USER26MODE);
+ UNDEF_LSMUserBankWb;
}
- for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
+ for (temp = 0; !BIT (temp); temp++)
+ ; /* N cycle first. */
+
#ifdef MODE32
- ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
+ ARMul_StoreWordN (state, address, state->Reg[temp++]);
#else
- if (state->Aborted) {
- (void)ARMul_LoadWordN(state,address) ;
- for ( ; temp < 16 ; temp++) /* Fake the Stores as Loads */
- if (BIT(temp)) { /* save this register */
- address += 4 ;
- (void)ARMul_LoadWordS(state,address) ;
- }
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
- TAKEABORT ;
- return ;
+ if (state->Aborted)
+ {
+ (void) ARMul_LoadWordN (state, address);
+
+ for (; temp < 16; temp++)
+ /* Fake the Stores as Loads. */
+ if (BIT (temp))
+ {
+ /* Save this register. */
+ address += 4;
+
+ (void) ARMul_LoadWordS (state, address);
+ }
+
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+
+ TAKEABORT;
+ return;
}
- else
- ARMul_StoreWordN(state,address,state->Reg[temp++]) ;
+ else
+ ARMul_StoreWordN (state, address, state->Reg[temp++]);
#endif
- if (state->abortSig && !state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
- if (BIT(21) && LHSReg != 15)
- LSBase = WBBase ;
+ if (state->abortSig && !state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
+ }
+
+ /* S cycles from here on. */
+ for (; temp < 16; temp++)
+ if (BIT (temp))
+ {
+ /* Save this register. */
+ address += 4;
+
+ ARMul_StoreWordS (state, address, state->Reg[temp]);
- for (; temp < 16 ; temp++) /* S cycles from here on */
- if (BIT(temp)) { /* save this register */
- address += 4 ;
- ARMul_StoreWordS(state,address,state->Reg[temp]) ;
- if (state->abortSig && !state->Aborted)
- state->Aborted = ARMul_DataAbortV ;
- }
+ if (state->abortSig && !state->Aborted)
+ {
+ XScale_set_fsr_far (state, ARMul_CP15_R5_ST_ALIGN, address);
+ state->Aborted = ARMul_DataAbortV;
+ }
+ }
- if (state->Mode != USER26MODE && state->Mode != USER32MODE)
- (void)ARMul_SwitchMode(state,USER26MODE,state->Mode) ; /* restore the correct bank */
+ if (state->Mode != USER26MODE && state->Mode != USER32MODE)
+ /* Restore the correct bank. */
+ (void) ARMul_SwitchMode (state, USER26MODE, state->Mode);
- if (state->Aborted) {
- TAKEABORT ;
- }
+ if (BIT (21) && LHSReg != 15)
+ LSBase = WBBase;
+
+ if (state->Aborted)
+ TAKEABORT;
}
-/***************************************************************************\
-* This function does the work of adding two 32bit values together, and *
-* calculating if a carry has occurred. *
-\***************************************************************************/
+/* This function does the work of adding two 32bit values
+ together, and calculating if a carry has occurred. */
-static ARMword Add32(ARMword a1,ARMword a2,int *carry)
+static ARMword
+Add32 (ARMword a1, ARMword a2, int *carry)
{
ARMword result = (a1 + a2);
- unsigned int uresult = (unsigned int)result;
- unsigned int ua1 = (unsigned int)a1;
+ unsigned int uresult = (unsigned int) result;
+ unsigned int ua1 = (unsigned int) a1;
/* If (result == RdLo) and (state->Reg[nRdLo] == 0),
- or (result > RdLo) then we have no carry: */
+ or (result > RdLo) then we have no carry. */
if ((uresult == ua1) ? (a2 != 0) : (uresult < ua1))
- *carry = 1;
+ *carry = 1;
else
- *carry = 0;
+ *carry = 0;
- return(result);
+ return result;
}
-/***************************************************************************\
-* This function does the work of multiplying two 32bit values to give a *
-* 64bit result. *
-\***************************************************************************/
+/* This function does the work of multiplying
+ two 32bit values to give a 64bit result. */
-static unsigned Multiply64(ARMul_State *state,ARMword instr,int msigned,int scc)
+static unsigned
+Multiply64 (ARMul_State * state, ARMword instr, int msigned, int scc)
{
- int nRdHi, nRdLo, nRs, nRm; /* operand register numbers */
- ARMword RdHi, RdLo, Rm;
- int scount; /* cycle count */
-
- nRdHi = BITS(16,19);
- nRdLo = BITS(12,15);
- nRs = BITS(8,11);
- nRm = BITS(0,3);
-
- /* Needed to calculate the cycle count: */
+ /* Operand register numbers. */
+ int nRdHi, nRdLo, nRs, nRm;
+ ARMword RdHi = 0, RdLo = 0, Rm;
+ /* Cycle count. */
+ int scount;
+
+ nRdHi = BITS (16, 19);
+ nRdLo = BITS (12, 15);
+ nRs = BITS (8, 11);
+ nRm = BITS (0, 3);
+
+ /* Needed to calculate the cycle count. */
Rm = state->Reg[nRm];
- /* Check for illegal operand combinations first: */
+ /* Check for illegal operand combinations first. */
if ( nRdHi != 15
&& nRdLo != 15
&& nRs != 15
&& nRm != 15
- && nRdHi != nRdLo
- && nRdHi != nRm
- && nRdLo != nRm)
+ && nRdHi != nRdLo)
{
- ARMword lo, mid1, mid2, hi; /* intermediate results */
+ /* Intermediate results. */
+ ARMword lo, mid1, mid2, hi;
int carry;
- ARMword Rs = state->Reg[ nRs ];
+ ARMword Rs = state->Reg[nRs];
int sign = 0;
+#ifdef MODE32
+ if (state->is_v6)
+ ;
+ else
+#endif
+ /* BAD code can trigger this result. So only complain if debugging. */
+ if (state->Debug && (nRdHi == nRm || nRdLo == nRm))
+ fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS: %d %d %d\n",
+ nRdHi, nRdLo, nRm);
if (msigned)
{
/* Compute sign of result and adjust operands if necessary. */
-
sign = (Rm ^ Rs) & 0x80000000;
-
- if (((signed long)Rm) < 0)
+
+ if (((ARMsword) Rm) < 0)
Rm = -Rm;
-
- if (((signed long)Rs) < 0)
+
+ if (((ARMsword) Rs) < 0)
Rs = -Rs;
}
-
- /* We can split the 32x32 into four 16x16 operations. This ensures
- that we do not lose precision on 32bit only hosts: */
- lo = ((Rs & 0xFFFF) * (Rm & 0xFFFF));
+
+ /* We can split the 32x32 into four 16x16 operations. This
+ ensures that we do not lose precision on 32bit only hosts. */
+ lo = ((Rs & 0xFFFF) * (Rm & 0xFFFF));
mid1 = ((Rs & 0xFFFF) * ((Rm >> 16) & 0xFFFF));
mid2 = (((Rs >> 16) & 0xFFFF) * (Rm & 0xFFFF));
- hi = (((Rs >> 16) & 0xFFFF) * ((Rm >> 16) & 0xFFFF));
-
- /* We now need to add all of these results together, taking care
- to propogate the carries from the additions: */
- RdLo = Add32(lo,(mid1 << 16),&carry);
+ hi = (((Rs >> 16) & 0xFFFF) * ((Rm >> 16) & 0xFFFF));
+
+ /* We now need to add all of these results together, taking
+ care to propogate the carries from the additions. */
+ RdLo = Add32 (lo, (mid1 << 16), &carry);
RdHi = carry;
- RdLo = Add32(RdLo,(mid2 << 16),&carry);
- RdHi += (carry + ((mid1 >> 16) & 0xFFFF) + ((mid2 >> 16) & 0xFFFF) + hi);
+ RdLo = Add32 (RdLo, (mid2 << 16), &carry);
+ RdHi +=
+ (carry + ((mid1 >> 16) & 0xFFFF) + ((mid2 >> 16) & 0xFFFF) + hi);
if (sign)
{
/* Negate result if necessary. */
-
- RdLo = ~ RdLo;
- RdHi = ~ RdHi;
+ RdLo = ~RdLo;
+ RdHi = ~RdHi;
if (RdLo == 0xFFFFFFFF)
{
RdLo = 0;
else
RdLo += 1;
}
-
+
state->Reg[nRdLo] = RdLo;
state->Reg[nRdHi] = RdHi;
-
- } /* else undefined result */
- else fprintf (stderr, "MULTIPLY64 - INVALID ARGUMENTS\n");
-
- if (scc)
- {
- if ((RdHi == 0) && (RdLo == 0))
- ARMul_NegZero(state,RdHi); /* zero value */
- else
- ARMul_NegZero(state,scc); /* non-zero value */
}
-
+ else if (state->Debug)
+ fprintf (stderr, "sim: MULTIPLY64 - INVALID ARGUMENTS\n");
+
+ if (scc)
+ /* Ensure that both RdHi and RdLo are used to compute Z,
+ but don't let RdLo's sign bit make it to N. */
+ ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF));
+
/* The cycle count depends on whether the instruction is a signed or
- unsigned multiply, and what bits are clear in the multiplier: */
- if (msigned && (Rm & ((unsigned)1 << 31)))
- Rm = ~Rm; /* invert the bits to make the check against zero */
-
+ unsigned multiply, and what bits are clear in the multiplier. */
+ if (msigned && (Rm & ((unsigned) 1 << 31)))
+ /* Invert the bits to make the check against zero. */
+ Rm = ~Rm;
+
if ((Rm & 0xFFFFFF00) == 0)
- scount = 1 ;
+ scount = 1;
else if ((Rm & 0xFFFF0000) == 0)
- scount = 2 ;
+ scount = 2;
else if ((Rm & 0xFF000000) == 0)
- scount = 3 ;
+ scount = 3;
else
- scount = 4 ;
-
- return 2 + scount ;
+ scount = 4;
+
+ return 2 + scount;
}
-/***************************************************************************\
-* This function does the work of multiplying two 32bit values and adding *
-* a 64bit value to give a 64bit result. *
-\***************************************************************************/
+/* This function does the work of multiplying two 32bit
+ values and adding a 64bit value to give a 64bit result. */
-static unsigned MultiplyAdd64(ARMul_State *state,ARMword instr,int msigned,int scc)
+static unsigned
+MultiplyAdd64 (ARMul_State * state, ARMword instr, int msigned, int scc)
{
unsigned scount;
ARMword RdLo, RdHi;
int nRdHi, nRdLo;
int carry = 0;
- nRdHi = BITS(16,19);
- nRdLo = BITS(12,15);
+ nRdHi = BITS (16, 19);
+ nRdLo = BITS (12, 15);
- RdHi = state->Reg[nRdHi] ;
- RdLo = state->Reg[nRdLo] ;
+ RdHi = state->Reg[nRdHi];
+ RdLo = state->Reg[nRdLo];
- scount = Multiply64(state,instr,msigned,LDEFAULT);
+ scount = Multiply64 (state, instr, msigned, LDEFAULT);
- RdLo = Add32(RdLo,state->Reg[nRdLo],&carry);
+ RdLo = Add32 (RdLo, state->Reg[nRdLo], &carry);
RdHi = (RdHi + state->Reg[nRdHi]) + carry;
state->Reg[nRdLo] = RdLo;
state->Reg[nRdHi] = RdHi;
- if (scc) {
- if ((RdHi == 0) && (RdLo == 0))
- ARMul_NegZero(state,RdHi); /* zero value */
- else
- ARMul_NegZero(state,scc); /* non-zero value */
- }
+ if (scc)
+ /* Ensure that both RdHi and RdLo are used to compute Z,
+ but don't let RdLo's sign bit make it to N. */
+ ARMul_NegZero (state, RdHi | (RdLo >> 16) | (RdLo & 0xFFFF));
- return scount + 1; /* extra cycle for addition */
+ /* Extra cycle for addition. */
+ return scount + 1;
}