summaryrefslogtreecommitdiff
path: root/sim/arm/armemu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sim/arm/armemu.c')
-rw-r--r--sim/arm/armemu.c3454
1 files changed, 3454 insertions, 0 deletions
diff --git a/sim/arm/armemu.c b/sim/arm/armemu.c
new file mode 100644
index 00000000000..171f1c8c0c8
--- /dev/null
+++ b/sim/arm/armemu.c
@@ -0,0 +1,3454 @@
+/* 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
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "armdefs.h"
+#include "armemu.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 */
+
+/***************************************************************************\
+* short-hand macros for LDR/STR *
+\***************************************************************************/
+
+/* store post decrement writeback */
+#define SHDOWNWB() \
+ lhs = LHS ; \
+ if (StoreHalfWord(state, instr, lhs)) \
+ LSBase = lhs - GetLS7RHS(state, instr) ;
+
+/* store post increment writeback */
+#define SHUPWB() \
+ lhs = LHS ; \
+ if (StoreHalfWord(state, instr, lhs)) \
+ LSBase = lhs + GetLS7RHS(state, instr) ;
+
+/* store pre decrement */
+#define SHPREDOWN() \
+ (void)StoreHalfWord(state, instr, LHS - GetLS7RHS(state, instr)) ;
+
+/* store pre decrement writeback */
+#define SHPREDOWNWB() \
+ temp = LHS - GetLS7RHS(state, instr) ; \
+ if (StoreHalfWord(state, instr, temp)) \
+ LSBase = temp ;
+
+/* store pre increment */
+#define SHPREUP() \
+ (void)StoreHalfWord(state, instr, LHS + GetLS7RHS(state, instr)) ;
+
+/* store pre increment writeback */
+#define SHPREUPWB() \
+ temp = LHS + GetLS7RHS(state, instr) ; \
+ if (StoreHalfWord(state, instr, temp)) \
+ LSBase = temp ;
+
+/* load post decrement writeback */
+#define LHPOSTDOWN() \
+{ \
+ int done = 1 ; \
+ lhs = LHS ; \
+ switch (BITS(5,6)) { \
+ case 1: /* H */ \
+ if (LoadHalfWord(state,instr,lhs,LUNSIGNED)) \
+ LSBase = lhs - GetLS7RHS(state,instr) ; \
+ break ; \
+ case 2: /* SB */ \
+ if (LoadByte(state,instr,lhs,LSIGNED)) \
+ LSBase = lhs - GetLS7RHS(state,instr) ; \
+ break ; \
+ case 3: /* SH */ \
+ if (LoadHalfWord(state,instr,lhs,LSIGNED)) \
+ LSBase = lhs - GetLS7RHS(state,instr) ; \
+ break ; \
+ case 0: /* SWP handled elsewhere */ \
+ default: \
+ done = 0 ; \
+ break ; \
+ } \
+ if (done) \
+ break ; \
+}
+
+/* load post increment writeback */
+#define LHPOSTUP() \
+{ \
+ int done = 1 ; \
+ lhs = LHS ; \
+ switch (BITS(5,6)) { \
+ case 1: /* H */ \
+ if (LoadHalfWord(state,instr,lhs,LUNSIGNED)) \
+ LSBase = lhs + GetLS7RHS(state,instr) ; \
+ break ; \
+ case 2: /* SB */ \
+ if (LoadByte(state,instr,lhs,LSIGNED)) \
+ LSBase = lhs + GetLS7RHS(state,instr) ; \
+ break ; \
+ case 3: /* SH */ \
+ if (LoadHalfWord(state,instr,lhs,LSIGNED)) \
+ LSBase = lhs + GetLS7RHS(state,instr) ; \
+ 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 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 ; \
+}
+
+/***************************************************************************\
+* EMULATION of ARM6 *
+\***************************************************************************/
+
+/* The PC pipeline value depends on whether ARM or Thumb instructions
+ are being executed: */
+ARMword isize;
+
+#ifdef MODE32
+ARMword ARMul_Emulate32(register ARMul_State *state)
+{
+#else
+ARMword ARMul_Emulate26(register 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 ;
+ }
+
+ 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] ;
+#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] ;
+#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++ ;
+
+#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;
+ }
+ }
+#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 */
+#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 */
+#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 */
+#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 */
+#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 */
+#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 */
+#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 */
+#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 */
+#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 */
+#ifdef MODET
+ if (BITS(4,11) == 0xB) {
+ /* STRH register offset, no write-back, up, post indexed */
+ SHUPWB() ;
+ break ;
+ }
+#endif
+#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 */
+#ifdef MODET
+ 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,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,11) == 0xB) {
+ /* STRH register offset, write-back, up, post-indexed */
+ SHUPWB() ;
+ break ;
+ }
+#endif
+#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 */
+#ifdef MODET
+ if ((BITS(4,11) & 0xF9) == 0x9) {
+ /* LDR register offset, write-back, up, post indexed */
+ LHPOSTUP() ;
+ /* fall through to remaining instruction decoding */
+ }
+#endif
+#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 */
+#ifdef MODET
+ if (BITS(4,7) == 0xB) {
+ /* STRH immediate offset, no write-back, up post indexed */
+ SHUPWB() ;
+ break ;
+ }
+#endif
+#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 */
+#ifdef MODET
+ if ((BITS(4,7) & 0x9) == 0x9) {
+ /* LDR immediate offset, no write-back, up, post indexed */
+ LHPOSTUP() ;
+ }
+#endif
+#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 */
+#ifdef MODET
+ if (BITS(4,7) == 0xB) {
+ /* STRH immediate offset, write-back, up, post indexed */
+ SHUPWB() ;
+ break ;
+ }
+#endif
+#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 */
+#ifdef MODET
+ if ((BITS(4,7) & 0x9) == 0x9) {
+ /* LDR immediate offset, write-back, up, post indexed */
+ LHPOSTUP() ;
+ /* fall through to remaining instruction decoding */
+ }
+#endif
+#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 */
+#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 ;
+#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 */
+#ifdef MODET
+ 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) */
+#ifdef MODET
+ if (BITS(4,11) == 0xB) {
+ /* STRH register offset, write-back, down, pre indexed */
+ SHPREDOWNWB() ;
+ break ;
+ }
+#endif
+#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 */
+#ifdef MODET
+ 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 */
+#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 ;
+#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 */
+#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 */
+#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 */
+#ifdef MODET
+ if ((BITS(4,7) & 0x9) == 0x9) {
+ /* LDR immediate offset, write-back, down, pre indexed */
+ LHPREDOWNWB() ;
+ /* continue with remaining instruction decoding */
+ }
+#endif
+ if (DESTReg == 15) {
+#ifdef MODE32
+ state->Cpsr = GETSPSR(state->Bank) ;
+ ARMul_CPSRAltered(state) ;
+#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 ;
+ }
+#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 ;
+ }
+#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 ;
+ }
+#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 : /* 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)) {
+ 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 */
+#else
+ state->Reg[14] = pc + 4 | ECC | ER15INT | EMODE ; /* put PC into Link */
+#endif
+ state->Reg[15] = pc + 8 + POSBRANCH ;
+ FLUSHPIPE ;
+ break ;
+
+/***************************************************************************\
+* Branch and Link backward *
+\***************************************************************************/
+
+ 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 */
+
+#ifdef MODET
+donext:
+#endif
+
+ if (state->Emulate == ONCE)
+ state->Emulate = STOP;
+ else if (state->Emulate != RUN)
+ break;
+ } while (1) ; /* 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 */
+#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)) ;
+ }
+ }
+ }
+ return(0) ; /* just to shut up lint */
+ }
+
+/***************************************************************************\
+* 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 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) ;
+#endif
+ FLUSHPIPE ;
+ }
+
+/***************************************************************************\
+* This routine handles writes to register 15 when the S bit is set. *
+\***************************************************************************/
+
+static void WriteSR15(ARMul_State *state, ARMword src)
+{
+#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 ;
+ }
+
+/***************************************************************************\
+* 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 *
+\***************************************************************************/
+
+static ARMword GetLSRegRHS(ARMul_State *state, ARMword instr)
+{ARMword shamt, base ;
+
+ 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)) ;
+ }
+ return(0) ; /* just to shut up lint */
+ }
+
+/***************************************************************************\
+* This routine evaluates the ARM7T halfword and signed transfer RHS's. *
+\***************************************************************************/
+
+static ARMword GetLS7RHS(ARMul_State *state, ARMword instr)
+{
+ if (BIT(22) == 0) { /* register */
+#ifndef MODE32
+ if (RHSReg == 15)
+ return ECC | ER15INT | R15PC | EMODE ; /* Now forbidden, but ... */
+#endif
+ return state->Reg[RHSReg] ;
+ }
+
+ /* else immediate */
+ return BITS(0,3) | (BITS(8,11) << 4) ;
+ }
+
+/***************************************************************************\
+* This function does the work of loading a word for a LDR instruction. *
+\***************************************************************************/
+
+static unsigned LoadWord(ARMul_State *state, ARMword instr, ARMword address)
+{
+ ARMword dest ;
+
+ BUSUSEDINCPCS ;
+#ifndef MODE32
+ if (ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ }
+#endif
+ dest = ARMul_LoadWordN(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) ;
+
+ return(DESTReg != LHSReg) ;
+}
+
+#ifdef MODET
+/***************************************************************************\
+* This function does the work of loading a halfword. *
+\***************************************************************************/
+
+static unsigned LoadHalfWord(ARMul_State *state, ARMword instr, ARMword address,int signextend)
+{
+ ARMword dest ;
+
+ BUSUSEDINCPCS ;
+#ifndef MODE32
+ if (ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ }
+#endif
+ 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) ;
+}
+#endif /* MODET */
+
+/***************************************************************************\
+* This function does the work of loading a byte for a LDRB instruction. *
+\***************************************************************************/
+
+static unsigned LoadByte(ARMul_State *state, ARMword instr, ARMword address,int signextend)
+{
+ ARMword dest ;
+
+ BUSUSEDINCPCS ;
+#ifndef MODE32
+ if (ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ }
+#endif
+ dest = ARMul_LoadByte(state,address) ;
+ if (state->Aborted) {
+ TAKEABORT ;
+ return(state->lateabtSig) ;
+ }
+ 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) ;
+}
+
+/***************************************************************************\
+* This function does the work of storing a word from a STR instruction. *
+\***************************************************************************/
+
+static unsigned StoreWord(ARMul_State *state, ARMword instr, ARMword address)
+{BUSUSEDINCPCN ;
+#ifndef MODE32
+ if (DESTReg == 15)
+ state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
+#endif
+#ifdef MODE32
+ ARMul_StoreWordN(state,address,DEST) ;
+#else
+ if (VECTORACCESS(address) || ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ (void)ARMul_LoadWordN(state,address) ;
+ }
+ else
+ ARMul_StoreWordN(state,address,DEST) ;
+#endif
+ if (state->Aborted) {
+ TAKEABORT ;
+ return(state->lateabtSig) ;
+ }
+ return(TRUE) ;
+}
+
+#ifdef MODET
+/***************************************************************************\
+* This function does the work of storing a byte for a STRH instruction. *
+\***************************************************************************/
+
+static unsigned StoreHalfWord(ARMul_State *state, ARMword instr, ARMword address)
+{BUSUSEDINCPCN ;
+
+#ifndef MODE32
+ if (DESTReg == 15)
+ state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
+#endif
+
+#ifdef MODE32
+ ARMul_StoreHalfWord(state,address,DEST);
+#else
+ if (VECTORACCESS(address) || ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ (void)ARMul_LoadHalfWord(state,address) ;
+ }
+ else
+ ARMul_StoreHalfWord(state,address,DEST) ;
+#endif
+
+ if (state->Aborted) {
+ TAKEABORT ;
+ return(state->lateabtSig) ;
+ }
+
+ return(TRUE) ;
+}
+#endif /* MODET */
+
+/***************************************************************************\
+* This function does the work of storing a byte for a STRB instruction. *
+\***************************************************************************/
+
+static unsigned StoreByte(ARMul_State *state, ARMword instr, ARMword address)
+{BUSUSEDINCPCN ;
+#ifndef MODE32
+ if (DESTReg == 15)
+ state->Reg[15] = ECC | ER15INT | R15PC | EMODE ;
+#endif
+#ifdef MODE32
+ ARMul_StoreByte(state,address,DEST) ;
+#else
+ if (VECTORACCESS(address) || ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ (void)ARMul_LoadByte(state,address) ;
+ }
+ else
+ ARMul_StoreByte(state,address,DEST) ;
+#endif
+ if (state->Aborted) {
+ TAKEABORT ;
+ return(state->lateabtSig) ;
+ }
+ 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 ;
+#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 ;
+#endif
+ FLUSHPIPE ;
+ }
+
+ ARMul_Icycles(state,1,0L) ; /* to write back the final register */
+
+ 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 ;
+#ifndef MODE32
+ 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 ;
+
+ 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 */
+#ifdef MODE32
+ if (state->Mode != USER26MODE && state->Mode != USER32MODE) {
+ state->Cpsr = GETSPSR(state->Bank) ;
+ ARMul_CPSRAltered(state) ;
+ }
+ state->Reg[15] = 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 (!BIT(15) && state->Mode != USER26MODE && state->Mode != USER32MODE)
+ (void)ARMul_SwitchMode(state,USER26MODE,state->Mode) ; /* restore the correct bank */
+
+ ARMul_Icycles(state,1,0L) ; /* to write back the final register */
+
+ 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. *
+\***************************************************************************/
+
+static void StoreMult(ARMul_State *state, ARMword instr,
+ ARMword address, ARMword WBBase)
+{ARMword temp ;
+
+ UNDEF_LSMNoRegs ;
+ UNDEF_LSMPCBase ;
+ UNDEF_LSMBaseInListWb ;
+ if (!TFLAG) {
+ BUSUSEDINCPCN ; /* N-cycle, increment the PC and update the NextInstr state */
+ }
+
+#ifndef MODE32
+ if (VECTORACCESS(address) || ADDREXCEPT(address)) {
+ INTERNALABORT(address) ;
+ }
+ if (BIT(15))
+ PATCHR15 ;
+#endif
+
+ for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
+#ifdef MODE32
+ 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 ;
+ }
+ 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) ;
+ }
+ if (BIT(15))
+ PATCHR15 ;
+#endif
+
+ if (state->Bank != USERBANK) {
+ (void)ARMul_SwitchMode(state,state->Mode,USER26MODE) ; /* Force User Bank */
+ UNDEF_LSMUserBankWb ;
+ }
+
+ for (temp = 0 ; !BIT(temp) ; temp++) ; /* N cycle first */
+#ifdef MODE32
+ 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 ;
+ }
+ 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->Mode != USER26MODE && state->Mode != USER32MODE)
+ (void)ARMul_SwitchMode(state,USER26MODE,state->Mode) ; /* restore the correct bank */
+
+ if (state->Aborted) {
+ TAKEABORT ;
+ }
+}
+
+/***************************************************************************\
+* 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)
+{
+ ARMword result = (a1 + a2);
+ 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: */
+ if ((uresult == ua1) ? (a2 != 0) : (uresult < ua1))
+ *carry = 1;
+ else
+ *carry = 0;
+
+ return(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)
+{
+ 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: */
+ Rm = state->Reg[nRm];
+
+ /* Check for illegal operand combinations first: */
+ if ( nRdHi != 15
+ && nRdLo != 15
+ && nRs != 15
+ && nRm != 15
+ && nRdHi != nRdLo
+ && nRdHi != nRm
+ && nRdLo != nRm)
+ {
+ ARMword lo, mid1, mid2, hi; /* intermediate results */
+ int carry;
+ ARMword Rs = state->Reg[ nRs ];
+ int sign = 0;
+
+ if (msigned)
+ {
+ /* Compute sign of result and adjust operands if necessary. */
+
+ sign = (Rm ^ Rs) & 0x80000000;
+
+ if (((signed long)Rm) < 0)
+ Rm = -Rm;
+
+ if (((signed long)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));
+ 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);
+ RdHi = carry;
+ 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;
+ if (RdLo == 0xFFFFFFFF)
+ {
+ RdLo = 0;
+ RdHi += 1;
+ }
+ 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 */
+ }
+
+ /* 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 */
+
+ if ((Rm & 0xFFFFFF00) == 0)
+ scount = 1 ;
+ else if ((Rm & 0xFFFF0000) == 0)
+ scount = 2 ;
+ else if ((Rm & 0xFF000000) == 0)
+ scount = 3 ;
+ else
+ 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. *
+\***************************************************************************/
+
+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);
+
+ RdHi = state->Reg[nRdHi] ;
+ RdLo = state->Reg[nRdLo] ;
+
+ scount = Multiply64(state,instr,msigned,LDEFAULT);
+
+ 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 */
+ }
+
+ return scount + 1; /* extra cycle for addition */
+}