diff --git a/trunk/VBA.vcproj b/trunk/VBA.vcproj
index cb79a096..d473948d 100644
--- a/trunk/VBA.vcproj
+++ b/trunk/VBA.vcproj
@@ -1,7 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
@@ -836,7 +826,17 @@
/>
+
+
+
@@ -930,16 +930,6 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -950,16 +940,6 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -970,6 +950,26 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
+
+
+
+
+
+
@@ -994,16 +994,6 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -1014,16 +1004,6 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -1034,6 +1014,26 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
+
+
+
+
+
+
@@ -1058,16 +1058,6 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -1079,7 +1069,17 @@
/>
+
+
+
@@ -1122,16 +1122,6 @@
Outputs=""$(ProjectDir)$(IntDir)\$(InputName).obj""
/>
-
-
-
@@ -1143,7 +1133,17 @@
/>
+
+
+
@@ -1302,6 +1302,14 @@
RelativePath=".\src\Flash.cpp"
>
+
+
+
+
@@ -1697,14 +1705,6 @@
CompileAs="1"
/>
-
-
-
@@ -1714,7 +1714,7 @@
/>
+
+
+
-
-
@@ -1904,10 +1908,6 @@
RelativePath=".\src\System.h"
>
-
-
+#include
+#include
+#include
+#include
+
+#include "GBA.h"
+#include "GBAcpu.h"
+#include "GBAinline.h"
+#include "Globals.h"
+#include "Gfx.h"
+#include "EEprom.h"
+#include "Flash.h"
+#include "Sound.h"
+#include "Sram.h"
+#include "bios.h"
+#include "unzip.h"
+#include "Cheats.h"
+#include "NLS.h"
+#include "elf.h"
+#include "Util.h"
+#include "Port.h"
+#include "agbprint.h"
+#ifdef PROFILING
+#include "prof/prof.h"
+#endif
+
+#ifdef _MSC_VER
+ // Disable "empty statement" warnings
+ #pragma warning(disable: 4390)
+ // Visual C's inline assembler treats "offset" as a reserved word, so we
+ // tell it otherwise. If you want to use it, write "OFFSET" in capitals.
+ #define offset offset_
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+static int clockTicks;
+
+static INSN_REGPARM void armUnknownInsn(u32 opcode)
+{
+#ifdef DEV_VERSION
+ if (systemVerbose & VERBOSE_UNDEFINED) {
+ log("Undefined ARM instruction %08x at %08x\n", opcode,
+ armNextPC-4);
+ }
+#endif
+ CPUUndefinedException();
+}
+
+#ifdef BKPT_SUPPORT
+static INSN_REGPARM void armBreakpoint(u32 opcode)
+{
+ extern void (*dbgSignal)(int,int);
+ reg[15].I -= 4;
+ armNextPC -= 4;
+ dbgSignal(5, (opcode & 0x0f) | ((opcode>>4) & 0xfff0));
+ clockTicks = -1;
+}
+#endif
+
+
+// Subroutine to count instructions (for debugging/optimizing)
+//#define INSN_COUNTER // comment out if you don't want it
+#ifdef INSN_COUNTER
+static void count(u32 opcode, int cond_res)
+{
+ static int insncount = 0; // number of insns seen
+ static int executed = 0; // number of insns executed
+ static int mergewith[4096]; // map instructions to routines
+ static int count[4096]; // count of each 12-bit code
+ int index = ((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F);
+ static FILE *outfile = NULL;
+
+ if (!insncount) {
+ for (int i = 0; i < 4096; i++) {
+ for (int j = 0; j < i; j++) {
+ if (armInsnTable[i] == armInsnTable[j])
+ break;
+ }
+ mergewith[i] = j;
+ }
+ outfile = fopen("VBA-armcount.txt", "w");
+ }
+ if (cond_res) {
+ count[mergewith[index]]++;
+ executed++;
+ }
+ insncount++;
+ if (outfile && insncount%1000000 == 0) {
+ fprintf(outfile, "Total instructions: %d\n", insncount);
+ fprintf(outfile, "Instructions executed: %d\n", executed);
+ for (int i = 0; i < 4096; i++) {
+ if (count[i])
+ fprintf(outfile, "arm%03X: %d\n", i, count[i]);
+ }
+ }
+}
+#endif
+
+// Common macros //////////////////////////////////////////////////////////
+
+#ifdef BKPT_SUPPORT
+#define CONSOLE_OUTPUT(a,b) do { \
+ extern void (*dbgOutput)(char *, u32); \
+ if ((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) { \
+ dbgOutput((a), (b)); \
+} while (0)
+#else
+#define CONSOLE_OUTPUT(a,b) /* nothing */
+#endif
+
+#define NEG(i) ((i) >> 31)
+#define POS(i) ((~(i)) >> 31)
+
+// The following macros are used for optimization; any not defined for a
+// particular compiler/CPU combination default to the C core versions.
+//
+// ALU_INIT_C: Used at the beginning of ALU instructions (AND/EOR/...).
+// (ALU_INIT_NC) Can consist of variable declarations, like the C core,
+// or the start of a continued assembly block, like the
+// x86-optimized version. The _C version is used when the
+// carry flag from the shift operation is needed (logical
+// operations that set condition codes, like ANDS); the
+// _NC version is used when the carry result is ignored.
+// VALUE_XXX: Retrieve the second operand's value for an ALU instruction.
+// The _C and _NC versions are used the same way as ALU_INIT.
+// OP_XXX: ALU operations. XXX is the instruction name.
+// ALU_FINISH: Appended to all ALU instructions. Usually empty, but if
+// ALU_INIT started a block ALU_FINISH can be used to end it
+// (as with the asm(...) statement in the x86 core).
+// SETCOND_NONE: Used in multiply instructions in place of SETCOND_MUL
+// when the condition codes are not set. Usually empty.
+// SETCOND_MUL: Used in multiply instructions to set the condition codes.
+// ROR_IMM_MSR: Used to rotate the immediate operand for MSR.
+// ROR_OFFSET: Used to rotate the `offset' parameter for LDR and STR
+// instructions.
+// RRX_OFFSET: Used to rotate (RRX) the `offset' parameter for LDR and
+// STR instructions.
+
+#ifndef C_CORE
+
+#if 0 // definitions have changed
+//#ifdef __POWERPC__
+ #define OP_SUBS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_RSBS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subfco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_ADDS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_ADCS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "addeo. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_SBCS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "subfeo. %0, %3, %2\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_RSCS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "subfeo. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_CMP \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define OP_CMN \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[base].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+
+#else // !__POWERPC__
+
+// Macros to emit instructions in the format used by the particular compiler.
+// We use GNU assembler syntax: "op src, dest" rather than "op dest, src"
+
+#ifdef __GNUC__
+ #define ALU_HEADER asm("mov %%ecx, %%edi; "
+ #define ALU_TRAILER : "=D" (opcode) : "c" (opcode) : "eax", "ebx", "edx", "esi")
+ #define EMIT0(op) #op"; "
+ #define EMIT1(op,arg) #op" "arg"; "
+ #define EMIT2(op,src,dest) #op" "src", "dest"; "
+ #define CONST(val) "$"#val
+ #define VAR(var) #var
+ #define VARL(var) #var
+ #define REGREF1(index) "reg("index")"
+ #define REGREF2(index,scale) "reg(,"index","#scale")"
+ #define LABEL(n) #n": "
+ #define LABELREF(n,dir) #n#dir
+ #define al "%%al"
+ #define ah "%%ah"
+ #define eax "%%eax"
+ #define bl "%%bl"
+ #define bh "%%bh"
+ #define ebx "%%ebx"
+ #define cl "%%cl"
+ #define ch "%%ch"
+ #define ecx "%%ecx"
+ #define dl "%%dl"
+ #define dh "%%dh"
+ #define edx "%%edx"
+ #define esp "%%esp"
+ #define ebp "%%ebp"
+ #define esi "%%esi"
+ #define edi "%%edi"
+ #define movzx movzb
+#else
+ #define ALU_HEADER __asm { __asm mov ecx, opcode
+ #define ALU_TRAILER }
+ #define EMIT0(op) __asm op
+ #define EMIT1(op,arg) __asm op arg
+ #define EMIT2(op,src,dest) __asm op dest, src
+ #define CONST(val) val
+ #define VAR(var) var
+ #define VARL(var) dword ptr var
+ #define REGREF1(index) reg[index]
+ #define REGREF2(index,scale) reg[index*scale]
+ #define LABEL(n) __asm l##n:
+ #define LABELREF(n,dir) l##n
+#endif
+
+//X//#ifndef _MSC_VER
+// ALU op register usage:
+// EAX -> 2nd operand value, result (RSB/RSC)
+// EBX -> C_OUT (carry flag from shift/rotate)
+// ECX -> opcode (input), shift/rotate count
+// EDX -> Rn (base) value, result (all except RSB/RSC)
+// ESI -> Rd (destination) index * 4
+
+// Helper macros for loading value / shift count
+#define VALUE_LOAD_IMM \
+ EMIT2(and, CONST(0x0F), eax) \
+ EMIT2(mov, REGREF2(eax,4), eax) \
+ EMIT2(shr, CONST(7), ecx) \
+ EMIT2(and, CONST(0x1F), ecx)
+#define VALUE_LOAD_REG \
+ EMIT2(and, CONST(0x0F), eax) \
+ EMIT2(mov, REGREF2(eax,4), eax) \
+ EMIT2(movzx, ch, ecx) \
+ EMIT2(and, CONST(0x0F), ecx) \
+ EMIT2(mov, REGREF2(ecx,4), ecx)
+
+// Helper macros for setting flags
+#define SETCOND_LOGICAL \
+ EMIT1(sets, VAR(N_FLAG)) \
+ EMIT1(setz, VAR(Z_FLAG)) \
+ EMIT2(mov, bl, VAR(C_FLAG))
+#define SETCOND_ADD \
+ EMIT1(sets, VAR(N_FLAG)) \
+ EMIT1(setz, VAR(Z_FLAG)) \
+ EMIT1(seto, VAR(V_FLAG)) \
+ EMIT1(setc, VAR(C_FLAG))
+#define SETCOND_SUB \
+ EMIT1(sets, VAR(N_FLAG)) \
+ EMIT1(setz, VAR(Z_FLAG)) \
+ EMIT1(seto, VAR(V_FLAG)) \
+ EMIT1(setnc, VAR(C_FLAG))
+
+// ALU initialization
+#define ALU_INIT(LOAD_C_FLAG) \
+ ALU_HEADER \
+ LOAD_C_FLAG \
+ EMIT2(mov, ecx, edx) \
+ EMIT2(shr, CONST(14), edx) \
+ EMIT2(mov, ecx, eax) \
+ EMIT2(mov, ecx, esi) \
+ EMIT2(shr, CONST(10), esi) \
+ EMIT2(and, CONST(0x3C), edx) \
+ EMIT2(mov, REGREF1(edx), edx) \
+ EMIT2(and, CONST(0x3C), esi)
+
+#define LOAD_C_FLAG_YES EMIT2(mov, VAR(C_FLAG), bl)
+#define LOAD_C_FLAG_NO /*nothing*/
+#define ALU_INIT_C ALU_INIT(LOAD_C_FLAG_YES)
+#define ALU_INIT_NC ALU_INIT(LOAD_C_FLAG_NO)
+
+// Macros to load the value operand for an ALU op; these all set N/Z
+// according to the value
+
+// OP Rd,Rb,Rm LSL #
+#define VALUE_LSL_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jnz, LABELREF(1,f)) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(shl, cl, eax) \
+ EMIT1(setc, bl) \
+ LABEL(0)
+#define VALUE_LSL_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT2(shl, cl, eax)
+
+// OP Rd,Rb,Rm LSL Rs
+#define VALUE_LSL_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(test, cl, cl) \
+ EMIT1(jz, LABELREF(0,f)) \
+ EMIT2(cmp, CONST(0x20), cl) \
+ EMIT1(je, LABELREF(1,f)) \
+ EMIT1(ja, LABELREF(2,f)) \
+ EMIT2(shl, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(test, CONST(1), al) \
+ EMIT1(setnz, bl) \
+ EMIT2(xor, eax, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(2) \
+ EMIT2(xor, ebx, ebx) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+#define VALUE_LSL_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(cmp, CONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(shl, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm LSR #
+#define VALUE_LSR_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(test, eax, eax) \
+ EMIT1(sets, bl) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+#define VALUE_LSR_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm LSR Rs
+#define VALUE_LSR_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(test, cl, cl) \
+ EMIT1(jz, LABELREF(0,f)) \
+ EMIT2(cmp, CONST(0x20), cl) \
+ EMIT1(je, LABELREF(1,f)) \
+ EMIT1(ja, LABELREF(2,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(test, eax, eax) \
+ EMIT1(sets, bl) \
+ EMIT2(xor, eax, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(2) \
+ EMIT2(xor, ebx, ebx) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+#define VALUE_LSR_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(cmp, CONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(shr, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(xor, eax, eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ASR #
+#define VALUE_ASR_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, CONST(31), eax) \
+ EMIT1(sets, bl) \
+ LABEL(0)
+#define VALUE_ASR_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, CONST(31), eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ASR Rs
+#define VALUE_ASR_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(test, cl, cl) \
+ EMIT1(jz, LABELREF(0,f)) \
+ EMIT2(cmp, CONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(setc, bl) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, CONST(31), eax) \
+ EMIT1(sets, bl) \
+ LABEL(0)
+#define VALUE_ASR_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(cmp, CONST(0x20), cl) \
+ EMIT1(jae, LABELREF(1,f)) \
+ EMIT2(sar, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(sar, CONST(31), eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ROR #
+#define VALUE_ROR_IMM_C \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(bt, CONST(0), ebx) \
+ EMIT2(rcr, CONST(1), eax) \
+ LABEL(0) \
+ EMIT1(setc, bl)
+#define VALUE_ROR_IMM_NC \
+ VALUE_LOAD_IMM \
+ EMIT1(jz, LABELREF(1,f)) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(jmp, LABELREF(0,f)) \
+ LABEL(1) \
+ EMIT2(bt, CONST(0), VARL(C_FLAG)) \
+ EMIT2(rcr, CONST(1), eax) \
+ LABEL(0)
+
+// OP Rd,Rb,Rm ROR Rs
+#define VALUE_ROR_REG_C \
+ VALUE_LOAD_REG \
+ EMIT2(bt, CONST(0), ebx) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(setc, bl)
+#define VALUE_ROR_REG_NC \
+ VALUE_LOAD_REG \
+ EMIT2(ror, cl, eax)
+
+// OP Rd,Rb,# ROR #
+#define VALUE_IMM_C \
+ EMIT2(movzx, ch, ecx) \
+ EMIT2(add, ecx, ecx) \
+ EMIT2(movzx, al, eax) \
+ EMIT2(bt, CONST(0), ebx) \
+ EMIT2(ror, cl, eax) \
+ EMIT1(setc, bl)
+#define VALUE_IMM_NC \
+ EMIT2(movzx, ch, ecx) \
+ EMIT2(add, ecx, ecx) \
+ EMIT2(movzx, al, eax) \
+ EMIT2(ror, cl, eax)
+
+// Macros to perform ALU ops
+
+// Set condition codes iff the destination register is not R15 (PC)
+#define CHECK_PC(OP, SETCOND) \
+ EMIT2(cmp, CONST(0x3C), esi) \
+ EMIT1(je, LABELREF(8,f)) \
+ OP SETCOND \
+ EMIT1(jmp, LABELREF(9,f)) \
+ LABEL(8) \
+ OP \
+ LABEL(9)
+
+#define OP_AND \
+ EMIT2(and, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ANDS CHECK_PC(OP_AND, SETCOND_LOGICAL)
+#define OP_EOR \
+ EMIT2(xor, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_EORS CHECK_PC(OP_EOR, SETCOND_LOGICAL)
+#define OP_SUB \
+ EMIT2(sub, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_SUBS CHECK_PC(OP_SUB, SETCOND_SUB)
+#define OP_RSB \
+ EMIT2(sub, edx, eax) \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_RSBS CHECK_PC(OP_RSB, SETCOND_SUB)
+#define OP_ADD \
+ EMIT2(add, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ADDS CHECK_PC(OP_ADD, SETCOND_ADD)
+#define OP_ADC \
+ EMIT2(bt, CONST(0), VARL(C_FLAG)) \
+ EMIT2(adc, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ADCS CHECK_PC(OP_ADC, SETCOND_ADD)
+#define OP_SBC \
+ EMIT2(bt, CONST(0), VARL(C_FLAG)) \
+ EMIT0(cmc) \
+ EMIT2(sbb, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_SBCS CHECK_PC(OP_SBC, SETCOND_SUB)
+#define OP_RSC \
+ EMIT2(bt, CONST(0), VARL(C_FLAG)) \
+ EMIT0(cmc) \
+ EMIT2(sbb, edx, eax) \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_RSCS CHECK_PC(OP_RSC, SETCOND_SUB)
+#define OP_TST \
+ EMIT2(and, eax, edx) \
+ SETCOND_LOGICAL
+#define OP_TEQ \
+ EMIT2(xor, eax, edx) \
+ SETCOND_LOGICAL
+#define OP_CMP \
+ EMIT2(sub, eax, edx) \
+ SETCOND_SUB
+#define OP_CMN \
+ EMIT2(add, eax, edx) \
+ SETCOND_ADD
+#define OP_ORR \
+ EMIT2(or, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_ORRS CHECK_PC(OP_ORR, SETCOND_LOGICAL)
+#define OP_MOV \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_MOVS CHECK_PC(EMIT2(test,eax,eax) EMIT2(mov,eax,REGREF1(esi)), SETCOND_LOGICAL)
+#define OP_BIC \
+ EMIT1(not, eax) \
+ EMIT2(and, eax, edx) \
+ EMIT2(mov, edx, REGREF1(esi))
+#define OP_BICS CHECK_PC(OP_BIC, SETCOND_LOGICAL)
+#define OP_MVN \
+ EMIT1(not, eax) \
+ EMIT2(mov, eax, REGREF1(esi))
+#define OP_MVNS CHECK_PC(OP_MVN, SETCOND_LOGICAL)
+
+// ALU cleanup macro
+#define ALU_FINISH ALU_TRAILER
+
+// End of ALU macros
+//X//#endif //_MSC_VER
+
+#ifdef __GNUC__
+
+#define ROR_IMM_MSR \
+ asm ("ror %%cl, %%eax;" \
+ : "=a" (value) \
+ : "a" (opcode & 0xFF), "c" (shift));
+
+#define ROR_OFFSET \
+ asm("ror %%cl, %0" \
+ : "=r" (offset) \
+ : "0" (offset), "c" (shift));
+
+#define RRX_OFFSET \
+ asm("btl $0, C_FLAG;" \
+ "rcr $1, %0" \
+ : "=r" (offset) \
+ : "0" (offset));
+
+#else // !__GNUC__, i.e. Visual C++
+
+#define ROR_IMM_MSR \
+ __asm { \
+ __asm mov ecx, shift \
+ __asm ror value, cl \
+ }
+
+
+#define ROR_OFFSET \
+ __asm { \
+ __asm mov ecx, shift \
+ __asm ror offset, cl \
+ }
+
+#define RRX_OFFSET \
+ __asm { \
+ __asm bt dword ptr C_FLAG, 0 \
+ __asm rcr offset, 1 \
+ }
+
+#endif // !__GNUC__
+
+#endif // !__POWERPC__
+#endif // !C_CORE
+
+// C core
+
+#define C_SETCOND_LOGICAL \
+ N_FLAG = ((s32)res < 0) ? true : false; \
+ Z_FLAG = (res == 0) ? true : false; \
+ C_FLAG = C_OUT;
+#define C_SETCOND_ADD \
+ N_FLAG = ((s32)res < 0) ? true : false; \
+ Z_FLAG = (res == 0) ? true : false; \
+ V_FLAG = ((NEG(lhs) & NEG(rhs) & POS(res)) | \
+ (POS(lhs) & POS(rhs) & NEG(res))) ? true : false;\
+ C_FLAG = ((NEG(lhs) & NEG(rhs)) | \
+ (NEG(lhs) & POS(res)) | \
+ (NEG(rhs) & POS(res))) ? true : false;
+#define C_SETCOND_SUB \
+ N_FLAG = ((s32)res < 0) ? true : false; \
+ Z_FLAG = (res == 0) ? true : false; \
+ V_FLAG = ((NEG(lhs) & POS(rhs) & POS(res)) | \
+ (POS(lhs) & NEG(rhs) & NEG(res))) ? true : false;\
+ C_FLAG = ((NEG(lhs) & POS(rhs)) | \
+ (NEG(lhs) & POS(res)) | \
+ (POS(rhs) & POS(res))) ? true : false;
+
+#ifndef ALU_INIT_C
+ #define ALU_INIT_C \
+ int dest = (opcode>>12) & 15; \
+ bool C_OUT = C_FLAG; \
+ u32 value;
+#endif
+// OP Rd,Rb,Rm LSL #
+#ifndef VALUE_LSL_IMM_C
+ #define VALUE_LSL_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(!shift)) { /* LSL #0 most common? */ \
+ value = reg[opcode & 0x0F].I; \
+ } else { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (32 - shift)) & 1 ? true : false; \
+ value = v << shift; \
+ }
+#endif
+// OP Rd,Rb,Rm LSL Rs
+#ifndef VALUE_LSL_REG_C
+ #define VALUE_LSL_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift)) { \
+ if (shift == 32) { \
+ value = 0; \
+ C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\
+ } else if (LIKELY(shift < 32)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (32 - shift)) & 1 ? true : false;\
+ value = v << shift; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ }
+#endif
+// OP Rd,Rb,Rm LSR #
+#ifndef VALUE_LSR_IMM_C
+ #define VALUE_LSR_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(shift)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = v >> shift; \
+ } else { \
+ value = 0; \
+ C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\
+ }
+#endif
+// OP Rd,Rb,Rm LSR Rs
+#ifndef VALUE_LSR_REG_C
+ #define VALUE_LSR_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift)) { \
+ if (shift == 32) { \
+ value = 0; \
+ C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\
+ } else if (LIKELY(shift < 32)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
+ value = v >> shift; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ }
+#endif
+// OP Rd,Rb,Rm ASR #
+#ifndef VALUE_ASR_IMM_C
+ #define VALUE_ASR_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(shift)) { \
+ /* VC++ BUG: u32 v; (s32)v>>n is optimized to shr! */ \
+ s32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\
+ value = v >> (int)shift; \
+ } else { \
+ if (reg[opcode & 0x0F].I & 0x80000000) { \
+ value = 0xFFFFFFFF; \
+ C_OUT = true; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ }
+#endif
+// OP Rd,Rb,Rm ASR Rs
+#ifndef VALUE_ASR_REG_C
+ #define VALUE_ASR_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift < 32)) { \
+ if (LIKELY(shift)) { \
+ s32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (int)(shift - 1)) & 1 ? true : false;\
+ value = v >> (int)shift; \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ } \
+ } else { \
+ if (reg[opcode & 0x0F].I & 0x80000000) { \
+ value = 0xFFFFFFFF; \
+ C_OUT = true; \
+ } else { \
+ value = 0; \
+ C_OUT = false; \
+ } \
+ }
+#endif
+// OP Rd,Rb,Rm ROR #
+#ifndef VALUE_ROR_IMM_C
+ #define VALUE_ROR_IMM_C \
+ unsigned int shift = (opcode >> 7) & 0x1F; \
+ if (LIKELY(shift)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = ((v << (32 - shift)) | \
+ (v >> shift)); \
+ } else { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v & 1) ? true : false; \
+ value = ((v >> 1) | \
+ (C_FLAG << 31)); \
+ }
+#endif
+// OP Rd,Rb,Rm ROR Rs
+#ifndef VALUE_ROR_REG_C
+ #define VALUE_ROR_REG_C \
+ unsigned int shift = reg[(opcode >> 8)&15].B.B0; \
+ if (LIKELY(shift & 0x1F)) { \
+ u32 v = reg[opcode & 0x0F].I; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = ((v << (32 - shift)) | \
+ (v >> shift)); \
+ } else { \
+ value = reg[opcode & 0x0F].I; \
+ if (shift) \
+ C_OUT = (value & 0x80000000 ? true : false);\
+ }
+#endif
+// OP Rd,Rb,# ROR #
+#ifndef VALUE_IMM_C
+ #define VALUE_IMM_C \
+ int shift = (opcode & 0xF00) >> 7; \
+ if (UNLIKELY(shift)) { \
+ u32 v = opcode & 0xFF; \
+ C_OUT = (v >> (shift - 1)) & 1 ? true : false; \
+ value = ((v << (32 - shift)) | \
+ (v >> shift)); \
+ } else { \
+ value = opcode & 0xFF; \
+ }
+#endif
+
+// Make the non-carry versions default to the carry versions
+// (this is fine for C--the compiler will optimize the dead code out)
+#ifndef ALU_INIT_NC
+ #define ALU_INIT_NC ALU_INIT_C
+#endif
+#ifndef VALUE_LSL_IMM_NC
+ #define VALUE_LSL_IMM_NC VALUE_LSL_IMM_C
+#endif
+#ifndef VALUE_LSL_REG_NC
+ #define VALUE_LSL_REG_NC VALUE_LSL_REG_C
+#endif
+#ifndef VALUE_LSR_IMM_NC
+ #define VALUE_LSR_IMM_NC VALUE_LSR_IMM_C
+#endif
+#ifndef VALUE_LSR_REG_NC
+ #define VALUE_LSR_REG_NC VALUE_LSR_REG_C
+#endif
+#ifndef VALUE_ASR_IMM_NC
+ #define VALUE_ASR_IMM_NC VALUE_ASR_IMM_C
+#endif
+#ifndef VALUE_ASR_REG_NC
+ #define VALUE_ASR_REG_NC VALUE_ASR_REG_C
+#endif
+#ifndef VALUE_ROR_IMM_NC
+ #define VALUE_ROR_IMM_NC VALUE_ROR_IMM_C
+#endif
+#ifndef VALUE_ROR_REG_NC
+ #define VALUE_ROR_REG_NC VALUE_ROR_REG_C
+#endif
+#ifndef VALUE_IMM_NC
+ #define VALUE_IMM_NC VALUE_IMM_C
+#endif
+
+#define C_CHECK_PC(SETCOND) if (LIKELY(dest != 15)) { SETCOND }
+#ifndef OP_AND
+ #define OP_AND \
+ u32 res = reg[(opcode>>16)&15].I & value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ANDS
+ #define OP_ANDS OP_AND C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_EOR
+ #define OP_EOR \
+ u32 res = reg[(opcode>>16)&15].I ^ value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_EORS
+ #define OP_EORS OP_EOR C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_SUB
+ #define OP_SUB \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs - rhs; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_SUBS
+ #define OP_SUBS OP_SUB C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_RSB
+ #define OP_RSB \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = rhs - lhs; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_RSBS
+ #define OP_RSBS OP_RSB C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_ADD
+ #define OP_ADD \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs + rhs; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ADDS
+ #define OP_ADDS OP_ADD C_CHECK_PC(C_SETCOND_ADD)
+#endif
+#ifndef OP_ADC
+ #define OP_ADC \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs + rhs + (u32)C_FLAG; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ADCS
+ #define OP_ADCS OP_ADC C_CHECK_PC(C_SETCOND_ADD)
+#endif
+#ifndef OP_SBC
+ #define OP_SBC \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs - rhs - !((u32)C_FLAG); \
+ reg[dest].I = res;
+#endif
+#ifndef OP_SBCS
+ #define OP_SBCS OP_SBC C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_RSC
+ #define OP_RSC \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = rhs - lhs - !((u32)C_FLAG); \
+ reg[dest].I = res;
+#endif
+#ifndef OP_RSCS
+ #define OP_RSCS OP_RSC C_CHECK_PC(C_SETCOND_SUB)
+#endif
+#ifndef OP_TST
+ #define OP_TST \
+ u32 res = reg[(opcode >> 16) & 0x0F].I & value; \
+ C_SETCOND_LOGICAL;
+#endif
+#ifndef OP_TEQ
+ #define OP_TEQ \
+ u32 res = reg[(opcode >> 16) & 0x0F].I ^ value; \
+ C_SETCOND_LOGICAL;
+#endif
+#ifndef OP_CMP
+ #define OP_CMP \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs - rhs; \
+ C_SETCOND_SUB;
+#endif
+#ifndef OP_CMN
+ #define OP_CMN \
+ u32 lhs = reg[(opcode>>16)&15].I; \
+ u32 rhs = value; \
+ u32 res = lhs + rhs; \
+ C_SETCOND_ADD;
+#endif
+#ifndef OP_ORR
+ #define OP_ORR \
+ u32 res = reg[(opcode >> 16) & 0x0F].I | value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_ORRS
+ #define OP_ORRS OP_ORR C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_MOV
+ #define OP_MOV \
+ u32 res = value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_MOVS
+ #define OP_MOVS OP_MOV C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_BIC
+ #define OP_BIC \
+ u32 res = reg[(opcode >> 16) & 0x0F].I & (~value); \
+ reg[dest].I = res;
+#endif
+#ifndef OP_BICS
+ #define OP_BICS OP_BIC C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+#ifndef OP_MVN
+ #define OP_MVN \
+ u32 res = ~value; \
+ reg[dest].I = res;
+#endif
+#ifndef OP_MVNS
+ #define OP_MVNS OP_MVN C_CHECK_PC(C_SETCOND_LOGICAL)
+#endif
+
+#ifndef SETCOND_NONE
+ #define SETCOND_NONE /*nothing*/
+#endif
+#ifndef SETCOND_MUL
+ #define SETCOND_MUL \
+ N_FLAG = ((s32)reg[dest].I < 0) ? true : false; \
+ Z_FLAG = reg[dest].I ? false : true;
+#endif
+#ifndef SETCOND_MULL
+ #define SETCOND_MULL \
+ N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
+ Z_FLAG = reg[dest].I || reg[acc].I ? false : true;
+#endif
+
+#ifndef ALU_FINISH
+ #define ALU_FINISH /*nothing*/
+#endif
+
+#ifndef ROR_IMM_MSR
+ #define ROR_IMM_MSR \
+ u32 v = opcode & 0xff; \
+ value = ((v << (32 - shift)) | (v >> shift));
+#endif
+#ifndef ROR_OFFSET
+ #define ROR_OFFSET \
+ offset = ((offset << (32 - shift)) | (offset >> shift));
+#endif
+#ifndef RRX_OFFSET
+ #define RRX_OFFSET \
+ offset = ((offset >> 1) | ((int)C_FLAG << 31));
+#endif
+
+// ALU ops (except multiply) //////////////////////////////////////////////
+
+// ALU_INIT: init code (ALU_INIT_C or ALU_INIT_NC)
+// GETVALUE: load value and shift/rotate (VALUE_XXX)
+// OP: ALU operation (OP_XXX)
+// MODECHANGE: MODECHANGE_NO or MODECHANGE_YES
+// ISREGSHIFT: 1 for insns of the form ...,Rn LSL/etc Rs; 0 otherwise
+// ALU_INIT, GETVALUE, OP, and ALU_FINISH are concatenated in order.
+#define ALU_INSN(ALU_INIT, GETVALUE, OP, MODECHANGE, ISREGSHIFT) \
+ ALU_INIT GETVALUE OP ALU_FINISH; \
+ if (LIKELY((opcode & 0x0000F000) != 0x0000F000)) { \
+ clockTicks = 1 + ISREGSHIFT \
+ + codeTicksAccessSeq32(armNextPC); \
+ } else { \
+ MODECHANGE; \
+ if (armState) { \
+ reg[15].I &= 0xFFFFFFFC; \
+ armNextPC = reg[15].I; \
+ reg[15].I += 4; \
+ ARM_PREFETCH; \
+ } else { \
+ reg[15].I &= 0xFFFFFFFE; \
+ armNextPC = reg[15].I; \
+ reg[15].I += 2; \
+ THUMB_PREFETCH; \
+ } \
+ clockTicks = 3 + ISREGSHIFT \
+ + codeTicksAccess32(armNextPC) \
+ + codeTicksAccessSeq32(armNextPC) \
+ + codeTicksAccessSeq32(armNextPC); \
+ }
+
+#define MODECHANGE_NO /*nothing*/
+#define MODECHANGE_YES CPUSwitchMode(reg[17].I & 0x1f, false);
+
+#define DEFINE_ALU_INSN_C(CODE1, CODE2, OP, MODECHANGE) \
+ static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSL_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_LSR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ASR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_ROR_REG_C, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_C, VALUE_IMM_C, OP_##OP, MODECHANGE_##MODECHANGE, 0); }
+#define DEFINE_ALU_INSN_NC(CODE1, CODE2, OP, MODECHANGE) \
+ static INSN_REGPARM void arm##CODE1##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##1(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSL_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##2(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##3(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_LSR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##4(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##5(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ASR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE1##6(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }\
+ static INSN_REGPARM void arm##CODE1##7(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_ROR_REG_NC, OP_##OP, MODECHANGE_##MODECHANGE, 1); }\
+ static INSN_REGPARM void arm##CODE2##0(u32 opcode) { ALU_INSN(ALU_INIT_NC, VALUE_IMM_NC, OP_##OP, MODECHANGE_##MODECHANGE, 0); }
+
+// AND
+DEFINE_ALU_INSN_NC(00, 20, AND, NO)
+// ANDS
+DEFINE_ALU_INSN_C (01, 21, ANDS, YES)
+
+// EOR
+DEFINE_ALU_INSN_NC(02, 22, EOR, NO)
+// EORS
+DEFINE_ALU_INSN_C (03, 23, EORS, YES)
+
+// SUB
+DEFINE_ALU_INSN_NC(04, 24, SUB, NO)
+// SUBS
+DEFINE_ALU_INSN_NC(05, 25, SUBS, YES)
+
+// RSB
+DEFINE_ALU_INSN_NC(06, 26, RSB, NO)
+// RSBS
+DEFINE_ALU_INSN_NC(07, 27, RSBS, YES)
+
+// ADD
+DEFINE_ALU_INSN_NC(08, 28, ADD, NO)
+// ADDS
+DEFINE_ALU_INSN_NC(09, 29, ADDS, YES)
+
+// ADC
+DEFINE_ALU_INSN_NC(0A, 2A, ADC, NO)
+// ADCS
+DEFINE_ALU_INSN_NC(0B, 2B, ADCS, YES)
+
+// SBC
+DEFINE_ALU_INSN_NC(0C, 2C, SBC, NO)
+// SBCS
+DEFINE_ALU_INSN_NC(0D, 2D, SBCS, YES)
+
+// RSC
+DEFINE_ALU_INSN_NC(0E, 2E, RSC, NO)
+// RSCS
+DEFINE_ALU_INSN_NC(0F, 2F, RSCS, YES)
+
+// TST
+DEFINE_ALU_INSN_C (11, 31, TST, NO)
+
+// TEQ
+DEFINE_ALU_INSN_C (13, 33, TEQ, NO)
+
+// CMP
+DEFINE_ALU_INSN_NC(15, 35, CMP, NO)
+
+// CMN
+DEFINE_ALU_INSN_NC(17, 37, CMN, NO)
+
+// ORR
+DEFINE_ALU_INSN_NC(18, 38, ORR, NO)
+// ORRS
+DEFINE_ALU_INSN_C (19, 39, ORRS, YES)
+
+// MOV
+DEFINE_ALU_INSN_NC(1A, 3A, MOV, NO)
+// MOVS
+DEFINE_ALU_INSN_C (1B, 3B, MOVS, YES)
+
+// BIC
+DEFINE_ALU_INSN_NC(1C, 3C, BIC, NO)
+// BICS
+DEFINE_ALU_INSN_C (1D, 3D, BICS, YES)
+
+// MVN
+DEFINE_ALU_INSN_NC(1E, 3E, MVN, NO)
+// MVNS
+DEFINE_ALU_INSN_C (1F, 3F, MVNS, YES)
+
+// Multiply instructions //////////////////////////////////////////////////
+
+// OP: OP_MUL, OP_MLA etc.
+// SETCOND: SETCOND_NONE, SETCOND_MUL, or SETCOND_MULL
+// CYCLES: base cycle count (1, 2, or 3)
+#define MUL_INSN(OP, SETCOND, CYCLES) \
+ int mult = (opcode & 0x0F); \
+ u32 rs = reg[(opcode >> 8) & 0x0F].I; \
+ int acc = (opcode >> 12) & 0x0F; /* or destLo */ \
+ int dest = (opcode >> 16) & 0x0F; /* or destHi */ \
+ OP; \
+ SETCOND; \
+ if ((s32)rs < 0) \
+ rs = ~rs; \
+ if ((rs & 0xFFFFFF00) == 0) \
+ clockTicks += 0; \
+ else if ((rs & 0xFFFF0000) == 0) \
+ clockTicks += 1; \
+ else if ((rs & 0xFF000000) == 0) \
+ clockTicks += 2; \
+ else \
+ clockTicks += 3; \
+ if (busPrefetchCount == 0) \
+ busPrefetchCount = ((busPrefetchCount+1)<> 32);
+#define OP_MLAL(SIGN) \
+ SIGN##64 res = ((SIGN##64)reg[dest].I<<32 | reg[acc].I)\
+ + ((SIGN##64)(SIGN##32)reg[mult].I \
+ * (SIGN##64)(SIGN##32)rs); \
+ reg[acc].I = (u32)res; \
+ reg[dest].I = (u32)(res >> 32);
+#define OP_UMULL OP_MULL(u)
+#define OP_UMLAL OP_MLAL(u)
+#define OP_SMULL OP_MULL(s)
+#define OP_SMLAL OP_MLAL(s)
+
+// MUL Rd, Rm, Rs
+static INSN_REGPARM void arm009(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_NONE, 1); }
+// MULS Rd, Rm, Rs
+static INSN_REGPARM void arm019(u32 opcode) { MUL_INSN(OP_MUL, SETCOND_MUL, 1); }
+
+// MLA Rd, Rm, Rs, Rn
+static INSN_REGPARM void arm029(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_NONE, 2); }
+// MLAS Rd, Rm, Rs, Rn
+static INSN_REGPARM void arm039(u32 opcode) { MUL_INSN(OP_MLA, SETCOND_MUL, 2); }
+
+// UMULL RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm089(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_NONE, 2); }
+// UMULLS RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm099(u32 opcode) { MUL_INSN(OP_UMULL, SETCOND_MULL, 2); }
+
+// UMLAL RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm0A9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_NONE, 3); }
+// UMLALS RdLo, RdHi, Rn, Rs
+static INSN_REGPARM void arm0B9(u32 opcode) { MUL_INSN(OP_UMLAL, SETCOND_MULL, 3); }
+
+// SMULL RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0C9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_NONE, 2); }
+// SMULLS RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0D9(u32 opcode) { MUL_INSN(OP_SMULL, SETCOND_MULL, 2); }
+
+// SMLAL RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0E9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_NONE, 3); }
+// SMLALS RdLo, RdHi, Rm, Rs
+static INSN_REGPARM void arm0F9(u32 opcode) { MUL_INSN(OP_SMLAL, SETCOND_MULL, 3); }
+
+// Misc instructions //////////////////////////////////////////////////////
+
+// SWP Rd, Rm, [Rn]
+static INSN_REGPARM void arm109(u32 opcode)
+{
+ u32 address = reg[(opcode >> 16) & 15].I;
+ u32 temp = CPUReadMemory(address);
+ CPUWriteMemory(address, reg[opcode&15].I);
+ reg[(opcode >> 12) & 15].I = temp;
+ clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address)
+ + codeTicksAccess32(armNextPC);
+}
+
+// SWPB Rd, Rm, [Rn]
+static INSN_REGPARM void arm149(u32 opcode)
+{
+ u32 address = reg[(opcode >> 16) & 15].I;
+ u32 temp = CPUReadByte(address);
+ CPUWriteByte(address, reg[opcode&15].B.B0);
+ reg[(opcode>>12)&15].I = temp;
+ clockTicks = 4 + dataTicksAccess32(address) + dataTicksAccess32(address)
+ + codeTicksAccess32(armNextPC);
+}
+
+// MRS Rd, CPSR
+static INSN_REGPARM void arm100(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FFF0FFF) == 0x010F0000)) {
+ CPUUpdateCPSR();
+ reg[(opcode >> 12) & 0x0F].I = reg[16].I;
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MRS Rd, SPSR
+static INSN_REGPARM void arm140(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FFF0FFF) == 0x014F0000)) {
+ reg[(opcode >> 12) & 0x0F].I = reg[17].I;
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR CPSR_fields, Rm
+static INSN_REGPARM void arm120(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0FFF0) == 0x0120F000)) {
+ CPUUpdateCPSR();
+ u32 value = reg[opcode & 15].I;
+ u32 newValue = reg[16].I;
+ if (armMode > 0x10) {
+ if (opcode & 0x00010000)
+ newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
+ }
+ if (opcode & 0x00080000)
+ newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
+ newValue |= 0x10;
+ CPUSwitchMode(newValue & 0x1F, false);
+ reg[16].I = newValue;
+ CPUUpdateFlags();
+ if (!armState) { // this should not be allowed, but it seems to work
+ THUMB_PREFETCH;
+ reg[15].I = armNextPC + 2;
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR SPSR_fields, Rm
+static INSN_REGPARM void arm160(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0FFF0) == 0x0160F000)) {
+ u32 value = reg[opcode & 15].I;
+ if (armMode > 0x10 && armMode < 0x1F) {
+ if (opcode & 0x00010000)
+ reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
+ if (opcode & 0x00080000)
+ reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR CPSR_fields, #
+static INSN_REGPARM void arm320(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0F000) == 0x0320F000)) {
+ CPUUpdateCPSR();
+ u32 value = opcode & 0xFF;
+ int shift = (opcode & 0xF00) >> 7;
+ if (shift) {
+ ROR_IMM_MSR;
+ }
+ u32 newValue = reg[16].I;
+ if (armMode > 0x10) {
+ if (opcode & 0x00010000)
+ newValue = (newValue & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ newValue = (newValue & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ newValue = (newValue & 0xFF00FFFF) | (value & 0x00FF0000);
+ }
+ if (opcode & 0x00080000)
+ newValue = (newValue & 0x00FFFFFF) | (value & 0xFF000000);
+
+ newValue |= 0x10;
+
+ CPUSwitchMode(newValue & 0x1F, false);
+ reg[16].I = newValue;
+ CPUUpdateFlags();
+ if (!armState) { // this should not be allowed, but it seems to work
+ THUMB_PREFETCH;
+ reg[15].I = armNextPC + 2;
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// MSR SPSR_fields, #
+static INSN_REGPARM void arm360(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FF0F000) == 0x0360F000)) {
+ if (armMode > 0x10 && armMode < 0x1F) {
+ u32 value = opcode & 0xFF;
+ int shift = (opcode & 0xF00) >> 7;
+ if (shift) {
+ ROR_IMM_MSR;
+ }
+ if (opcode & 0x00010000)
+ reg[17].I = (reg[17].I & 0xFFFFFF00) | (value & 0x000000FF);
+ if (opcode & 0x00020000)
+ reg[17].I = (reg[17].I & 0xFFFF00FF) | (value & 0x0000FF00);
+ if (opcode & 0x00040000)
+ reg[17].I = (reg[17].I & 0xFF00FFFF) | (value & 0x00FF0000);
+ if (opcode & 0x00080000)
+ reg[17].I = (reg[17].I & 0x00FFFFFF) | (value & 0xFF000000);
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// BX Rm
+static INSN_REGPARM void arm121(u32 opcode)
+{
+ if (LIKELY((opcode & 0x0FFFFFF0) == 0x012FFF10)) {
+ int base = opcode & 0x0F;
+ busPrefetchCount = 0;
+ armState = reg[base].I & 1 ? false : true;
+ if (armState) {
+ reg[15].I = reg[base].I & 0xFFFFFFFC;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = 3 + codeTicksAccessSeq32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC)
+ + codeTicksAccess32(armNextPC);
+ } else {
+ reg[15].I = reg[base].I & 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = 3 + codeTicksAccessSeq16(armNextPC)
+ + codeTicksAccessSeq16(armNextPC)
+ + codeTicksAccess16(armNextPC);
+ }
+ } else {
+ armUnknownInsn(opcode);
+ }
+}
+
+// Load/store /////////////////////////////////////////////////////////////
+
+#define OFFSET_IMM \
+ int offset = opcode & 0xFFF;
+#define OFFSET_IMM8 \
+ int offset = ((opcode & 0x0F) | ((opcode>>4) & 0xF0));
+#define OFFSET_REG \
+ int offset = reg[opcode & 15].I;
+#define OFFSET_LSL \
+ int offset = reg[opcode & 15].I << ((opcode>>7) & 31);
+#define OFFSET_LSR \
+ int shift = (opcode >> 7) & 31; \
+ int offset = shift ? reg[opcode & 15].I >> shift : 0;
+#define OFFSET_ASR \
+ int shift = (opcode >> 7) & 31; \
+ int offset; \
+ if (shift) \
+ offset = (int)((s32)reg[opcode & 15].I >> shift);\
+ else if (reg[opcode & 15].I & 0x80000000) \
+ offset = 0xFFFFFFFF; \
+ else \
+ offset = 0;
+#define OFFSET_ROR \
+ int shift = (opcode >> 7) & 31; \
+ u32 offset = reg[opcode & 15].I; \
+ if (shift) { \
+ ROR_OFFSET; \
+ } else { \
+ RRX_OFFSET; \
+ }
+
+#define ADDRESS_POST (reg[base].I)
+#define ADDRESS_PREDEC (reg[base].I - offset)
+#define ADDRESS_PREINC (reg[base].I + offset)
+
+#define OP_STR CPUWriteMemory(address, reg[dest].I)
+#define OP_STRH CPUWriteHalfWord(address, reg[dest].W.W0)
+#define OP_STRB CPUWriteByte(address, reg[dest].B.B0)
+#define OP_LDR reg[dest].I = CPUReadMemory(address)
+#define OP_LDRH reg[dest].I = CPUReadHalfWord(address)
+#define OP_LDRB reg[dest].I = CPUReadByte(address)
+#define OP_LDRSH reg[dest].I = (s16)CPUReadHalfWordSigned(address)
+#define OP_LDRSB reg[dest].I = (s8)CPUReadByte(address)
+
+#define WRITEBACK_NONE /*nothing*/
+#define WRITEBACK_PRE reg[base].I = address
+#define WRITEBACK_POSTDEC reg[base].I = address - offset
+#define WRITEBACK_POSTINC reg[base].I = address + offset
+
+#define LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS) \
+ if (busPrefetchCount == 0) \
+ busPrefetch = busPrefetchEnable; \
+ int dest = (opcode >> 12) & 15; \
+ int base = (opcode >> 16) & 15; \
+ CALC_OFFSET; \
+ u32 address = CALC_ADDRESS;
+
+#define STR(CALC_OFFSET, CALC_ADDRESS, STORE_DATA, WRITEBACK1, WRITEBACK2, SIZE) \
+ LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \
+ WRITEBACK1; \
+ STORE_DATA; \
+ WRITEBACK2; \
+ clockTicks = 2 + dataTicksAccess##SIZE(address) \
+ + codeTicksAccess32(armNextPC);
+#define LDR(CALC_OFFSET, CALC_ADDRESS, LOAD_DATA, WRITEBACK, SIZE) \
+ LDRSTR_INIT(CALC_OFFSET, CALC_ADDRESS); \
+ LOAD_DATA; \
+ if (dest != base) \
+ WRITEBACK; \
+ clockTicks = 0; \
+ if (dest == 15) { \
+ reg[15].I &= 0xFFFFFFFC; \
+ armNextPC = reg[15].I; \
+ reg[15].I += 4; \
+ ARM_PREFETCH; \
+ clockTicks += 2 + dataTicksAccessSeq32(address) \
+ + dataTicksAccessSeq32(address);\
+ } \
+ clockTicks += 3 + dataTicksAccess##SIZE(address) \
+ + codeTicksAccess32(armNextPC);
+#define STR_POSTDEC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTDEC, SIZE)
+#define STR_POSTINC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_POST, STORE_DATA, WRITEBACK_NONE, WRITEBACK_POSTINC, SIZE)
+#define STR_PREDEC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE)
+#define STR_PREDEC_WB(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREDEC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE)
+#define STR_PREINC(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_NONE, WRITEBACK_NONE, SIZE)
+#define STR_PREINC_WB(CALC_OFFSET, STORE_DATA, SIZE) \
+ STR(CALC_OFFSET, ADDRESS_PREINC, STORE_DATA, WRITEBACK_PRE, WRITEBACK_NONE, SIZE)
+#define LDR_POSTDEC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTDEC, SIZE)
+#define LDR_POSTINC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_POST, LOAD_DATA, WRITEBACK_POSTINC, SIZE)
+#define LDR_PREDEC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_NONE, SIZE)
+#define LDR_PREDEC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREDEC, LOAD_DATA, WRITEBACK_PRE, SIZE)
+#define LDR_PREINC(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_NONE, SIZE)
+#define LDR_PREINC_WB(CALC_OFFSET, LOAD_DATA, SIZE) \
+ LDR(CALC_OFFSET, ADDRESS_PREINC, LOAD_DATA, WRITEBACK_PRE, SIZE)
+
+// STRH Rd, [Rn], -Rm
+static INSN_REGPARM void arm00B(u32 opcode) { STR_POSTDEC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn], #-offset
+static INSN_REGPARM void arm04B(u32 opcode) { STR_POSTDEC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn], Rm
+static INSN_REGPARM void arm08B(u32 opcode) { STR_POSTINC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn], #offset
+static INSN_REGPARM void arm0CB(u32 opcode) { STR_POSTINC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, -Rm]
+static INSN_REGPARM void arm10B(u32 opcode) { STR_PREDEC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm12B(u32 opcode) { STR_PREDEC_WB(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, -#offset]
+static INSN_REGPARM void arm14B(u32 opcode) { STR_PREDEC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm16B(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, Rm]
+static INSN_REGPARM void arm18B(u32 opcode) { STR_PREINC(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1AB(u32 opcode) { STR_PREINC_WB(OFFSET_REG, OP_STRH, 16); }
+// STRH Rd, [Rn, #offset]
+static INSN_REGPARM void arm1CB(u32 opcode) { STR_PREINC(OFFSET_IMM8, OP_STRH, 16); }
+// STRH Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1EB(u32 opcode) { STR_PREINC_WB(OFFSET_IMM8, OP_STRH, 16); }
+
+// LDRH Rd, [Rn], -Rm
+static INSN_REGPARM void arm01B(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn], #-offset
+static INSN_REGPARM void arm05B(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn], Rm
+static INSN_REGPARM void arm09B(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn], #offset
+static INSN_REGPARM void arm0DB(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -Rm]
+static INSN_REGPARM void arm11B(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm13B(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -#offset]
+static INSN_REGPARM void arm15B(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm17B(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, Rm]
+static INSN_REGPARM void arm19B(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1BB(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRH, 16); }
+// LDRH Rd, [Rn, #offset]
+static INSN_REGPARM void arm1DB(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRH, 16); }
+// LDRH Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1FB(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRH, 16); }
+
+// LDRSB Rd, [Rn], -Rm
+static INSN_REGPARM void arm01D(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn], #-offset
+static INSN_REGPARM void arm05D(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn], Rm
+static INSN_REGPARM void arm09D(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn], #offset
+static INSN_REGPARM void arm0DD(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -Rm]
+static INSN_REGPARM void arm11D(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm13D(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -#offset]
+static INSN_REGPARM void arm15D(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm17D(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, Rm]
+static INSN_REGPARM void arm19D(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1BD(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, #offset]
+static INSN_REGPARM void arm1DD(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSB, 16); }
+// LDRSB Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1FD(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSB, 16); }
+
+// LDRSH Rd, [Rn], -Rm
+static INSN_REGPARM void arm01F(u32 opcode) { LDR_POSTDEC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn], #-offset
+static INSN_REGPARM void arm05F(u32 opcode) { LDR_POSTDEC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn], Rm
+static INSN_REGPARM void arm09F(u32 opcode) { LDR_POSTINC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn], #offset
+static INSN_REGPARM void arm0DF(u32 opcode) { LDR_POSTINC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -Rm]
+static INSN_REGPARM void arm11F(u32 opcode) { LDR_PREDEC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -Rm]!
+static INSN_REGPARM void arm13F(u32 opcode) { LDR_PREDEC_WB(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -#offset]
+static INSN_REGPARM void arm15F(u32 opcode) { LDR_PREDEC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, -#offset]!
+static INSN_REGPARM void arm17F(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, Rm]
+static INSN_REGPARM void arm19F(u32 opcode) { LDR_PREINC(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, Rm]!
+static INSN_REGPARM void arm1BF(u32 opcode) { LDR_PREINC_WB(OFFSET_REG, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, #offset]
+static INSN_REGPARM void arm1DF(u32 opcode) { LDR_PREINC(OFFSET_IMM8, OP_LDRSH, 16); }
+// LDRSH Rd, [Rn, #offset]!
+static INSN_REGPARM void arm1FF(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM8, OP_LDRSH, 16); }
+
+// STR[T] Rd, [Rn], -#
+// Note: STR and STRT do the same thing on the GBA (likewise for LDR/LDRT etc)
+static INSN_REGPARM void arm400(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STR, 32); }
+// LDR[T] Rd, [Rn], -#
+static INSN_REGPARM void arm410(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], -#
+static INSN_REGPARM void arm440(u32 opcode) { STR_POSTDEC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], -#
+static INSN_REGPARM void arm450(u32 opcode) { LDR_POSTDEC(OFFSET_IMM, OP_LDRB, 16); }
+// STR[T] Rd, [Rn], #
+static INSN_REGPARM void arm480(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn], #
+static INSN_REGPARM void arm490(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], #
+static INSN_REGPARM void arm4C0(u32 opcode) { STR_POSTINC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], #
+static INSN_REGPARM void arm4D0(u32 opcode) { LDR_POSTINC(OFFSET_IMM, OP_LDRB, 16); }
+// STR Rd, [Rn, -#]
+static INSN_REGPARM void arm500(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, -#]
+static INSN_REGPARM void arm510(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDR, 32); }
+// STR Rd, [Rn, -#]!
+static INSN_REGPARM void arm520(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, -#]!
+static INSN_REGPARM void arm530(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDR, 32); }
+// STRB Rd, [Rn, -#]
+static INSN_REGPARM void arm540(u32 opcode) { STR_PREDEC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, -#]
+static INSN_REGPARM void arm550(u32 opcode) { LDR_PREDEC(OFFSET_IMM, OP_LDRB, 16); }
+// STRB Rd, [Rn, -#]!
+static INSN_REGPARM void arm560(u32 opcode) { STR_PREDEC_WB(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, -#]!
+static INSN_REGPARM void arm570(u32 opcode) { LDR_PREDEC_WB(OFFSET_IMM, OP_LDRB, 16); }
+// STR Rd, [Rn, #]
+static INSN_REGPARM void arm580(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, #]
+static INSN_REGPARM void arm590(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDR, 32); }
+// STR Rd, [Rn, #]!
+static INSN_REGPARM void arm5A0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STR, 32); }
+// LDR Rd, [Rn, #]!
+static INSN_REGPARM void arm5B0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDR, 32); }
+// STRB Rd, [Rn, #]
+static INSN_REGPARM void arm5C0(u32 opcode) { STR_PREINC(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, #]
+static INSN_REGPARM void arm5D0(u32 opcode) { LDR_PREINC(OFFSET_IMM, OP_LDRB, 16); }
+// STRB Rd, [Rn, #]!
+static INSN_REGPARM void arm5E0(u32 opcode) { STR_PREINC_WB(OFFSET_IMM, OP_STRB, 16); }
+// LDRB Rd, [Rn, #]!
+static INSN_REGPARM void arm5F0(u32 opcode) { LDR_PREINC_WB(OFFSET_IMM, OP_LDRB, 16); }
+
+// STR[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm600(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STR, 32); }
+// STR[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm602(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STR, 32); }
+// STR[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm604(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STR, 32); }
+// STR[T] Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm606(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STR, 32); }
+// LDR[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm610(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm612(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm614(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm616(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm640(u32 opcode) { STR_POSTDEC(OFFSET_LSL, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm642(u32 opcode) { STR_POSTDEC(OFFSET_LSR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm644(u32 opcode) { STR_POSTDEC(OFFSET_ASR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm646(u32 opcode) { STR_POSTDEC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], -Rm, LSL #
+static INSN_REGPARM void arm650(u32 opcode) { LDR_POSTDEC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], -Rm, LSR #
+static INSN_REGPARM void arm652(u32 opcode) { LDR_POSTDEC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], -Rm, ASR #
+static INSN_REGPARM void arm654(u32 opcode) { LDR_POSTDEC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn], -Rm, ROR #
+static INSN_REGPARM void arm656(u32 opcode) { LDR_POSTDEC(OFFSET_ROR, OP_LDRB, 16); }
+// STR[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm680(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STR, 32); }
+// STR[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm682(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STR, 32); }
+// STR[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm684(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STR, 32); }
+// STR[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm686(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STR, 32); }
+// LDR[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm690(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm692(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm694(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDR, 32); }
+// LDR[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm696(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDR, 32); }
+// STRB[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm6C0(u32 opcode) { STR_POSTINC(OFFSET_LSL, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm6C2(u32 opcode) { STR_POSTINC(OFFSET_LSR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm6C4(u32 opcode) { STR_POSTINC(OFFSET_ASR, OP_STRB, 16); }
+// STRB[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm6C6(u32 opcode) { STR_POSTINC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, LSL #
+static INSN_REGPARM void arm6D0(u32 opcode) { LDR_POSTINC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, LSR #
+static INSN_REGPARM void arm6D2(u32 opcode) { LDR_POSTINC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, ASR #
+static INSN_REGPARM void arm6D4(u32 opcode) { LDR_POSTINC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB[T] Rd, [Rn], Rm, ROR #
+static INSN_REGPARM void arm6D6(u32 opcode) { LDR_POSTINC(OFFSET_ROR, OP_LDRB, 16); }
+// STR Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm700(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm702(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm704(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm706(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm710(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm712(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm714(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm716(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDR, 32); }
+// STR Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm720(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm722(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm724(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm726(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm730(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm732(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm734(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm736(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDR, 32); }
+// STRB Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm740(u32 opcode) { STR_PREDEC(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm742(u32 opcode) { STR_PREDEC(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm744(u32 opcode) { STR_PREDEC(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm746(u32 opcode) { STR_PREDEC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSL #]
+static INSN_REGPARM void arm750(u32 opcode) { LDR_PREDEC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSR #]
+static INSN_REGPARM void arm752(u32 opcode) { LDR_PREDEC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ASR #]
+static INSN_REGPARM void arm754(u32 opcode) { LDR_PREDEC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ROR #]
+static INSN_REGPARM void arm756(u32 opcode) { LDR_PREDEC(OFFSET_ROR, OP_LDRB, 16); }
+// STRB Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm760(u32 opcode) { STR_PREDEC_WB(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm762(u32 opcode) { STR_PREDEC_WB(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm764(u32 opcode) { STR_PREDEC_WB(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm766(u32 opcode) { STR_PREDEC_WB(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSL #]!
+static INSN_REGPARM void arm770(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, LSR #]!
+static INSN_REGPARM void arm772(u32 opcode) { LDR_PREDEC_WB(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ASR #]!
+static INSN_REGPARM void arm774(u32 opcode) { LDR_PREDEC_WB(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, -Rm, ROR #]!
+static INSN_REGPARM void arm776(u32 opcode) { LDR_PREDEC_WB(OFFSET_ROR, OP_LDRB, 16); }
+// STR Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm780(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm782(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm784(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm786(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm790(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm792(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm794(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm796(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDR, 32); }
+// STR Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7A0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STR, 32); }
+// STR Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7A2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7A4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STR, 32); }
+// STR Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7A6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STR, 32); }
+// LDR Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7B0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7B2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7B4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDR, 32); }
+// LDR Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7B6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDR, 32); }
+// STRB Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm7C0(u32 opcode) { STR_PREINC(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm7C2(u32 opcode) { STR_PREINC(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm7C4(u32 opcode) { STR_PREINC(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm7C6(u32 opcode) { STR_PREINC(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, Rm, LSL #]
+static INSN_REGPARM void arm7D0(u32 opcode) { LDR_PREINC(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, LSR #]
+static INSN_REGPARM void arm7D2(u32 opcode) { LDR_PREINC(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ASR #]
+static INSN_REGPARM void arm7D4(u32 opcode) { LDR_PREINC(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ROR #]
+static INSN_REGPARM void arm7D6(u32 opcode) { LDR_PREINC(OFFSET_ROR, OP_LDRB, 16); }
+// STRB Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7E0(u32 opcode) { STR_PREINC_WB(OFFSET_LSL, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7E2(u32 opcode) { STR_PREINC_WB(OFFSET_LSR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7E4(u32 opcode) { STR_PREINC_WB(OFFSET_ASR, OP_STRB, 16); }
+// STRB Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7E6(u32 opcode) { STR_PREINC_WB(OFFSET_ROR, OP_STRB, 16); }
+// LDRB Rd, [Rn, Rm, LSL #]!
+static INSN_REGPARM void arm7F0(u32 opcode) { LDR_PREINC_WB(OFFSET_LSL, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, LSR #]!
+static INSN_REGPARM void arm7F2(u32 opcode) { LDR_PREINC_WB(OFFSET_LSR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ASR #]!
+static INSN_REGPARM void arm7F4(u32 opcode) { LDR_PREINC_WB(OFFSET_ASR, OP_LDRB, 16); }
+// LDRB Rd, [Rn, Rm, ROR #]!
+static INSN_REGPARM void arm7F6(u32 opcode) { LDR_PREINC_WB(OFFSET_ROR, OP_LDRB, 16); }
+
+// STM/LDM ////////////////////////////////////////////////////////////////
+
+#define STM_REG(bit,num) \
+ if (opcode & (1U<<(bit))) { \
+ CPUWriteMemory(address, reg[(num)].I); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ address += 4; \
+ }
+#define STMW_REG(bit,num) \
+ if (opcode & (1U<<(bit))) { \
+ CPUWriteMemory(address, reg[(num)].I); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ reg[base].I = temp; \
+ count++; \
+ address += 4; \
+ }
+#define LDM_REG(bit,num) \
+ if (opcode & (1U<<(bit))) { \
+ reg[(num)].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ address += 4; \
+ }
+#define STM_LOW(STORE_REG) \
+ STORE_REG(0, 0); \
+ STORE_REG(1, 1); \
+ STORE_REG(2, 2); \
+ STORE_REG(3, 3); \
+ STORE_REG(4, 4); \
+ STORE_REG(5, 5); \
+ STORE_REG(6, 6); \
+ STORE_REG(7, 7);
+#define STM_HIGH(STORE_REG) \
+ STORE_REG(8, 8); \
+ STORE_REG(9, 9); \
+ STORE_REG(10, 10); \
+ STORE_REG(11, 11); \
+ STORE_REG(12, 12); \
+ STORE_REG(13, 13); \
+ STORE_REG(14, 14);
+#define STM_HIGH_2(STORE_REG) \
+ if (armMode == 0x11) { \
+ STORE_REG(8, R8_FIQ); \
+ STORE_REG(9, R9_FIQ); \
+ STORE_REG(10, R10_FIQ); \
+ STORE_REG(11, R11_FIQ); \
+ STORE_REG(12, R12_FIQ); \
+ } else { \
+ STORE_REG(8, 8); \
+ STORE_REG(9, 9); \
+ STORE_REG(10, 10); \
+ STORE_REG(11, 11); \
+ STORE_REG(12, 12); \
+ } \
+ if (armMode != 0x10 && armMode != 0x1F) { \
+ STORE_REG(13, R13_USR); \
+ STORE_REG(14, R14_USR); \
+ } else { \
+ STORE_REG(13, 13); \
+ STORE_REG(14, 14); \
+ }
+#define STM_PC \
+ if (opcode & (1U<<15)) { \
+ CPUWriteMemory(address, reg[15].I+4); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ }
+#define STMW_PC \
+ if (opcode & (1U<<15)) { \
+ CPUWriteMemory(address, reg[15].I+4); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ reg[base].I = temp; \
+ count++; \
+ }
+#define LDM_LOW \
+ LDM_REG(0, 0); \
+ LDM_REG(1, 1); \
+ LDM_REG(2, 2); \
+ LDM_REG(3, 3); \
+ LDM_REG(4, 4); \
+ LDM_REG(5, 5); \
+ LDM_REG(6, 6); \
+ LDM_REG(7, 7);
+#define LDM_HIGH \
+ LDM_REG(8, 8); \
+ LDM_REG(9, 9); \
+ LDM_REG(10, 10); \
+ LDM_REG(11, 11); \
+ LDM_REG(12, 12); \
+ LDM_REG(13, 13); \
+ LDM_REG(14, 14);
+#define LDM_HIGH_2 \
+ if (armMode == 0x11) { \
+ LDM_REG(8, R8_FIQ); \
+ LDM_REG(9, R9_FIQ); \
+ LDM_REG(10, R10_FIQ); \
+ LDM_REG(11, R11_FIQ); \
+ LDM_REG(12, R12_FIQ); \
+ } else { \
+ LDM_REG(8, 8); \
+ LDM_REG(9, 9); \
+ LDM_REG(10, 10); \
+ LDM_REG(11, 11); \
+ LDM_REG(12, 12); \
+ } \
+ if (armMode != 0x10 && armMode != 0x1F) { \
+ LDM_REG(13, R13_USR); \
+ LDM_REG(14, R14_USR); \
+ } else { \
+ LDM_REG(13, 13); \
+ LDM_REG(14, 14); \
+ }
+#define STM_ALL \
+ STM_LOW(STM_REG); \
+ STM_HIGH(STM_REG); \
+ STM_PC;
+#define STMW_ALL \
+ STM_LOW(STMW_REG); \
+ STM_HIGH(STMW_REG); \
+ STMW_PC;
+#define LDM_ALL \
+ LDM_LOW; \
+ LDM_HIGH; \
+ if (opcode & (1U<<15)) { \
+ reg[15].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address);\
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address);\
+ } \
+ count++; \
+ } \
+ if (opcode & (1U<<15)) { \
+ armNextPC = reg[15].I; \
+ reg[15].I += 4; \
+ ARM_PREFETCH; \
+ clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\
+ }
+#define STM_ALL_2 \
+ STM_LOW(STM_REG); \
+ STM_HIGH_2(STM_REG); \
+ STM_PC;
+#define STMW_ALL_2 \
+ STM_LOW(STMW_REG); \
+ STM_HIGH_2(STMW_REG); \
+ STMW_PC;
+#define LDM_ALL_2 \
+ LDM_LOW; \
+ if (opcode & (1U<<15)) { \
+ LDM_HIGH; \
+ reg[15].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ } else { \
+ LDM_HIGH_2; \
+ }
+#define LDM_ALL_2B \
+ if (opcode & (1U<<15)) { \
+ CPUSwitchMode(reg[17].I & 0x1F, false); \
+ if (armState) { \
+ armNextPC = reg[15].I & 0xFFFFFFFC; \
+ reg[15].I = armNextPC + 4; \
+ ARM_PREFETCH; \
+ } else { \
+ armNextPC = reg[15].I & 0xFFFFFFFE; \
+ reg[15].I = armNextPC + 2; \
+ THUMB_PREFETCH; \
+ } \
+ clockTicks += 1 + codeTicksAccessSeq32(armNextPC);\
+ }
+
+
+// STMDA Rn, {Rlist}
+static INSN_REGPARM void arm800(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn, {Rlist}
+static INSN_REGPARM void arm810(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDA Rn!, {Rlist}
+static INSN_REGPARM void arm820(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp+4) & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn!, {Rlist}
+static INSN_REGPARM void arm830(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMDA Rn, {Rlist}^
+static INSN_REGPARM void arm840(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp+4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn, {Rlist}^
+static INSN_REGPARM void arm850(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDA Rn!, {Rlist}^
+static INSN_REGPARM void arm860(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp+4) & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDA Rn!, {Rlist}^
+static INSN_REGPARM void arm870(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (temp + 4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIA Rn, {Rlist}
+static INSN_REGPARM void arm880(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn, {Rlist}
+static INSN_REGPARM void arm890(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIA Rn!, {Rlist}
+static INSN_REGPARM void arm8A0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn!, {Rlist}
+static INSN_REGPARM void arm8B0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMIA Rn, {Rlist}^
+static INSN_REGPARM void arm8C0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn, {Rlist}^
+static INSN_REGPARM void arm8D0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIA Rn!, {Rlist}^
+static INSN_REGPARM void arm8E0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIA Rn!, {Rlist}^
+static INSN_REGPARM void arm8F0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = reg[base].I & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDB Rn, {Rlist}
+static INSN_REGPARM void arm900(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn, {Rlist}
+static INSN_REGPARM void arm910(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDB Rn!, {Rlist}
+static INSN_REGPARM void arm920(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn!, {Rlist}
+static INSN_REGPARM void arm930(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMDB Rn, {Rlist}^
+static INSN_REGPARM void arm940(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn, {Rlist}^
+static INSN_REGPARM void arm950(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMDB Rn!, {Rlist}^
+static INSN_REGPARM void arm960(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMDB Rn!, {Rlist}^
+static INSN_REGPARM void arm970(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I -
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = temp & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIB Rn, {Rlist}
+static INSN_REGPARM void arm980(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn, {Rlist}
+static INSN_REGPARM void arm990(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIB Rn!, {Rlist}
+static INSN_REGPARM void arm9A0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn!, {Rlist}
+static INSN_REGPARM void arm9B0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+}
+
+// STMIB Rn, {Rlist}^
+static INSN_REGPARM void arm9C0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ STM_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn, {Rlist}^
+static INSN_REGPARM void arm9D0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// STMIB Rn!, {Rlist}^
+static INSN_REGPARM void arm9E0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 0xFF] + cpuBitsSet[(opcode >> 8) & 255]);
+ STMW_ALL_2;
+ clockTicks += 1 + codeTicksAccess32(armNextPC);
+}
+
+// LDMIB Rn!, {Rlist}^
+static INSN_REGPARM void arm9F0(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int base = (opcode & 0x000F0000) >> 16;
+ u32 temp = reg[base].I +
+ 4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
+ u32 address = (reg[base].I+4) & 0xFFFFFFFC;
+ int count = 0;
+ LDM_ALL_2;
+ if (!(opcode & (1U << base)))
+ reg[base].I = temp;
+ LDM_ALL_2B;
+ clockTicks += 2 + codeTicksAccess32(armNextPC);
+}
+
+// B/BL/SWI and (unimplemented) coproc support ////////////////////////////
+
+// B
+static INSN_REGPARM void armA00(u32 opcode)
+{
+ int offset = opcode & 0x00FFFFFF;
+ if (offset & 0x00800000)
+ offset |= 0xFF000000; // negative offset
+ reg[15].I += offset<<2;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
+ clockTicks += 2 + codeTicksAccess32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC);
+ busPrefetchCount = 0;
+}
+
+// BL
+static INSN_REGPARM void armB00(u32 opcode)
+{
+ int offset = opcode & 0x00FFFFFF;
+ if (offset & 0x00800000)
+ offset |= 0xFF000000; // negative offset
+ reg[14].I = reg[15].I - 4;
+ reg[15].I += offset<<2;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
+ clockTicks += 2 + codeTicksAccess32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC);
+ busPrefetchCount = 0;
+}
+
+
+#ifdef GP_SUPPORT
+// MRC
+static INSN_REGPARM void armE01(u32 opcode)
+{
+}
+#else
+ #define armE01 armUnknownInsn
+#endif
+
+
+// SWI
+static INSN_REGPARM void armF00(u32 opcode)
+{
+ clockTicks = codeTicksAccessSeq32(armNextPC) + 1;
+ clockTicks += 2 + codeTicksAccess32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC);
+ busPrefetchCount = 0;
+ CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
+}
+
+// Instruction table //////////////////////////////////////////////////////
+
+typedef INSN_REGPARM void (*insnfunc_t)(u32 opcode);
+#define REP16(insn) \
+ insn,insn,insn,insn,insn,insn,insn,insn,\
+ insn,insn,insn,insn,insn,insn,insn,insn
+#define REP256(insn) \
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn),\
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn),\
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn),\
+ REP16(insn),REP16(insn),REP16(insn),REP16(insn)
+#define arm_UI armUnknownInsn
+#ifdef BKPT_SUPPORT
+ #define arm_BP armBreakpoint
+#else
+ #define arm_BP armUnknownInsn
+#endif
+static insnfunc_t armInsnTable[4096] = {
+ arm000,arm001,arm002,arm003,arm004,arm005,arm006,arm007, // 000
+ arm000,arm009,arm002,arm00B,arm004,arm_UI,arm006,arm_UI, // 008
+ arm010,arm011,arm012,arm013,arm014,arm015,arm016,arm017, // 010
+ arm010,arm019,arm012,arm01B,arm014,arm01D,arm016,arm01F, // 018
+ arm020,arm021,arm022,arm023,arm024,arm025,arm026,arm027, // 020
+ arm020,arm029,arm022,arm_UI,arm024,arm_UI,arm026,arm_UI, // 028
+ arm030,arm031,arm032,arm033,arm034,arm035,arm036,arm037, // 030
+ arm030,arm039,arm032,arm_UI,arm034,arm01D,arm036,arm01F, // 038
+ arm040,arm041,arm042,arm043,arm044,arm045,arm046,arm047, // 040
+ arm040,arm_UI,arm042,arm04B,arm044,arm_UI,arm046,arm_UI, // 048
+ arm050,arm051,arm052,arm053,arm054,arm055,arm056,arm057, // 050
+ arm050,arm_UI,arm052,arm05B,arm054,arm05D,arm056,arm05F, // 058
+ arm060,arm061,arm062,arm063,arm064,arm065,arm066,arm067, // 060
+ arm060,arm_UI,arm062,arm_UI,arm064,arm_UI,arm066,arm_UI, // 068
+ arm070,arm071,arm072,arm073,arm074,arm075,arm076,arm077, // 070
+ arm070,arm_UI,arm072,arm_UI,arm074,arm05D,arm076,arm05F, // 078
+ arm080,arm081,arm082,arm083,arm084,arm085,arm086,arm087, // 080
+ arm080,arm089,arm082,arm08B,arm084,arm_UI,arm086,arm_UI, // 088
+ arm090,arm091,arm092,arm093,arm094,arm095,arm096,arm097, // 090
+ arm090,arm099,arm092,arm09B,arm094,arm09D,arm096,arm09F, // 098
+ arm0A0,arm0A1,arm0A2,arm0A3,arm0A4,arm0A5,arm0A6,arm0A7, // 0A0
+ arm0A0,arm0A9,arm0A2,arm_UI,arm0A4,arm_UI,arm0A6,arm_UI, // 0A8
+ arm0B0,arm0B1,arm0B2,arm0B3,arm0B4,arm0B5,arm0B6,arm0B7, // 0B0
+ arm0B0,arm0B9,arm0B2,arm_UI,arm0B4,arm09D,arm0B6,arm09F, // 0B8
+ arm0C0,arm0C1,arm0C2,arm0C3,arm0C4,arm0C5,arm0C6,arm0C7, // 0C0
+ arm0C0,arm0C9,arm0C2,arm0CB,arm0C4,arm_UI,arm0C6,arm_UI, // 0C8
+ arm0D0,arm0D1,arm0D2,arm0D3,arm0D4,arm0D5,arm0D6,arm0D7, // 0D0
+ arm0D0,arm0D9,arm0D2,arm0DB,arm0D4,arm0DD,arm0D6,arm0DF, // 0D8
+ arm0E0,arm0E1,arm0E2,arm0E3,arm0E4,arm0E5,arm0E6,arm0E7, // 0E0
+ arm0E0,arm0E9,arm0E2,arm_UI,arm0E4,arm_UI,arm0E6,arm_UI, // 0E8
+ arm0F0,arm0F1,arm0F2,arm0F3,arm0F4,arm0F5,arm0F6,arm0F7, // 0F0
+ arm0F0,arm0F9,arm0F2,arm_UI,arm0F4,arm0DD,arm0F6,arm0DF, // 0F8
+
+ arm100,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 100
+ arm_UI,arm109,arm_UI,arm10B,arm_UI,arm_UI,arm_UI,arm_UI, // 108
+ arm110,arm111,arm112,arm113,arm114,arm115,arm116,arm117, // 110
+ arm110,arm_UI,arm112,arm11B,arm114,arm11D,arm116,arm11F, // 118
+ arm120,arm121,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_BP, // 120
+ arm_UI,arm_UI,arm_UI,arm12B,arm_UI,arm_UI,arm_UI,arm_UI, // 128
+ arm130,arm131,arm132,arm133,arm134,arm135,arm136,arm137, // 130
+ arm130,arm_UI,arm132,arm13B,arm134,arm13D,arm136,arm13F, // 138
+ arm140,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 140
+ arm_UI,arm149,arm_UI,arm14B,arm_UI,arm_UI,arm_UI,arm_UI, // 148
+ arm150,arm151,arm152,arm153,arm154,arm155,arm156,arm157, // 150
+ arm150,arm_UI,arm152,arm15B,arm154,arm15D,arm156,arm15F, // 158
+ arm160,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI,arm_UI, // 160
+ arm_UI,arm_UI,arm_UI,arm16B,arm_UI,arm_UI,arm_UI,arm_UI, // 168
+ arm170,arm171,arm172,arm173,arm174,arm175,arm176,arm177, // 170
+ arm170,arm_UI,arm172,arm17B,arm174,arm17D,arm176,arm17F, // 178
+ arm180,arm181,arm182,arm183,arm184,arm185,arm186,arm187, // 180
+ arm180,arm_UI,arm182,arm18B,arm184,arm_UI,arm186,arm_UI, // 188
+ arm190,arm191,arm192,arm193,arm194,arm195,arm196,arm197, // 190
+ arm190,arm_UI,arm192,arm19B,arm194,arm19D,arm196,arm19F, // 198
+ arm1A0,arm1A1,arm1A2,arm1A3,arm1A4,arm1A5,arm1A6,arm1A7, // 1A0
+ arm1A0,arm_UI,arm1A2,arm1AB,arm1A4,arm_UI,arm1A6,arm_UI, // 1A8
+ arm1B0,arm1B1,arm1B2,arm1B3,arm1B4,arm1B5,arm1B6,arm1B7, // 1B0
+ arm1B0,arm_UI,arm1B2,arm1BB,arm1B4,arm1BD,arm1B6,arm1BF, // 1B8
+ arm1C0,arm1C1,arm1C2,arm1C3,arm1C4,arm1C5,arm1C6,arm1C7, // 1C0
+ arm1C0,arm_UI,arm1C2,arm1CB,arm1C4,arm_UI,arm1C6,arm_UI, // 1C8
+ arm1D0,arm1D1,arm1D2,arm1D3,arm1D4,arm1D5,arm1D6,arm1D7, // 1D0
+ arm1D0,arm_UI,arm1D2,arm1DB,arm1D4,arm1DD,arm1D6,arm1DF, // 1D8
+ arm1E0,arm1E1,arm1E2,arm1E3,arm1E4,arm1E5,arm1E6,arm1E7, // 1E0
+ arm1E0,arm_UI,arm1E2,arm1EB,arm1E4,arm_UI,arm1E6,arm_UI, // 1E8
+ arm1F0,arm1F1,arm1F2,arm1F3,arm1F4,arm1F5,arm1F6,arm1F7, // 1F0
+ arm1F0,arm_UI,arm1F2,arm1FB,arm1F4,arm1FD,arm1F6,arm1FF, // 1F8
+
+ REP16(arm200),REP16(arm210),REP16(arm220),REP16(arm230), // 200
+ REP16(arm240),REP16(arm250),REP16(arm260),REP16(arm270), // 240
+ REP16(arm280),REP16(arm290),REP16(arm2A0),REP16(arm2B0), // 280
+ REP16(arm2C0),REP16(arm2D0),REP16(arm2E0),REP16(arm2F0), // 2C0
+ REP16(arm_UI),REP16(arm310),REP16(arm320),REP16(arm330), // 300
+ REP16(arm_UI),REP16(arm350),REP16(arm360),REP16(arm370), // 340
+ REP16(arm380),REP16(arm390),REP16(arm3A0),REP16(arm3B0), // 380
+ REP16(arm3C0),REP16(arm3D0),REP16(arm3E0),REP16(arm3F0), // 3C0
+
+ REP16(arm400),REP16(arm410),REP16(arm400),REP16(arm410), // 400
+ REP16(arm440),REP16(arm450),REP16(arm440),REP16(arm450), // 440
+ REP16(arm480),REP16(arm490),REP16(arm480),REP16(arm490), // 480
+ REP16(arm4C0),REP16(arm4D0),REP16(arm4C0),REP16(arm4D0), // 4C0
+ REP16(arm500),REP16(arm510),REP16(arm520),REP16(arm530), // 500
+ REP16(arm540),REP16(arm550),REP16(arm560),REP16(arm570), // 540
+ REP16(arm580),REP16(arm590),REP16(arm5A0),REP16(arm5B0), // 580
+ REP16(arm5C0),REP16(arm5D0),REP16(arm5E0),REP16(arm5F0), // 5C0
+
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 600
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 608
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 610
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 618
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 620
+ arm600,arm_UI,arm602,arm_UI,arm604,arm_UI,arm606,arm_UI, // 628
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 630
+ arm610,arm_UI,arm612,arm_UI,arm614,arm_UI,arm616,arm_UI, // 638
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 640
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 648
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 650
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 658
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 660
+ arm640,arm_UI,arm642,arm_UI,arm644,arm_UI,arm646,arm_UI, // 668
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 670
+ arm650,arm_UI,arm652,arm_UI,arm654,arm_UI,arm656,arm_UI, // 678
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 680
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 688
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 690
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 698
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A0
+ arm680,arm_UI,arm682,arm_UI,arm684,arm_UI,arm686,arm_UI, // 6A8
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B0
+ arm690,arm_UI,arm692,arm_UI,arm694,arm_UI,arm696,arm_UI, // 6B8
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C0
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6C8
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D0
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6D8
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E0
+ arm6C0,arm_UI,arm6C2,arm_UI,arm6C4,arm_UI,arm6C6,arm_UI, // 6E8
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F0
+ arm6D0,arm_UI,arm6D2,arm_UI,arm6D4,arm_UI,arm6D6,arm_UI, // 6F8
+
+ arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 700
+ arm700,arm_UI,arm702,arm_UI,arm704,arm_UI,arm706,arm_UI, // 708
+ arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 710
+ arm710,arm_UI,arm712,arm_UI,arm714,arm_UI,arm716,arm_UI, // 718
+ arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 720
+ arm720,arm_UI,arm722,arm_UI,arm724,arm_UI,arm726,arm_UI, // 728
+ arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 730
+ arm730,arm_UI,arm732,arm_UI,arm734,arm_UI,arm736,arm_UI, // 738
+ arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 740
+ arm740,arm_UI,arm742,arm_UI,arm744,arm_UI,arm746,arm_UI, // 748
+ arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 750
+ arm750,arm_UI,arm752,arm_UI,arm754,arm_UI,arm756,arm_UI, // 758
+ arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 760
+ arm760,arm_UI,arm762,arm_UI,arm764,arm_UI,arm766,arm_UI, // 768
+ arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 770
+ arm770,arm_UI,arm772,arm_UI,arm774,arm_UI,arm776,arm_UI, // 778
+ arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 780
+ arm780,arm_UI,arm782,arm_UI,arm784,arm_UI,arm786,arm_UI, // 788
+ arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 790
+ arm790,arm_UI,arm792,arm_UI,arm794,arm_UI,arm796,arm_UI, // 798
+ arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A0
+ arm7A0,arm_UI,arm7A2,arm_UI,arm7A4,arm_UI,arm7A6,arm_UI, // 7A8
+ arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B0
+ arm7B0,arm_UI,arm7B2,arm_UI,arm7B4,arm_UI,arm7B6,arm_UI, // 7B8
+ arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C0
+ arm7C0,arm_UI,arm7C2,arm_UI,arm7C4,arm_UI,arm7C6,arm_UI, // 7C8
+ arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D0
+ arm7D0,arm_UI,arm7D2,arm_UI,arm7D4,arm_UI,arm7D6,arm_UI, // 7D8
+ arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E0
+ arm7E0,arm_UI,arm7E2,arm_UI,arm7E4,arm_UI,arm7E6,arm_UI, // 7E8
+ arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_UI, // 7F0
+ arm7F0,arm_UI,arm7F2,arm_UI,arm7F4,arm_UI,arm7F6,arm_BP, // 7F8
+
+ REP16(arm800),REP16(arm810),REP16(arm820),REP16(arm830), // 800
+ REP16(arm840),REP16(arm850),REP16(arm860),REP16(arm870), // 840
+ REP16(arm880),REP16(arm890),REP16(arm8A0),REP16(arm8B0), // 880
+ REP16(arm8C0),REP16(arm8D0),REP16(arm8E0),REP16(arm8F0), // 8C0
+ REP16(arm900),REP16(arm910),REP16(arm920),REP16(arm930), // 900
+ REP16(arm940),REP16(arm950),REP16(arm960),REP16(arm970), // 940
+ REP16(arm980),REP16(arm990),REP16(arm9A0),REP16(arm9B0), // 980
+ REP16(arm9C0),REP16(arm9D0),REP16(arm9E0),REP16(arm9F0), // 9C0
+
+ REP256(armA00), // A00
+ REP256(armB00), // B00
+ REP256(arm_UI), // C00
+ REP256(arm_UI), // D00
+
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E00
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E08
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E10
+ arm_UI,armE01,arm_UI,armE01,arm_UI,armE01,arm_UI,armE01, // E18
+ REP16(arm_UI), // E20
+ REP16(arm_UI), // E30
+ REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E40
+ REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // E80
+ REP16(arm_UI),REP16(arm_UI),REP16(arm_UI),REP16(arm_UI), // EC0
+
+ REP256(armF00), // F00
+};
+
+// Wrapper routine (execution loop) ///////////////////////////////////////
+
+#include
+static void tester(void) {
+ static int ran=0;if(ran)return;ran=1;
+ FILE*f=fopen("p:\\timing.txt","w");if(!f)return;
+ for (int op=/*0*/9; op*0xF00*/10;op++){if(armInsnTable[op]==arm_UI)continue;
+ int i;for(i=0;i> 28;
+ bool cond_res = true;
+ if (UNLIKELY(cond != 0x0E)) { // most opcodes are AL (always)
+ switch(cond) {
+ case 0x00: // EQ
+ cond_res = Z_FLAG;
+ break;
+ case 0x01: // NE
+ cond_res = !Z_FLAG;
+ break;
+ case 0x02: // CS
+ cond_res = C_FLAG;
+ break;
+ case 0x03: // CC
+ cond_res = !C_FLAG;
+ break;
+ case 0x04: // MI
+ cond_res = N_FLAG;
+ break;
+ case 0x05: // PL
+ cond_res = !N_FLAG;
+ break;
+ case 0x06: // VS
+ cond_res = V_FLAG;
+ break;
+ case 0x07: // VC
+ cond_res = !V_FLAG;
+ break;
+ case 0x08: // HI
+ cond_res = C_FLAG && !Z_FLAG;
+ break;
+ case 0x09: // LS
+ cond_res = !C_FLAG || Z_FLAG;
+ break;
+ case 0x0A: // GE
+ cond_res = N_FLAG == V_FLAG;
+ break;
+ case 0x0B: // LT
+ cond_res = N_FLAG != V_FLAG;
+ break;
+ case 0x0C: // GT
+ cond_res = !Z_FLAG &&(N_FLAG == V_FLAG);
+ break;
+ case 0x0D: // LE
+ cond_res = Z_FLAG || (N_FLAG != V_FLAG);
+ break;
+ case 0x0E: // AL (impossible, checked above)
+ cond_res = true;
+ break;
+ case 0x0F:
+ default:
+ // ???
+ cond_res = false;
+ break;
+ }
+ }
+
+ if (cond_res)
+ (*armInsnTable[((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F)])(opcode);
+#ifdef INSN_COUNTER
+ count(opcode, cond_res);
+#endif
+ if (clockTicks < 0)
+ return 0;
+ if (clockTicks == 0)
+ clockTicks = 1 + codeTicksAccessSeq32(oldArmNextPC);
+ cpuTotalTicks += clockTicks;
+
+ } while (cpuTotalTicks
+#include
+#include
+#include
+#include
+
+#include "GBA.h"
+#include "GBAcpu.h"
+#include "GBAinline.h"
+#include "Globals.h"
+#include "Gfx.h"
+#include "EEprom.h"
+#include "Flash.h"
+#include "Sound.h"
+#include "Sram.h"
+#include "bios.h"
+#include "unzip.h"
+#include "Cheats.h"
+#include "NLS.h"
+#include "elf.h"
+#include "Util.h"
+#include "Port.h"
+#include "agbprint.h"
+#ifdef PROFILING
+#include "prof/prof.h"
+#endif
+
+#define snprintf _snprintf
+
+///////////////////////////////////////////////////////////////////////////
+
+static int clockTicks;
+
+static INSN_REGPARM void thumbUnknownInsn(u32 opcode)
+{
+#ifdef DEV_VERSION
+ if(systemVerbose & VERBOSE_UNDEFINED)
+ log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2);
+#endif
+ CPUUndefinedException();
+}
+
+#ifdef BKPT_SUPPORT
+static INSN_REGPARM void thumbBreakpoint(u32 opcode)
+{
+ extern void (*dbgSignal)(int,int);
+ reg[15].I -= 2;
+ armNextPC -= 2;
+ dbgSignal(5, opcode & 255);
+ clockTicks = -1;
+}
+#endif
+
+// Common macros //////////////////////////////////////////////////////////
+
+#ifdef BKPT_SUPPORT
+# define THUMB_CONSOLE_OUTPUT(a,b) do { \
+ if ((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) { \
+ extern void (*dbgOutput)(const char *, u32); \
+ dbgOutput((a), (b)); \
+ } \
+} while (0)
+# define UPDATE_OLDREG do { \
+ if (debugger_last) { \
+ snprintf(oldbuffer, sizeof(oldbuffer), "%08X", \
+ armState ? reg[15].I - 4 : reg[15].I - 2); \
+ int i; \
+ for (i = 0; i < 18; i++) { \
+ oldreg[i] = reg[i].I; \
+ } \
+ } \
+} while (0)
+#else
+# define THUMB_CONSOLE_OUTPUT(a,b)
+# define UPDATE_OLDREG
+#endif
+
+#define NEG(i) ((i) >> 31)
+#define POS(i) ((~(i)) >> 31)
+
+#ifndef C_CORE
+#ifdef __GNUC__
+#ifdef __POWERPC__
+ #define ADD_RD_RS_RN(N) \
+ { \
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (reg[N].I) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define ADD_RD_RS_O3(N) \
+ { \
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (N) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define ADD_RD_RS_O3_0 ADD_RD_RS_O3
+ #define ADD_RN_O8(d) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[(d)].I), \
+ "r" (opcode & 255) \
+ ); \
+ reg[(d)].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define CMN_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("addco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define ADC_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "addeo. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SUB_RD_RS_RN(N) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (reg[N].I) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SUB_RD_RS_O3(N) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (N) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SUB_RD_RS_O3_0 SUB_RD_RS_O3
+ #define SUB_RN_O8(d) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[(d)].I), \
+ "r" (opcode & 255) \
+ ); \
+ reg[(d)].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define CMP_RN_O8(d) \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[(d)].I), \
+ "r" (opcode & 255) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define SBC_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("mtspr xer, %4\n" \
+ "subfeo. %0, %3, %2\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value), \
+ "r" (C_FLAG << 29) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define NEG_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subfco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[source].I), \
+ "r" (0) \
+ ); \
+ reg[dest].I = Result; \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+ #define CMP_RD_RS \
+ {\
+ register int Flags; \
+ register int Result; \
+ asm volatile("subco. %0, %2, %3\n" \
+ "mcrxr cr1\n" \
+ "mfcr %1\n" \
+ : "=r" (Result), \
+ "=r" (Flags) \
+ : "r" (reg[dest].I), \
+ "r" (value) \
+ ); \
+ Z_FLAG = (Flags >> 29) & 1; \
+ N_FLAG = (Flags >> 31) & 1; \
+ C_FLAG = (Flags >> 25) & 1; \
+ V_FLAG = (Flags >> 26) & 1; \
+ }
+#else
+ #define ADD_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "addl %%eax, %0;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setcb C_FLAG;"\
+ "setob V_FLAG;"\
+ : "=m" (reg[(d)].I));
+ #define CMN_RD_RS \
+ asm ("add %0, %1;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setcb C_FLAG;"\
+ "setob V_FLAG;"\
+ : \
+ : "r" (value), "r" (reg[dest].I):"1");
+ #define ADC_RD_RS \
+ asm ("bt $0, C_FLAG;"\
+ "adc %1, %%ebx;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setcb C_FLAG;"\
+ "setob V_FLAG;"\
+ : "=b" (reg[dest].I)\
+ : "r" (value), "b" (reg[dest].I));
+ #define SUB_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "subl %%eax, %0;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setncb C_FLAG;"\
+ "setob V_FLAG;"\
+ : "=m" (reg[(d)].I));
+ #define MOV_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "movb $0, N_FLAG;"\
+ "movl %%eax, %0;"\
+ "setzb Z_FLAG;"\
+ : "=m" (reg[(d)].I));
+ #define CMP_RN_O8(d) \
+ asm ("andl $0xFF, %%eax;"\
+ "cmpl %%eax, %0;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setncb C_FLAG;"\
+ "setob V_FLAG;"\
+ : \
+ : "m" (reg[(d)].I));
+ #define SBC_RD_RS \
+ asm volatile ("bt $0, C_FLAG;"\
+ "cmc;"\
+ "sbb %1, %%ebx;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setncb C_FLAG;"\
+ "setob V_FLAG;"\
+ : "=b" (reg[dest].I)\
+ : "r" (value), "b" (reg[dest].I) : "cc", "memory");
+ #define LSL_RD_RS \
+ asm ("shl %%cl, %%eax;"\
+ "setcb C_FLAG;"\
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define LSR_RD_RS \
+ asm ("shr %%cl, %%eax;"\
+ "setcb C_FLAG;"\
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define ASR_RD_RS \
+ asm ("sar %%cl, %%eax;"\
+ "setcb C_FLAG;"\
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define ROR_RD_RS \
+ asm ("ror %%cl, %%eax;"\
+ "setcb C_FLAG;"\
+ : "=a" (value)\
+ : "a" (reg[dest].I), "c" (value));
+ #define NEG_RD_RS \
+ asm ("neg %%ebx;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setncb C_FLAG;"\
+ "setob V_FLAG;"\
+ : "=b" (reg[dest].I)\
+ : "b" (reg[source].I));
+ #define CMP_RD_RS \
+ asm ("sub %0, %1;"\
+ "setsb N_FLAG;"\
+ "setzb Z_FLAG;"\
+ "setncb C_FLAG;"\
+ "setob V_FLAG;"\
+ : \
+ : "r" (value), "r" (reg[dest].I):"1");
+ #define IMM5_INSN(OP,N) \
+ asm("movl %%eax,%%ecx;" \
+ "shrl $1,%%eax;" \
+ "andl $7,%%ecx;" \
+ "andl $0x1C,%%eax;" \
+ "movl reg(%%eax),%%edx;" \
+ OP \
+ "setsb N_FLAG;" \
+ "setzb Z_FLAG;" \
+ "movl %%edx,reg(,%%ecx,4);" \
+ : : "i" (N))
+ #define IMM5_INSN_0(OP) \
+ asm("movl %%eax,%%ecx;" \
+ "shrl $1,%%eax;" \
+ "andl $7,%%ecx;" \
+ "andl $0x1C,%%eax;" \
+ "movl reg(%%eax),%%edx;" \
+ OP \
+ "setsb N_FLAG;" \
+ "setzb Z_FLAG;" \
+ "movl %%edx,reg(,%%ecx,4);" \
+ : : )
+ #define IMM5_LSL \
+ "shll %0,%%edx;"\
+ "setcb C_FLAG;"
+ #define IMM5_LSL_0 \
+ "testl %%edx,%%edx;"
+ #define IMM5_LSR \
+ "shrl %0,%%edx;"\
+ "setcb C_FLAG;"
+ #define IMM5_LSR_0 \
+ "testl %%edx,%%edx;"\
+ "setsb C_FLAG;"\
+ "xorl %%edx,%%edx;"
+ #define IMM5_ASR \
+ "sarl %0,%%edx;"\
+ "setcb C_FLAG;"
+ #define IMM5_ASR_0 \
+ "sarl $31,%%edx;"\
+ "setsb C_FLAG;"
+ #define THREEARG_INSN(OP,N) \
+ asm("movl %%eax,%%edx;" \
+ "shrl $1,%%edx;" \
+ "andl $0x1C,%%edx;" \
+ "andl $7,%%eax;" \
+ "movl reg(%%edx),%%ecx;" \
+ OP(N) \
+ "setsb N_FLAG;" \
+ "setzb Z_FLAG;" \
+ "movl %%ecx,reg(,%%eax,4)"::)
+ #define ADD_RD_RS_RN(N) \
+ "add (reg+"#N"*4),%%ecx;" \
+ "setcb C_FLAG;" \
+ "setob V_FLAG;"
+ #define ADD_RD_RS_O3(N) \
+ "add $"#N",%%ecx;" \
+ "setcb C_FLAG;" \
+ "setob V_FLAG;"
+ #define ADD_RD_RS_O3_0(N) \
+ "movb $0,C_FLAG;" \
+ "add $0,%%ecx;" \
+ "movb $0,V_FLAG;"
+ #define SUB_RD_RS_RN(N) \
+ "sub (reg+"#N"*4),%%ecx;" \
+ "setncb C_FLAG;" \
+ "setob V_FLAG;"
+ #define SUB_RD_RS_O3(N) \
+ "sub $"#N",%%ecx;" \
+ "setncb C_FLAG;" \
+ "setob V_FLAG;"
+ #define SUB_RD_RS_O3_0(N) \
+ "movb $1,C_FLAG;" \
+ "sub $0,%%ecx;" \
+ "movb $0,V_FLAG;"
+#endif
+#else // !__GNUC__
+ #define ADD_RD_RS_RN(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, dword ptr [OFFSET reg+4*N]\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define ADD_RD_RS_O3(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, N\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define ADD_RD_RS_O3_0 \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, 0\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm mov byte ptr C_FLAG, 0\
+ __asm mov byte ptr V_FLAG, 0\
+ }
+ #define ADD_RN_O8(d) \
+ {\
+ __asm mov ebx, opcode\
+ __asm and ebx, 255\
+ __asm add dword ptr [OFFSET reg+4*(d)], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define CMN_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm add ebx, value\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define ADC_RD_RS \
+ {\
+ __asm mov ebx, dest\
+ __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
+ __asm bt word ptr C_FLAG, 0\
+ __asm adc ebx, value\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SUB_RD_RS_RN(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, dword ptr [OFFSET reg+4*N]\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SUB_RD_RS_O3(N) \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, N\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SUB_RD_RS_O3_0 \
+ {\
+ __asm mov eax, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, 0\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm mov byte ptr C_FLAG, 1\
+ __asm mov byte ptr V_FLAG, 0\
+ }
+ #define SUB_RN_O8(d) \
+ {\
+ __asm mov ebx, opcode\
+ __asm and ebx, 255\
+ __asm sub dword ptr [OFFSET reg + 4*(d)], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define MOV_RN_O8(d) \
+ {\
+ __asm mov eax, opcode\
+ __asm and eax, 255\
+ __asm mov dword ptr [OFFSET reg+4*(d)], eax\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ }
+ #define CMP_RN_O8(d) \
+ {\
+ __asm mov eax, dword ptr [OFFSET reg+4*(d)]\
+ __asm mov ebx, opcode\
+ __asm and ebx, 255\
+ __asm sub eax, ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define SBC_RD_RS \
+ {\
+ __asm mov ebx, dest\
+ __asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\
+ __asm mov eax, value\
+ __asm bt word ptr C_FLAG, 0\
+ __asm cmc\
+ __asm sbb ebx, eax\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg + 4*eax], ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define LSL_RD_RM_I5 \
+ {\
+ __asm mov eax, source\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr shift\
+ __asm shl eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define LSL_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr value\
+ __asm shl eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define LSR_RD_RM_I5 \
+ {\
+ __asm mov eax, source\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr shift\
+ __asm shr eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define LSR_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
+ __asm mov cl, byte ptr value\
+ __asm shr eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define ASR_RD_RM_I5 \
+ {\
+ __asm mov eax, source\
+ __asm mov eax, dword ptr [OFFSET reg + 4*eax]\
+ __asm mov cl, byte ptr shift\
+ __asm sar eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define ASR_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4*eax]\
+ __asm mov cl, byte ptr value\
+ __asm sar eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define ROR_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov eax, dword ptr [OFFSET reg + 4*eax]\
+ __asm mov cl, byte ptr value\
+ __asm ror eax, cl\
+ __asm mov value, eax\
+ __asm setc byte ptr C_FLAG\
+ }
+ #define NEG_RD_RS \
+ {\
+ __asm mov ebx, source\
+ __asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
+ __asm neg ebx\
+ __asm mov eax, dest\
+ __asm mov dword ptr [OFFSET reg+4*eax],ebx\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+ #define CMP_RD_RS \
+ {\
+ __asm mov eax, dest\
+ __asm mov ebx, dword ptr [OFFSET reg+4*eax]\
+ __asm sub ebx, value\
+ __asm sets byte ptr N_FLAG\
+ __asm setz byte ptr Z_FLAG\
+ __asm setnc byte ptr C_FLAG\
+ __asm seto byte ptr V_FLAG\
+ }
+#endif
+#endif
+
+// C core
+#ifndef ADDCARRY
+ #define ADDCARRY(a, b, c) \
+ C_FLAG = ((NEG(a) & NEG(b)) |\
+ (NEG(a) & POS(c)) |\
+ (NEG(b) & POS(c))) ? true : false;
+#endif
+#ifndef ADDOVERFLOW
+ #define ADDOVERFLOW(a, b, c) \
+ V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\
+ (POS(a) & POS(b) & NEG(c))) ? true : false;
+#endif
+#ifndef SUBCARRY
+ #define SUBCARRY(a, b, c) \
+ C_FLAG = ((NEG(a) & POS(b)) |\
+ (NEG(a) & POS(c)) |\
+ (POS(b) & POS(c))) ? true : false;
+#endif
+#ifndef SUBOVERFLOW
+ #define SUBOVERFLOW(a, b, c)\
+ V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\
+ (POS(a) & NEG(b) & NEG(c))) ? true : false;
+#endif
+#ifndef ADD_RD_RS_RN
+ #define ADD_RD_RS_RN(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = reg[N].I;\
+ u32 res = lhs + rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef ADD_RD_RS_O3
+ #define ADD_RD_RS_O3(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = N;\
+ u32 res = lhs + rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef ADD_RD_RS_O3_0
+# define ADD_RD_RS_O3_0 ADD_RD_RS_O3
+#endif
+#ifndef ADD_RN_O8
+ #define ADD_RN_O8(d) \
+ {\
+ u32 lhs = reg[(d)].I;\
+ u32 rhs = (opcode & 255);\
+ u32 res = lhs + rhs;\
+ reg[(d)].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef CMN_RD_RS
+ #define CMN_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs + rhs;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef ADC_RD_RS
+ #define ADC_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs + rhs + (u32)C_FLAG;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ ADDCARRY(lhs, rhs, res);\
+ ADDOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SUB_RD_RS_RN
+ #define SUB_RD_RS_RN(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = reg[N].I;\
+ u32 res = lhs - rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SUB_RD_RS_O3
+ #define SUB_RD_RS_O3(N) \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = N;\
+ u32 res = lhs - rhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SUB_RD_RS_O3_0
+# define SUB_RD_RS_O3_0 SUB_RD_RS_O3
+#endif
+#ifndef SUB_RN_O8
+ #define SUB_RN_O8(d) \
+ {\
+ u32 lhs = reg[(d)].I;\
+ u32 rhs = (opcode & 255);\
+ u32 res = lhs - rhs;\
+ reg[(d)].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef MOV_RN_O8
+ #define MOV_RN_O8(d) \
+ {\
+ reg[d].I = opcode & 255;\
+ N_FLAG = false;\
+ Z_FLAG = (reg[d].I ? false : true);\
+ }
+#endif
+#ifndef CMP_RN_O8
+ #define CMP_RN_O8(d) \
+ {\
+ u32 lhs = reg[(d)].I;\
+ u32 rhs = (opcode & 255);\
+ u32 res = lhs - rhs;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef SBC_RD_RS
+ #define SBC_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs - rhs - !((u32)C_FLAG);\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef LSL_RD_RM_I5
+ #define LSL_RD_RM_I5 \
+ {\
+ C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\
+ value = reg[source].I << shift;\
+ }
+#endif
+#ifndef LSL_RD_RS
+ #define LSL_RD_RS \
+ {\
+ C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\
+ value = reg[dest].I << value;\
+ }
+#endif
+#ifndef LSR_RD_RM_I5
+ #define LSR_RD_RM_I5 \
+ {\
+ C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\
+ value = reg[source].I >> shift;\
+ }
+#endif
+#ifndef LSR_RD_RS
+ #define LSR_RD_RS \
+ {\
+ C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
+ value = reg[dest].I >> value;\
+ }
+#endif
+#ifndef ASR_RD_RM_I5
+ #define ASR_RD_RM_I5 \
+ {\
+ C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\
+ value = (s32)reg[source].I >> (int)shift;\
+ }
+#endif
+#ifndef ASR_RD_RS
+ #define ASR_RD_RS \
+ {\
+ C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\
+ value = (s32)reg[dest].I >> (int)value;\
+ }
+#endif
+#ifndef ROR_RD_RS
+ #define ROR_RD_RS \
+ {\
+ C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
+ value = ((reg[dest].I << (32 - value)) |\
+ (reg[dest].I >> value));\
+ }
+#endif
+#ifndef NEG_RD_RS
+ #define NEG_RD_RS \
+ {\
+ u32 lhs = reg[source].I;\
+ u32 rhs = 0;\
+ u32 res = rhs - lhs;\
+ reg[dest].I = res;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(rhs, lhs, res);\
+ SUBOVERFLOW(rhs, lhs, res);\
+ }
+#endif
+#ifndef CMP_RD_RS
+ #define CMP_RD_RS \
+ {\
+ u32 lhs = reg[dest].I;\
+ u32 rhs = value;\
+ u32 res = lhs - rhs;\
+ Z_FLAG = (res == 0) ? true : false;\
+ N_FLAG = NEG(res) ? true : false;\
+ SUBCARRY(lhs, rhs, res);\
+ SUBOVERFLOW(lhs, rhs, res);\
+ }
+#endif
+#ifndef IMM5_INSN
+ #define IMM5_INSN(OP,N) \
+ int dest = opcode & 0x07;\
+ int source = (opcode >> 3) & 0x07;\
+ u32 value;\
+ OP(N);\
+ reg[dest].I = value;\
+ N_FLAG = (value & 0x80000000 ? true : false);\
+ Z_FLAG = (value ? false : true);
+ #define IMM5_INSN_0(OP) \
+ int dest = opcode & 0x07;\
+ int source = (opcode >> 3) & 0x07;\
+ u32 value;\
+ OP;\
+ reg[dest].I = value;\
+ N_FLAG = (value & 0x80000000 ? true : false);\
+ Z_FLAG = (value ? false : true);
+ #define IMM5_LSL(N) \
+ int shift = N;\
+ LSL_RD_RM_I5;
+ #define IMM5_LSL_0 \
+ value = reg[source].I;
+ #define IMM5_LSR(N) \
+ int shift = N;\
+ LSR_RD_RM_I5;
+ #define IMM5_LSR_0 \
+ C_FLAG = reg[source].I & 0x80000000 ? true : false;\
+ value = 0;
+ #define IMM5_ASR(N) \
+ int shift = N;\
+ ASR_RD_RM_I5;
+ #define IMM5_ASR_0 \
+ if(reg[source].I & 0x80000000) {\
+ value = 0xFFFFFFFF;\
+ C_FLAG = true;\
+ } else {\
+ value = 0;\
+ C_FLAG = false;\
+ }
+#endif
+#ifndef THREEARG_INSN
+ #define THREEARG_INSN(OP,N) \
+ int dest = opcode & 0x07; \
+ int source = (opcode >> 3) & 0x07; \
+ OP(N);
+#endif
+
+// Shift instructions /////////////////////////////////////////////////////
+
+#define DEFINE_IMM5_INSN(OP,BASE) \
+ static INSN_REGPARM void thumb##BASE##_00(u32 opcode) { IMM5_INSN_0(OP##_0); } \
+ static INSN_REGPARM void thumb##BASE##_01(u32 opcode) { IMM5_INSN(OP, 1); } \
+ static INSN_REGPARM void thumb##BASE##_02(u32 opcode) { IMM5_INSN(OP, 2); } \
+ static INSN_REGPARM void thumb##BASE##_03(u32 opcode) { IMM5_INSN(OP, 3); } \
+ static INSN_REGPARM void thumb##BASE##_04(u32 opcode) { IMM5_INSN(OP, 4); } \
+ static INSN_REGPARM void thumb##BASE##_05(u32 opcode) { IMM5_INSN(OP, 5); } \
+ static INSN_REGPARM void thumb##BASE##_06(u32 opcode) { IMM5_INSN(OP, 6); } \
+ static INSN_REGPARM void thumb##BASE##_07(u32 opcode) { IMM5_INSN(OP, 7); } \
+ static INSN_REGPARM void thumb##BASE##_08(u32 opcode) { IMM5_INSN(OP, 8); } \
+ static INSN_REGPARM void thumb##BASE##_09(u32 opcode) { IMM5_INSN(OP, 9); } \
+ static INSN_REGPARM void thumb##BASE##_0A(u32 opcode) { IMM5_INSN(OP,10); } \
+ static INSN_REGPARM void thumb##BASE##_0B(u32 opcode) { IMM5_INSN(OP,11); } \
+ static INSN_REGPARM void thumb##BASE##_0C(u32 opcode) { IMM5_INSN(OP,12); } \
+ static INSN_REGPARM void thumb##BASE##_0D(u32 opcode) { IMM5_INSN(OP,13); } \
+ static INSN_REGPARM void thumb##BASE##_0E(u32 opcode) { IMM5_INSN(OP,14); } \
+ static INSN_REGPARM void thumb##BASE##_0F(u32 opcode) { IMM5_INSN(OP,15); } \
+ static INSN_REGPARM void thumb##BASE##_10(u32 opcode) { IMM5_INSN(OP,16); } \
+ static INSN_REGPARM void thumb##BASE##_11(u32 opcode) { IMM5_INSN(OP,17); } \
+ static INSN_REGPARM void thumb##BASE##_12(u32 opcode) { IMM5_INSN(OP,18); } \
+ static INSN_REGPARM void thumb##BASE##_13(u32 opcode) { IMM5_INSN(OP,19); } \
+ static INSN_REGPARM void thumb##BASE##_14(u32 opcode) { IMM5_INSN(OP,20); } \
+ static INSN_REGPARM void thumb##BASE##_15(u32 opcode) { IMM5_INSN(OP,21); } \
+ static INSN_REGPARM void thumb##BASE##_16(u32 opcode) { IMM5_INSN(OP,22); } \
+ static INSN_REGPARM void thumb##BASE##_17(u32 opcode) { IMM5_INSN(OP,23); } \
+ static INSN_REGPARM void thumb##BASE##_18(u32 opcode) { IMM5_INSN(OP,24); } \
+ static INSN_REGPARM void thumb##BASE##_19(u32 opcode) { IMM5_INSN(OP,25); } \
+ static INSN_REGPARM void thumb##BASE##_1A(u32 opcode) { IMM5_INSN(OP,26); } \
+ static INSN_REGPARM void thumb##BASE##_1B(u32 opcode) { IMM5_INSN(OP,27); } \
+ static INSN_REGPARM void thumb##BASE##_1C(u32 opcode) { IMM5_INSN(OP,28); } \
+ static INSN_REGPARM void thumb##BASE##_1D(u32 opcode) { IMM5_INSN(OP,29); } \
+ static INSN_REGPARM void thumb##BASE##_1E(u32 opcode) { IMM5_INSN(OP,30); } \
+ static INSN_REGPARM void thumb##BASE##_1F(u32 opcode) { IMM5_INSN(OP,31); }
+
+// LSL Rd, Rm, #Imm 5
+DEFINE_IMM5_INSN(IMM5_LSL,00)
+// LSR Rd, Rm, #Imm 5
+DEFINE_IMM5_INSN(IMM5_LSR,08)
+// ASR Rd, Rm, #Imm 5
+DEFINE_IMM5_INSN(IMM5_ASR,10)
+
+// 3-argument ADD/SUB /////////////////////////////////////////////////////
+
+#define DEFINE_REG3_INSN(OP,BASE) \
+ static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP,0); } \
+ static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \
+ static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \
+ static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \
+ static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \
+ static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \
+ static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \
+ static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); }
+
+#define DEFINE_IMM3_INSN(OP,BASE) \
+ static INSN_REGPARM void thumb##BASE##_0(u32 opcode) { THREEARG_INSN(OP##_0,0); } \
+ static INSN_REGPARM void thumb##BASE##_1(u32 opcode) { THREEARG_INSN(OP,1); } \
+ static INSN_REGPARM void thumb##BASE##_2(u32 opcode) { THREEARG_INSN(OP,2); } \
+ static INSN_REGPARM void thumb##BASE##_3(u32 opcode) { THREEARG_INSN(OP,3); } \
+ static INSN_REGPARM void thumb##BASE##_4(u32 opcode) { THREEARG_INSN(OP,4); } \
+ static INSN_REGPARM void thumb##BASE##_5(u32 opcode) { THREEARG_INSN(OP,5); } \
+ static INSN_REGPARM void thumb##BASE##_6(u32 opcode) { THREEARG_INSN(OP,6); } \
+ static INSN_REGPARM void thumb##BASE##_7(u32 opcode) { THREEARG_INSN(OP,7); }
+
+// ADD Rd, Rs, Rn
+DEFINE_REG3_INSN(ADD_RD_RS_RN,18)
+// SUB Rd, Rs, Rn
+DEFINE_REG3_INSN(SUB_RD_RS_RN,1A)
+// ADD Rd, Rs, #Offset3
+DEFINE_IMM3_INSN(ADD_RD_RS_O3,1C)
+// SUB Rd, Rs, #Offset3
+DEFINE_IMM3_INSN(SUB_RD_RS_O3,1E)
+
+// MOV/CMP/ADD/SUB immediate //////////////////////////////////////////////
+
+// MOV R0, #Offset8
+static INSN_REGPARM void thumb20(u32 opcode) { MOV_RN_O8(0); }
+// MOV R1, #Offset8
+static INSN_REGPARM void thumb21(u32 opcode) { MOV_RN_O8(1); }
+// MOV R2, #Offset8
+static INSN_REGPARM void thumb22(u32 opcode) { MOV_RN_O8(2); }
+// MOV R3, #Offset8
+static INSN_REGPARM void thumb23(u32 opcode) { MOV_RN_O8(3); }
+// MOV R4, #Offset8
+static INSN_REGPARM void thumb24(u32 opcode) { MOV_RN_O8(4); }
+// MOV R5, #Offset8
+static INSN_REGPARM void thumb25(u32 opcode) { MOV_RN_O8(5); }
+// MOV R6, #Offset8
+static INSN_REGPARM void thumb26(u32 opcode) { MOV_RN_O8(6); }
+// MOV R7, #Offset8
+static INSN_REGPARM void thumb27(u32 opcode) { MOV_RN_O8(7); }
+
+// CMP R0, #Offset8
+static INSN_REGPARM void thumb28(u32 opcode) { CMP_RN_O8(0); }
+// CMP R1, #Offset8
+static INSN_REGPARM void thumb29(u32 opcode) { CMP_RN_O8(1); }
+// CMP R2, #Offset8
+static INSN_REGPARM void thumb2A(u32 opcode) { CMP_RN_O8(2); }
+// CMP R3, #Offset8
+static INSN_REGPARM void thumb2B(u32 opcode) { CMP_RN_O8(3); }
+// CMP R4, #Offset8
+static INSN_REGPARM void thumb2C(u32 opcode) { CMP_RN_O8(4); }
+// CMP R5, #Offset8
+static INSN_REGPARM void thumb2D(u32 opcode) { CMP_RN_O8(5); }
+// CMP R6, #Offset8
+static INSN_REGPARM void thumb2E(u32 opcode) { CMP_RN_O8(6); }
+// CMP R7, #Offset8
+static INSN_REGPARM void thumb2F(u32 opcode) { CMP_RN_O8(7); }
+
+// ADD R0,#Offset8
+static INSN_REGPARM void thumb30(u32 opcode) { ADD_RN_O8(0); }
+// ADD R1,#Offset8
+static INSN_REGPARM void thumb31(u32 opcode) { ADD_RN_O8(1); }
+// ADD R2,#Offset8
+static INSN_REGPARM void thumb32(u32 opcode) { ADD_RN_O8(2); }
+// ADD R3,#Offset8
+static INSN_REGPARM void thumb33(u32 opcode) { ADD_RN_O8(3); }
+// ADD R4,#Offset8
+static INSN_REGPARM void thumb34(u32 opcode) { ADD_RN_O8(4); }
+// ADD R5,#Offset8
+static INSN_REGPARM void thumb35(u32 opcode) { ADD_RN_O8(5); }
+// ADD R6,#Offset8
+static INSN_REGPARM void thumb36(u32 opcode) { ADD_RN_O8(6); }
+// ADD R7,#Offset8
+static INSN_REGPARM void thumb37(u32 opcode) { ADD_RN_O8(7); }
+
+// SUB R0,#Offset8
+static INSN_REGPARM void thumb38(u32 opcode) { SUB_RN_O8(0); }
+// SUB R1,#Offset8
+static INSN_REGPARM void thumb39(u32 opcode) { SUB_RN_O8(1); }
+// SUB R2,#Offset8
+static INSN_REGPARM void thumb3A(u32 opcode) { SUB_RN_O8(2); }
+// SUB R3,#Offset8
+static INSN_REGPARM void thumb3B(u32 opcode) { SUB_RN_O8(3); }
+// SUB R4,#Offset8
+static INSN_REGPARM void thumb3C(u32 opcode) { SUB_RN_O8(4); }
+// SUB R5,#Offset8
+static INSN_REGPARM void thumb3D(u32 opcode) { SUB_RN_O8(5); }
+// SUB R6,#Offset8
+static INSN_REGPARM void thumb3E(u32 opcode) { SUB_RN_O8(6); }
+// SUB R7,#Offset8
+static INSN_REGPARM void thumb3F(u32 opcode) { SUB_RN_O8(7); }
+
+// ALU operations /////////////////////////////////////////////////////////
+
+// AND Rd, Rs
+static INSN_REGPARM void thumb40_0(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I &= reg[(opcode >> 3)&7].I;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ THUMB_CONSOLE_OUTPUT(NULL, reg[2].I);
+}
+
+// EOR Rd, Rs
+static INSN_REGPARM void thumb40_1(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I ^= reg[(opcode >> 3)&7].I;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+}
+
+// LSL Rd, Rs
+static INSN_REGPARM void thumb40_2(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+ if(value) {
+ if(value == 32) {
+ value = 0;
+ C_FLAG = (reg[dest].I & 1 ? true : false);
+ } else if(value < 32) {
+ LSL_RD_RS;
+ } else {
+ value = 0;
+ C_FLAG = false;
+ }
+ reg[dest].I = value;
+ }
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+}
+
+// LSR Rd, Rs
+static INSN_REGPARM void thumb40_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+ if(value) {
+ if(value == 32) {
+ value = 0;
+ C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
+ } else if(value < 32) {
+ LSR_RD_RS;
+ } else {
+ value = 0;
+ C_FLAG = false;
+ }
+ reg[dest].I = value;
+ }
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+}
+
+// ASR Rd, Rs
+static INSN_REGPARM void thumb41_0(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+ if(value) {
+ if(value < 32) {
+ ASR_RD_RS;
+ reg[dest].I = value;
+ } else {
+ if(reg[dest].I & 0x80000000){
+ reg[dest].I = 0xFFFFFFFF;
+ C_FLAG = true;
+ } else {
+ reg[dest].I = 0x00000000;
+ C_FLAG = false;
+ }
+ }
+ }
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+}
+
+// ADC Rd, Rs
+static INSN_REGPARM void thumb41_1(u32 opcode)
+{
+ int dest = opcode & 0x07;
+ u32 value = reg[(opcode >> 3)&7].I;
+ ADC_RD_RS;
+}
+
+// SBC Rd, Rs
+static INSN_REGPARM void thumb41_2(u32 opcode)
+{
+ int dest = opcode & 0x07;
+ u32 value = reg[(opcode >> 3)&7].I;
+ SBC_RD_RS;
+}
+
+// ROR Rd, Rs
+static INSN_REGPARM void thumb41_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].B.B0;
+
+ if(value) {
+ value = value & 0x1f;
+ if(value == 0) {
+ C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
+ } else {
+ ROR_RD_RS;
+ reg[dest].I = value;
+ }
+ }
+ clockTicks = codeTicksAccess16(armNextPC)+2;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+ Z_FLAG = reg[dest].I ? false : true;
+}
+
+// TST Rd, Rs
+static INSN_REGPARM void thumb42_0(u32 opcode)
+{
+ u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I;
+ N_FLAG = value & 0x80000000 ? true : false;
+ Z_FLAG = value ? false : true;
+}
+
+// NEG Rd, Rs
+static INSN_REGPARM void thumb42_1(u32 opcode)
+{
+ int dest = opcode & 7;
+ int source = (opcode >> 3) & 7;
+ NEG_RD_RS;
+}
+
+// CMP Rd, Rs
+static INSN_REGPARM void thumb42_2(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].I;
+ CMP_RD_RS;
+}
+
+// CMN Rd, Rs
+static INSN_REGPARM void thumb42_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[(opcode >> 3)&7].I;
+ CMN_RD_RS;
+}
+
+// ORR Rd, Rs
+static INSN_REGPARM void thumb43_0(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I |= reg[(opcode >> 3) & 7].I;
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// MUL Rd, Rs
+static INSN_REGPARM void thumb43_1(u32 opcode)
+{
+ clockTicks = 1;
+ int dest = opcode & 7;
+ u32 rm = reg[dest].I;
+ reg[dest].I = reg[(opcode >> 3) & 7].I * rm;
+ if (((s32)rm) < 0)
+ rm = ~rm;
+ if ((rm & 0xFFFFFF00) == 0)
+ clockTicks += 0;
+ else if ((rm & 0xFFFF0000) == 0)
+ clockTicks += 1;
+ else if ((rm & 0xFF000000) == 0)
+ clockTicks += 2;
+ else
+ clockTicks += 3;
+ busPrefetchCount = (busPrefetchCount<>(8-clockTicks));
+ clockTicks += codeTicksAccess16(armNextPC) + 1;
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// BIC Rd, Rs
+static INSN_REGPARM void thumb43_2(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I &= (~reg[(opcode >> 3) & 7].I);
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// MVN Rd, Rs
+static INSN_REGPARM void thumb43_3(u32 opcode)
+{
+ int dest = opcode & 7;
+ reg[dest].I = ~reg[(opcode >> 3) & 7].I;
+ Z_FLAG = reg[dest].I ? false : true;
+ N_FLAG = reg[dest].I & 0x80000000 ? true : false;
+}
+
+// High-register instructions and BX //////////////////////////////////////
+
+// ADD Rd, Hs
+static INSN_REGPARM void thumb44_1(u32 opcode)
+{
+ reg[opcode&7].I += reg[((opcode>>3)&7)+8].I;
+}
+
+// ADD Hd, Rs
+static INSN_REGPARM void thumb44_2(u32 opcode)
+{
+ reg[(opcode&7)+8].I += reg[(opcode>>3)&7].I;
+ if((opcode&7) == 7) {
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+// ADD Hd, Hs
+static INSN_REGPARM void thumb44_3(u32 opcode)
+{
+ reg[(opcode&7)+8].I += reg[((opcode>>3)&7)+8].I;
+ if((opcode&7) == 7) {
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+// CMP Rd, Hs
+static INSN_REGPARM void thumb45_1(u32 opcode)
+{
+ int dest = opcode & 7;
+ u32 value = reg[((opcode>>3)&7)+8].I;
+ CMP_RD_RS;
+}
+
+// CMP Hd, Rs
+static INSN_REGPARM void thumb45_2(u32 opcode)
+{
+ int dest = (opcode & 7) + 8;
+ u32 value = reg[(opcode>>3)&7].I;
+ CMP_RD_RS;
+}
+
+// CMP Hd, Hs
+static INSN_REGPARM void thumb45_3(u32 opcode)
+{
+ int dest = (opcode & 7) + 8;
+ u32 value = reg[((opcode>>3)&7)+8].I;
+ CMP_RD_RS;
+}
+
+// MOV Rd, Hs
+static INSN_REGPARM void thumb46_1(u32 opcode)
+{
+ reg[opcode&7].I = reg[((opcode>>3)&7)+8].I;
+}
+
+// MOV Hd, Rs
+static INSN_REGPARM void thumb46_2(u32 opcode)
+{
+ reg[(opcode&7)+8].I = reg[(opcode>>3)&7].I;
+ if((opcode&7) == 7) {
+ UPDATE_OLDREG;
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+// MOV Hd, Hs
+static INSN_REGPARM void thumb46_3(u32 opcode)
+{
+ reg[(opcode&7)+8].I = reg[((opcode>>3)&7)+8].I;
+ if((opcode&7) == 7) {
+ UPDATE_OLDREG;
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)*2
+ + codeTicksAccess16(armNextPC) + 3;
+ }
+}
+
+
+// BX Rs
+static INSN_REGPARM void thumb47(u32 opcode)
+{
+ int base = (opcode >> 3) & 15;
+ busPrefetchCount=0;
+ UPDATE_OLDREG;
+ reg[15].I = reg[base].I;
+ if(reg[base].I & 1) {
+ armState = false;
+ reg[15].I &= 0xFFFFFFFE;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ THUMB_PREFETCH;
+ clockTicks = codeTicksAccessSeq16(armNextPC)
+ + codeTicksAccessSeq16(armNextPC) + codeTicksAccess16(armNextPC) + 3;
+ } else {
+ armState = true;
+ reg[15].I &= 0xFFFFFFFC;
+ armNextPC = reg[15].I;
+ reg[15].I += 4;
+ ARM_PREFETCH;
+ clockTicks = codeTicksAccessSeq32(armNextPC)
+ + codeTicksAccessSeq32(armNextPC) + codeTicksAccess32(armNextPC) + 3;
+ }
+}
+
+// Load/store instructions ////////////////////////////////////////////////
+
+// LDR R0~R7,[PC, #Imm]
+static INSN_REGPARM void thumb48(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
+ reg[regist].I = CPUReadMemoryQuick(address);
+ busPrefetchCount=0;
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// STR Rd, [Rs, Rn]
+static INSN_REGPARM void thumb50(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ CPUWriteMemory(address, reg[opcode & 7].I);
+ clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// STRH Rd, [Rs, Rn]
+static INSN_REGPARM void thumb52(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ CPUWriteHalfWord(address, reg[opcode&7].W.W0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// STRB Rd, [Rs, Rn]
+static INSN_REGPARM void thumb54(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I;
+ CPUWriteByte(address, reg[opcode & 7].B.B0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDSB Rd, [Rs, Rn]
+static INSN_REGPARM void thumb56(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = (s8)CPUReadByte(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDR Rd, [Rs, Rn]
+static INSN_REGPARM void thumb58(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = CPUReadMemory(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDRH Rd, [Rs, Rn]
+static INSN_REGPARM void thumb5A(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = CPUReadHalfWord(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDRB Rd, [Rs, Rn]
+static INSN_REGPARM void thumb5C(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = CPUReadByte(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// LDSH Rd, [Rs, Rn]
+static INSN_REGPARM void thumb5E(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
+ reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// STR Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb60(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2);
+ CPUWriteMemory(address, reg[opcode&7].I);
+ clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDR Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb68(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2);
+ reg[opcode&7].I = CPUReadMemory(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// STRB Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb70(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31));
+ CPUWriteByte(address, reg[opcode&7].B.B0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDRB Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb78(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31));
+ reg[opcode&7].I = CPUReadByte(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// STRH Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb80(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1);
+ CPUWriteHalfWord(address, reg[opcode&7].W.W0);
+ clockTicks = dataTicksAccess16(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDRH Rd, [Rs, #Imm]
+static INSN_REGPARM void thumb88(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1);
+ reg[opcode&7].I = CPUReadHalfWord(address);
+ clockTicks = 3 + dataTicksAccess16(address) + codeTicksAccess16(armNextPC);
+}
+
+// STR R0~R7, [SP, #Imm]
+static INSN_REGPARM void thumb90(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[13].I + ((opcode&255)<<2);
+ CPUWriteMemory(address, reg[regist].I);
+ clockTicks = dataTicksAccess32(address) + codeTicksAccess16(armNextPC) + 2;
+}
+
+// LDR R0~R7, [SP, #Imm]
+static INSN_REGPARM void thumb98(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[13].I + ((opcode&255)<<2);
+ reg[regist].I = CPUReadMemoryQuick(address);
+ clockTicks = 3 + dataTicksAccess32(address) + codeTicksAccess16(armNextPC);
+}
+
+// PC/stack-related ///////////////////////////////////////////////////////
+
+// ADD R0~R7, PC, Imm
+static INSN_REGPARM void thumbA0(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ reg[regist].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
+}
+
+// ADD R0~R7, SP, Imm
+static INSN_REGPARM void thumbA8(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ reg[regist].I = reg[13].I + ((opcode&255)<<2);
+}
+
+// ADD SP, Imm
+static INSN_REGPARM void thumbB0(u32 opcode)
+{
+ int offset = (opcode & 127) << 2;
+ if(opcode & 0x80)
+ offset = -offset;
+ reg[13].I += offset;
+}
+
+// Push and pop ///////////////////////////////////////////////////////////
+
+#define PUSH_REG(val, r) \
+ if (opcode & (val)) { \
+ CPUWriteMemory(address, reg[(r)].I); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+#define POP_REG(val, r) \
+ if (opcode & (val)) { \
+ reg[(r)].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+// PUSH {Rlist}
+static INSN_REGPARM void thumbB4(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff];
+ u32 address = temp & 0xFFFFFFFC;
+ PUSH_REG(1, 0);
+ PUSH_REG(2, 1);
+ PUSH_REG(4, 2);
+ PUSH_REG(8, 3);
+ PUSH_REG(16, 4);
+ PUSH_REG(32, 5);
+ PUSH_REG(64, 6);
+ PUSH_REG(128, 7);
+ clockTicks += 1 + codeTicksAccess16(armNextPC);
+ reg[13].I = temp;
+}
+
+// PUSH {Rlist, LR}
+static INSN_REGPARM void thumbB5(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff];
+ u32 address = temp & 0xFFFFFFFC;
+ PUSH_REG(1, 0);
+ PUSH_REG(2, 1);
+ PUSH_REG(4, 2);
+ PUSH_REG(8, 3);
+ PUSH_REG(16, 4);
+ PUSH_REG(32, 5);
+ PUSH_REG(64, 6);
+ PUSH_REG(128, 7);
+ PUSH_REG(256, 14);
+ clockTicks += 1 + codeTicksAccess16(armNextPC);
+ reg[13].I = temp;
+}
+
+// POP {Rlist}
+static INSN_REGPARM void thumbBC(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 address = reg[13].I & 0xFFFFFFFC;
+ u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF];
+ POP_REG(1, 0);
+ POP_REG(2, 1);
+ POP_REG(4, 2);
+ POP_REG(8, 3);
+ POP_REG(16, 4);
+ POP_REG(32, 5);
+ POP_REG(64, 6);
+ POP_REG(128, 7);
+ reg[13].I = temp;
+ clockTicks = 2 + codeTicksAccess16(armNextPC);
+}
+
+// POP {Rlist, PC}
+static INSN_REGPARM void thumbBD(u32 opcode)
+{
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ int count = 0;
+ u32 address = reg[13].I & 0xFFFFFFFC;
+ u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF];
+ POP_REG(1, 0);
+ POP_REG(2, 1);
+ POP_REG(4, 2);
+ POP_REG(8, 3);
+ POP_REG(16, 4);
+ POP_REG(32, 5);
+ POP_REG(64, 6);
+ POP_REG(128, 7);
+ reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE);
+ if (!count) {
+ clockTicks += 1 + dataTicksAccess32(address);
+ } else {
+ clockTicks += 1 + dataTicksAccessSeq32(address);
+ }
+ count++;
+ armNextPC = reg[15].I;
+ reg[15].I += 2;
+ reg[13].I = temp;
+ THUMB_PREFETCH;
+ busPrefetchCount = 0;
+ clockTicks += 3 + codeTicksAccess16(armNextPC) + codeTicksAccess16(armNextPC);
+}
+
+// Load/store multiple ////////////////////////////////////////////////////
+
+#define THUMB_STM_REG(val,r,b) \
+ if(opcode & (val)) { \
+ CPUWriteMemory(address, reg[(r)].I); \
+ reg[(b)].I = temp; \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+#define THUMB_LDM_REG(val,r) \
+ if(opcode & (val)) { \
+ reg[(r)].I = CPUReadMemory(address); \
+ if (!count) { \
+ clockTicks += 1 + dataTicksAccess32(address); \
+ } else { \
+ clockTicks += 1 + dataTicksAccessSeq32(address); \
+ } \
+ count++; \
+ address += 4; \
+ }
+
+// STM R0~7!, {Rlist}
+static INSN_REGPARM void thumbC0(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[regist].I & 0xFFFFFFFC;
+ u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xff];
+ int count = 0;
+ // store
+ THUMB_STM_REG(1, 0, regist);
+ THUMB_STM_REG(2, 1, regist);
+ THUMB_STM_REG(4, 2, regist);
+ THUMB_STM_REG(8, 3, regist);
+ THUMB_STM_REG(16, 4, regist);
+ THUMB_STM_REG(32, 5, regist);
+ THUMB_STM_REG(64, 6, regist);
+ THUMB_STM_REG(128, 7, regist);
+ clockTicks = 1 + codeTicksAccess16(armNextPC);
+}
+
+// LDM R0~R7!, {Rlist}
+static INSN_REGPARM void thumbC8(u32 opcode)
+{
+ u8 regist = (opcode >> 8) & 7;
+ if (busPrefetchCount == 0)
+ busPrefetch = busPrefetchEnable;
+ u32 address = reg[regist].I & 0xFFFFFFFC;
+ u32 temp = reg[regist].I + 4*cpuBitsSet[opcode & 0xFF];
+ int count = 0;
+ // load
+ THUMB_LDM_REG(1, 0);
+ THUMB_LDM_REG(2, 1);
+ THUMB_LDM_REG(4, 2);
+ THUMB_LDM_REG(8, 3);
+ THUMB_LDM_REG(16, 4);
+ THUMB_LDM_REG(32, 5);
+ THUMB_LDM_REG(64, 6);
+ THUMB_LDM_REG(128, 7);
+ clockTicks = 2 + codeTicksAccess16(armNextPC);
+ if(!(opcode & (1<>6])(opcode);
+
+ if (clockTicks < 0)
+ return 0;
+ if (clockTicks==0)
+ clockTicks = codeTicksAccessSeq16(oldArmNextPC) + 1;
+ cpuTotalTicks += clockTicks;
+
+ } while (cpuTotalTicks < cpuNextEvent && !armState && !holdState && !SWITicks);
+ return 1;
+}
diff --git a/trunk/src/GBA.cpp b/trunk/src/GBA.cpp
index 7f6e3174..e873b5ff 100644
--- a/trunk/src/GBA.cpp
+++ b/trunk/src/GBA.cpp
@@ -23,6 +23,7 @@
#include
#include "GBA.h"
+#include "GBAcpu.h"
#include "GBAinline.h"
#include "Globals.h"
#include "Gfx.h"
@@ -42,29 +43,6 @@
#include "prof/prof.h"
#endif
-#define UPDATE_REG(address, value)\
- {\
- WRITE16LE(((u16 *)&ioMem[address]),value);\
- }\
-
-#define ARM_PREFETCH \
- {\
- cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\
- cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\
- }
-
-#define THUMB_PREFETCH \
- {\
- cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\
- cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\
- }
-
-#define ARM_PREFETCH_NEXT \
- cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);
-
-#define THUMB_PREFETCH_NEXT\
- cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);
-
#ifdef __GNUC__
#define _stricmp strcasecmp
#endif
@@ -118,12 +96,14 @@ int profilingTicksReload = 0;
static profile_segment *profilSegment = NULL;
#endif
+#ifdef BKPT_SUPPORT
u8 freezeWorkRAM[0x40000];
u8 freezeInternalRAM[0x8000];
u8 freezeVRAM[0x18000];
u8 freezePRAM[0x400];
u8 freezeOAM[0x400];
bool debugger_last;
+#endif
int lcdTicks = (useBios && !skipBios) ? 1008 : 208;
u8 timerOnOffDelay = 0;
@@ -522,208 +502,6 @@ void cpuEnableProfiling(int hz)
#endif
-// Waitstates when accessing data
-inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ
-{
- int addr = (address>>24)&15;
- int value = memoryWait[addr];
-
- if ((addr>=0x08) || (addr < 0x02))
- {
- busPrefetchCount=0;
- busPrefetch=false;
- }
- else if (busPrefetch)
- {
- int waitState = value;
- if (!waitState)
- waitState = 1;
- busPrefetchCount = ((++busPrefetchCount)<>24)&15;
- int value = memoryWait32[addr];
-
- if ((addr>=0x08) || (addr < 0x02))
- {
- busPrefetchCount=0;
- busPrefetch=false;
- }
- else if (busPrefetch)
- {
- int waitState = value;
- if (!waitState)
- waitState = 1;
- busPrefetchCount = ((++busPrefetchCount)<>24)&15;
- int value = memoryWaitSeq[addr];
-
- if ((addr>=0x08) || (addr < 0x02))
- {
- busPrefetchCount=0;
- busPrefetch=false;
- }
- else if (busPrefetch)
- {
- int waitState = value;
- if (!waitState)
- waitState = 1;
- busPrefetchCount = ((++busPrefetchCount)<>24)&15;
- int value = memoryWaitSeq32[addr];
-
- if ((addr>=0x08) || (addr < 0x02))
- {
- busPrefetchCount=0;
- busPrefetch=false;
- }
- else if (busPrefetch)
- {
- int waitState = value;
- if (!waitState)
- waitState = 1;
- busPrefetchCount = ((++busPrefetchCount)<>24)&15;
-
- if ((addr>=0x08) && (addr<=0x0D))
- {
- if (busPrefetchCount&0x1)
- {
- if (busPrefetchCount&0x2)
- {
- busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
- return 0;
- }
- busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
- return memoryWaitSeq[addr]-1;
- }
- else
- {
- busPrefetchCount=0;
- return memoryWait[addr];
- }
- }
- else
- {
- busPrefetchCount = 0;
- return memoryWait[addr];
- }
-}
-
-inline int codeTicksAccess32(u32 address) // ARM NON SEQ
-{
- int addr = (address>>24)&15;
-
- if ((addr>=0x08) && (addr<=0x0D))
- {
- if (busPrefetchCount&0x1)
- {
- if (busPrefetchCount&0x2)
- {
- busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
- return 0;
- }
- busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
- return memoryWaitSeq[addr] - 1;
- }
- else
- {
- busPrefetchCount = 0;
- return memoryWait32[addr];
- }
- }
- else
- {
- busPrefetchCount = 0;
- return memoryWait32[addr];
- }
-}
-
-inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ
-{
- int addr = (address>>24)&15;
-
- if ((addr>=0x08) && (addr<=0x0D))
- {
- if (busPrefetchCount&0x1)
- {
- busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
- return 0;
- }
- else
- if (busPrefetchCount>0xFF)
- {
- busPrefetchCount=0;
- return memoryWait[addr];
- }
- else
- return memoryWaitSeq[addr];
- }
- else
- {
- busPrefetchCount = 0;
- return memoryWaitSeq[addr];
- }
-}
-
-inline int codeTicksAccessSeq32(u32 address) // ARM SEQ
-{
- int addr = (address>>24)&15;
-
- if ((addr>=0x08) && (addr<=0x0D))
- {
- if (busPrefetchCount&0x1)
- {
- if (busPrefetchCount&0x2)
- {
- busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
- return 0;
- }
- busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
- return memoryWaitSeq[addr];
- }
- else
- if (busPrefetchCount>0xFF)
- {
- busPrefetchCount=0;
- return memoryWait32[addr];
- }
- else
- return memoryWaitSeq32[addr];
- }
- else
- {
- return memoryWaitSeq32[addr];
- }
-}
inline int CPUUpdateTicks()
@@ -2316,15 +2094,14 @@ void doDMA(u32 &s, u32 &d, u32 si, u32 di, u32 c, int transfer32)
}
-bool CPUCheckDMA(int reason, int dmamask)
+void CPUCheckDMA(int reason, int dmamask)
{
- bool res = false;
- cpuDmaHack = 0;
+
// DMA 0
if((DM0CNT_H & 0x8000) && (dmamask & 1)) {
if(((DM0CNT_H >> 12) & 3) == reason) {
- res = true;
+
u32 sourceIncrement = 4;
u32 destIncrement = 4;
switch((DM0CNT_H >> 7) & 3) {
@@ -2382,7 +2159,7 @@ bool CPUCheckDMA(int reason, int dmamask)
// DMA 1
if((DM1CNT_H & 0x8000) && (dmamask & 2)) {
if(((DM1CNT_H >> 12) & 3) == reason) {
- res = true;
+
u32 sourceIncrement = 4;
u32 destIncrement = 4;
@@ -2453,7 +2230,7 @@ bool CPUCheckDMA(int reason, int dmamask)
// DMA 2
if((DM2CNT_H & 0x8000) && (dmamask & 4)) {
if(((DM2CNT_H >> 12) & 3) == reason) {
- res = true;
+
u32 sourceIncrement = 4;
u32 destIncrement = 4;
switch((DM2CNT_H >> 7) & 3) {
@@ -2524,7 +2301,7 @@ bool CPUCheckDMA(int reason, int dmamask)
// DMA 3
if((DM3CNT_H & 0x8000) && (dmamask & 8)) {
if(((DM3CNT_H >> 12) & 3) == reason) {
- res = true;
+
u32 sourceIncrement = 4;
u32 destIncrement = 4;
switch((DM3CNT_H >> 7) & 3) {
@@ -2577,7 +2354,7 @@ bool CPUCheckDMA(int reason, int dmamask)
}
}
//cpuDmaHack = false;
- return res;
+
}
void CPUUpdateRegister(u32 address, u16 value)
@@ -3187,248 +2964,6 @@ void applyTimer ()
timerOnOffDelay = 0;
}
-void CPUWriteHalfWord(u32 address, u16 value)
-{
-#ifdef DEV_VERSION
- if(address & 1) {
- if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
- log("Unaligned halfword write: %04x to %08x from %08x\n",
- value,
- address,
- armMode ? armNextPC - 4 : armNextPC - 2);
- }
- }
-#endif
-
- switch(address >> 24) {
- case 2:
-#ifdef BKPT_SUPPORT
- if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
- cheatsWriteHalfWord(address & 0x203FFFE,
- value);
- else
-#endif
- WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
- break;
- case 3:
-#ifdef BKPT_SUPPORT
- if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
- cheatsWriteHalfWord(address & 0x3007ffe,
- value);
- else
-#endif
- WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
- break;
- case 4:
- if(address < 0x4000400)
- CPUUpdateRegister(address & 0x3fe, value);
- else goto unwritable;
- break;
- case 5:
-#ifdef BKPT_SUPPORT
- if(*((u16 *)&freezePRAM[address & 0x03fe]))
- cheatsWriteHalfWord(address & 0x70003fe,
- value);
- else
-#endif
- WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
- break;
- case 6:
- address = (address & 0x1fffe);
- if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
- return;
- if ((address & 0x18000) == 0x18000)
- address &= 0x17fff;
-#ifdef BKPT_SUPPORT
- if(*((u16 *)&freezeVRAM[address]))
- cheatsWriteHalfWord(address + 0x06000000,
- value);
- else
-#endif
- WRITE16LE(((u16 *)&vram[address]), value);
- break;
- case 7:
-#ifdef BKPT_SUPPORT
- if(*((u16 *)&freezeOAM[address & 0x03fe]))
- cheatsWriteHalfWord(address & 0x70003fe,
- value);
- else
-#endif
- WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
- break;
- case 8:
- case 9:
- if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) {
- if(!rtcWrite(address, value))
- goto unwritable;
- } else if(!agbPrintWrite(address, value)) goto unwritable;
- break;
- case 13:
- if(cpuEEPROMEnabled) {
- eepromWrite(address, (u8)value);
- break;
- }
- goto unwritable;
- case 14:
- if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) {
- (*cpuSaveGameFunc)(address, (u8)value);
- break;
- }
- goto unwritable;
- default:
- unwritable:
-#ifdef DEV_VERSION
- if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
- log("Illegal halfword write: %04x to %08x from %08x\n",
- value,
- address,
- armMode ? armNextPC - 4 : armNextPC - 2);
- }
-#endif
- break;
- }
-}
-
-void CPUWriteByte(u32 address, u8 b)
-{
- switch(address >> 24) {
- case 2:
-#ifdef BKPT_SUPPORT
- if(freezeWorkRAM[address & 0x3FFFF])
- cheatsWriteByte(address & 0x203FFFF, b);
- else
-#endif
- workRAM[address & 0x3FFFF] = b;
- break;
- case 3:
-#ifdef BKPT_SUPPORT
- if(freezeInternalRAM[address & 0x7fff])
- cheatsWriteByte(address & 0x3007fff, b);
- else
-#endif
- internalRAM[address & 0x7fff] = b;
- break;
- case 4:
- if(address < 0x4000400) {
- switch(address & 0x3FF) {
- case 0x301:
- if(b == 0x80)
- stopState = true;
- holdState = 1;
- holdType = -1;
- cpuNextEvent = cpuTotalTicks;
- break;
- case 0x60:
- case 0x61:
- case 0x62:
- case 0x63:
- case 0x64:
- case 0x65:
- case 0x68:
- case 0x69:
- case 0x6c:
- case 0x6d:
- case 0x70:
- case 0x71:
- case 0x72:
- case 0x73:
- case 0x74:
- case 0x75:
- case 0x78:
- case 0x79:
- case 0x7c:
- case 0x7d:
- case 0x80:
- case 0x81:
- case 0x84:
- case 0x85:
- case 0x90:
- case 0x91:
- case 0x92:
- case 0x93:
- case 0x94:
- case 0x95:
- case 0x96:
- case 0x97:
- case 0x98:
- case 0x99:
- case 0x9a:
- case 0x9b:
- case 0x9c:
- case 0x9d:
- case 0x9e:
- case 0x9f:
- soundEvent(address&0xFF, b);
- break;
- default:
- if(address & 1)
- CPUUpdateRegister(address & 0x3fe,
- ((READ16LE(((u16 *)&ioMem[address & 0x3fe])))
- & 0x00FF) |
- b<<8);
- else
- CPUUpdateRegister(address & 0x3fe,
- ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b));
- }
- break;
- } else goto unwritable;
- break;
- case 5:
- // no need to switch
- *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
- break;
- case 6:
- address = (address & 0x1fffe);
- if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
- return;
- if ((address & 0x18000) == 0x18000)
- address &= 0x17fff;
-
- // no need to switch
- // byte writes to OBJ VRAM are ignored
- if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2])
- {
-#ifdef BKPT_SUPPORT
- if(freezeVRAM[address])
- cheatsWriteByte(address + 0x06000000, b);
- else
-#endif
- *((u16 *)&vram[address]) = (b << 8) | b;
- }
- break;
- case 7:
- // no need to switch
- // byte writes to OAM are ignored
- // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
- break;
- case 13:
- if(cpuEEPROMEnabled) {
- eepromWrite(address, b);
- break;
- }
- goto unwritable;
- case 14:
- if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) {
-
- //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
-
- (*cpuSaveGameFunc)(address, b);
- break;
- }
- // default
- default:
- unwritable:
-#ifdef DEV_VERSION
- if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
- log("Illegal byte write: %02x to %08x from %08x\n",
- b,
- address,
- armMode ? armNextPC - 4 : armNextPC -2 );
- }
-#endif
- break;
- }
-}
u8 cpuBitsSet[256];
u8 cpuLowestBitSet[256];
@@ -3883,7 +3418,7 @@ void CPULoop(int ticks)
// variable used by the CPU core
cpuTotalTicks = 0;
#ifdef LINK_EMULATION
- if(linkenable && cpuDmaHack2)
+ if(linkenable)
cpuNextEvent = 1;
#endif
cpuBreakLoop = false;
@@ -3929,28 +3464,17 @@ void CPULoop(int ticks)
#endif /* FINAL_VERSION */
if(!holdState && !SWITicks) {
-
- // Emulates the Cheat System (m) code
- if((cheatsEnabled) && (mastercode) && (mastercode == armNextPC))
- {
- u32 joy = 0;
- if(systemReadJoypads())
- joy = systemReadJoypad(-1);
- u32 ext = (joy >> 10);
- cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext);
- }
-
- if ((armNextPC & 0x0803FFFF) == 0x08020000)
- busPrefetchCount=0x100;
-
if(armState) {
-#include "arm-new.h"
+ if (!armExecute())
+ return;
} else {
-#include "thumb.h"
- }
- } else
+ if (!thumbExecute())
+ return;
+
+ }
+ }
clockTicks = CPUUpdateTicks();
-
+
cpuTotalTicks += clockTicks;
@@ -4084,7 +3608,7 @@ void CPULoop(int ticks)
IF |= 1;
UPDATE_REG(0x202, IF);
}
- cpuDmaHack2 = CPUCheckDMA(1, 0x0f);
+ CPUCheckDMA(1, 0x0f);
if(frameCount >= framesToSkip) {
systemDrawScreen();
frameCount = 0;
@@ -4204,7 +3728,7 @@ void CPULoop(int ticks)
DISPSTAT |= 2;
UPDATE_REG(0x04, DISPSTAT);
lcdTicks += 224;
- cpuDmaHack2 = CPUCheckDMA(2, 0x0f);
+ CPUCheckDMA(2, 0x0f);
if(DISPSTAT & 16) {
IF |= 2;
UPDATE_REG(0x202, IF);
@@ -4367,7 +3891,7 @@ void CPULoop(int ticks)
goto updateLoop;
}
#ifdef LINK_EMULATION
- if(linkenable && cpuDmaHack2)
+ if(linkenable)
cpuNextEvent = 1;
#endif
if(IF && (IME & 1) && armIrqEnable) {
diff --git a/trunk/src/GBA.h b/trunk/src/GBA.h
index 3595500e..30bf450f 100644
--- a/trunk/src/GBA.h
+++ b/trunk/src/GBA.h
@@ -84,6 +84,7 @@ extern bool armState;
extern int armMode;
extern void (*cpuSaveGameFunc)(u32,u8);
+#ifdef BKPT_SUPPORT
extern u8 freezeWorkRAM[0x40000];
extern u8 freezeInternalRAM[0x8000];
extern u8 freezeVRAM[0x18000];
@@ -92,6 +93,7 @@ extern u8 freezePRAM[0x400];
extern bool debugger_last;
extern int oldreg[17];
extern char oldbuffer[10];
+#endif
extern bool CPUReadGSASnapshot(const char *);
extern bool CPUWriteGSASnapshot(const char *, const char *, const char *, const char *);
@@ -111,12 +113,10 @@ extern int CPULoadRom(const char *);
extern void doMirroring(bool);
extern void CPUUpdateRegister(u32, u16);
extern void applyTimer ();
-extern void CPUWriteHalfWord(u32, u16);
-extern void CPUWriteByte(u32, u8);
extern void CPUInit(const char *,bool);
extern void CPUReset();
extern void CPULoop(int);
-extern bool CPUCheckDMA(int,int);
+extern void CPUCheckDMA(int,int);
extern bool CPUIsGBAImage(const char *);
extern bool CPUIsZipFile(const char *);
#ifdef PROFILING
diff --git a/trunk/src/GBAcpu.h b/trunk/src/GBAcpu.h
new file mode 100644
index 00000000..3309df91
--- /dev/null
+++ b/trunk/src/GBAcpu.h
@@ -0,0 +1,302 @@
+// -*- C++ -*-
+// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
+// Copyright (C) 1999-2003 Forgotten
+// Copyright (C) 2005 Forgotten and the VBA development team
+
+// 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, 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.
+
+#ifndef VBA_GBAcpu_H
+#define VBA_GBAcpu_H
+
+extern int armExecute();
+extern int thumbExecute();
+
+#ifdef __GNUC__
+# define INSN_REGPARM __attribute__((regparm(1)))
+# define LIKELY(x) __builtin_expect(!!(x),1)
+# define UNLIKELY(x) __builtin_expect(!!(x),0)
+#else
+# define INSN_REGPARM /*nothing*/
+# define LIKELY(x) (x)
+# define UNLIKELY(x) (x)
+#endif
+
+#define UPDATE_REG(address, value)\
+ {\
+ WRITE16LE(((u16 *)&ioMem[address]),value);\
+ }\
+
+#define ARM_PREFETCH \
+ {\
+ cpuPrefetch[0] = CPUReadMemoryQuick(armNextPC);\
+ cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);\
+ }
+
+#define THUMB_PREFETCH \
+ {\
+ cpuPrefetch[0] = CPUReadHalfWordQuick(armNextPC);\
+ cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);\
+ }
+
+#define ARM_PREFETCH_NEXT \
+ cpuPrefetch[1] = CPUReadMemoryQuick(armNextPC+4);
+
+#define THUMB_PREFETCH_NEXT\
+ cpuPrefetch[1] = CPUReadHalfWordQuick(armNextPC+2);
+
+
+extern int SWITicks;
+extern u32 mastercode;
+extern bool busPrefetch;
+extern bool busPrefetchEnable;
+extern u32 busPrefetchCount;
+extern int cpuNextEvent;
+extern bool holdState;
+extern u32 cpuPrefetch[2];
+extern int cpuTotalTicks;
+extern u8 memoryWait[16];
+extern u8 memoryWait32[16];
+extern u8 memoryWaitSeq[16];
+extern u8 memoryWaitSeq32[16];
+extern u8 cpuBitsSet[256];
+extern u8 cpuLowestBitSet[256];
+extern void CPUSwitchMode(int mode, bool saveState, bool breakLoop);
+extern void CPUSwitchMode(int mode, bool saveState);
+extern void CPUUpdateCPSR();
+extern void CPUUpdateFlags(bool breakLoop);
+extern void CPUUpdateFlags();
+extern void CPUUndefinedException();
+extern void CPUSoftwareInterrupt();
+extern void CPUSoftwareInterrupt(int comment);
+
+
+// Waitstates when accessing data
+inline int dataTicksAccess16(u32 address) // DATA 8/16bits NON SEQ
+{
+ int addr = (address>>24)&15;
+ int value = memoryWait[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<>24)&15;
+ int value = memoryWait32[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<>24)&15;
+ int value = memoryWaitSeq[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<>24)&15;
+ int value = memoryWaitSeq32[addr];
+
+ if ((addr>=0x08) || (addr < 0x02))
+ {
+ busPrefetchCount=0;
+ busPrefetch=false;
+ }
+ else if (busPrefetch)
+ {
+ int waitState = value;
+ if (!waitState)
+ waitState = 1;
+ busPrefetchCount = ((busPrefetchCount+1)<>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ if (busPrefetchCount&0x2)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return memoryWaitSeq[addr]-1;
+ }
+ else
+ {
+ busPrefetchCount=0;
+ return memoryWait[addr];
+ }
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWait[addr];
+ }
+}
+
+inline int codeTicksAccess32(u32 address) // ARM NON SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ if (busPrefetchCount&0x2)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return memoryWaitSeq[addr] - 1;
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWait32[addr];
+ }
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWait32[addr];
+ }
+}
+
+inline int codeTicksAccessSeq16(u32 address) // THUMB SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ else
+ if (busPrefetchCount>0xFF)
+ {
+ busPrefetchCount=0;
+ return memoryWait[addr];
+ }
+ else
+ return memoryWaitSeq[addr];
+ }
+ else
+ {
+ busPrefetchCount = 0;
+ return memoryWaitSeq[addr];
+ }
+}
+
+inline int codeTicksAccessSeq32(u32 address) // ARM SEQ
+{
+ int addr = (address>>24)&15;
+
+ if ((addr>=0x08) && (addr<=0x0D))
+ {
+ if (busPrefetchCount&0x1)
+ {
+ if (busPrefetchCount&0x2)
+ {
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>2) | (busPrefetchCount&0xFFFFFF00);
+ return 0;
+ }
+ busPrefetchCount = ((busPrefetchCount&0xFF)>>1) | (busPrefetchCount&0xFFFFFF00);
+ return memoryWaitSeq[addr];
+ }
+ else
+ if (busPrefetchCount>0xFF)
+ {
+ busPrefetchCount=0;
+ return memoryWait32[addr];
+ }
+ else
+ return memoryWaitSeq32[addr];
+ }
+ else
+ {
+ return memoryWaitSeq32[addr];
+ }
+}
+
+
+// Emulates the Cheat System (m) code
+inline void cpuMasterCodeCheck()
+{
+ if((cheatsEnabled) && (mastercode) && (mastercode == armNextPC))
+ {
+ u32 joy = 0;
+ if(systemReadJoypads())
+ joy = systemReadJoypad(-1);
+ u32 ext = (joy >> 10);
+ cpuTotalTicks += cheatsCheckKeys(P1^0x3FF, ext);
+ }
+}
+
+#endif //VBA_GBAcpu_H
diff --git a/trunk/src/GBAinline.h b/trunk/src/GBAinline.h
index af00337b..674ed971 100644
--- a/trunk/src/GBAinline.h
+++ b/trunk/src/GBAinline.h
@@ -23,6 +23,15 @@
#include "System.h"
#include "Port.h"
#include "RTC.h"
+#include "Sound.h"
+#include "agbprint.h"
+
+extern const u32 objTilesAddress[3];
+
+extern bool stopState;
+extern bool holdState;
+extern int holdType;
+extern int cpuNextEvent;
extern bool cpuSramEnabled;
extern bool cpuFlashEnabled;
@@ -34,7 +43,6 @@ extern bool linkenable;
extern void LinkSStop(void);
#endif /* LINK_EMULATION */
extern bool cpuDmaHack;
-extern bool cpuDmaHack2;
extern u32 cpuDmaLast;
extern bool timer0On;
extern int timer0Ticks;
@@ -150,7 +158,7 @@ static inline u32 CPUReadMemory(u32 address)
}
#endif
- if(cpuDmaHack || cpuDmaHack2) {
+ if(cpuDmaHack) {
value = cpuDmaLast;
} else {
if(armState) {
@@ -292,7 +300,7 @@ static inline u32 CPUReadHalfWord(u32 address)
armNextPC - 4 : armNextPC - 2);
}
#endif
- if(cpuDmaHack2 || cpuDmaHack) {
+ if(cpuDmaHack) {
value = cpuDmaLast & 0xFFFF;
} else {
if(armState) {
@@ -392,7 +400,7 @@ static inline u8 CPUReadByte(u32 address)
armNextPC - 4 : armNextPC - 2);
}
#endif
- if(cpuDmaHack || cpuDmaHack2) {
+ if(cpuDmaHack) {
return cpuDmaLast & 0xFF;
} else {
if(armState) {
@@ -503,4 +511,246 @@ static inline void CPUWriteMemory(u32 address, u32 value)
}
}
+static inline void CPUWriteHalfWord(u32 address, u16 value)
+{
+#ifdef DEV_VERSION
+ if(address & 1) {
+ if(systemVerbose & VERBOSE_UNALIGNED_MEMORY) {
+ log("Unaligned halfword write: %04x to %08x from %08x\n",
+ value,
+ address,
+ armMode ? armNextPC - 4 : armNextPC - 2);
+ }
+ }
+#endif
+
+ switch(address >> 24) {
+ case 2:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeWorkRAM[address & 0x3FFFE]))
+ cheatsWriteHalfWord(address & 0x203FFFE,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&workRAM[address & 0x3FFFE]),value);
+ break;
+ case 3:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeInternalRAM[address & 0x7ffe]))
+ cheatsWriteHalfWord(address & 0x3007ffe,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&internalRAM[address & 0x7ffe]), value);
+ break;
+ case 4:
+ if(address < 0x4000400)
+ CPUUpdateRegister(address & 0x3fe, value);
+ else goto unwritable;
+ break;
+ case 5:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezePRAM[address & 0x03fe]))
+ cheatsWriteHalfWord(address & 0x70003fe,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&paletteRAM[address & 0x3fe]), value);
+ break;
+ case 6:
+ address = (address & 0x1fffe);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ return;
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeVRAM[address]))
+ cheatsWriteHalfWord(address + 0x06000000,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&vram[address]), value);
+ break;
+ case 7:
+#ifdef BKPT_SUPPORT
+ if(*((u16 *)&freezeOAM[address & 0x03fe]))
+ cheatsWriteHalfWord(address & 0x70003fe,
+ value);
+ else
+#endif
+ WRITE16LE(((u16 *)&oam[address & 0x3fe]), value);
+ break;
+ case 8:
+ case 9:
+ if(address == 0x80000c4 || address == 0x80000c6 || address == 0x80000c8) {
+ if(!rtcWrite(address, value))
+ goto unwritable;
+ } else if(!agbPrintWrite(address, value)) goto unwritable;
+ break;
+ case 13:
+ if(cpuEEPROMEnabled) {
+ eepromWrite(address, (u8)value);
+ break;
+ }
+ goto unwritable;
+ case 14:
+ if(!eepromInUse | cpuSramEnabled | cpuFlashEnabled) {
+ (*cpuSaveGameFunc)(address, (u8)value);
+ break;
+ }
+ goto unwritable;
+ default:
+ unwritable:
+#ifdef DEV_VERSION
+ if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
+ log("Illegal halfword write: %04x to %08x from %08x\n",
+ value,
+ address,
+ armMode ? armNextPC - 4 : armNextPC - 2);
+ }
+#endif
+ break;
+ }
+}
+
+static inline void CPUWriteByte(u32 address, u8 b)
+{
+ switch(address >> 24) {
+ case 2:
+#ifdef BKPT_SUPPORT
+ if(freezeWorkRAM[address & 0x3FFFF])
+ cheatsWriteByte(address & 0x203FFFF, b);
+ else
+#endif
+ workRAM[address & 0x3FFFF] = b;
+ break;
+ case 3:
+#ifdef BKPT_SUPPORT
+ if(freezeInternalRAM[address & 0x7fff])
+ cheatsWriteByte(address & 0x3007fff, b);
+ else
+#endif
+ internalRAM[address & 0x7fff] = b;
+ break;
+ case 4:
+ if(address < 0x4000400) {
+ switch(address & 0x3FF) {
+ case 0x301:
+ if(b == 0x80)
+ stopState = true;
+ holdState = 1;
+ holdType = -1;
+ cpuNextEvent = cpuTotalTicks;
+ break;
+ case 0x60:
+ case 0x61:
+ case 0x62:
+ case 0x63:
+ case 0x64:
+ case 0x65:
+ case 0x68:
+ case 0x69:
+ case 0x6c:
+ case 0x6d:
+ case 0x70:
+ case 0x71:
+ case 0x72:
+ case 0x73:
+ case 0x74:
+ case 0x75:
+ case 0x78:
+ case 0x79:
+ case 0x7c:
+ case 0x7d:
+ case 0x80:
+ case 0x81:
+ case 0x84:
+ case 0x85:
+ case 0x90:
+ case 0x91:
+ case 0x92:
+ case 0x93:
+ case 0x94:
+ case 0x95:
+ case 0x96:
+ case 0x97:
+ case 0x98:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0x9f:
+ soundEvent(address&0xFF, b);
+ break;
+ default:
+ if(address & 1)
+ CPUUpdateRegister(address & 0x3fe,
+ ((READ16LE(((u16 *)&ioMem[address & 0x3fe])))
+ & 0x00FF) |
+ b<<8);
+ else
+ CPUUpdateRegister(address & 0x3fe,
+ ((READ16LE(((u16 *)&ioMem[address & 0x3fe])) & 0xFF00) | b));
+ }
+ break;
+ } else goto unwritable;
+ break;
+ case 5:
+ // no need to switch
+ *((u16 *)&paletteRAM[address & 0x3FE]) = (b << 8) | b;
+ break;
+ case 6:
+ address = (address & 0x1fffe);
+ if (((DISPCNT & 7) >2) && ((address & 0x1C000) == 0x18000))
+ return;
+ if ((address & 0x18000) == 0x18000)
+ address &= 0x17fff;
+
+ // no need to switch
+ // byte writes to OBJ VRAM are ignored
+ if ((address) < objTilesAddress[((DISPCNT&7)+1)>>2])
+ {
+#ifdef BKPT_SUPPORT
+ if(freezeVRAM[address])
+ cheatsWriteByte(address + 0x06000000, b);
+ else
+#endif
+ *((u16 *)&vram[address]) = (b << 8) | b;
+ }
+ break;
+ case 7:
+ // no need to switch
+ // byte writes to OAM are ignored
+ // *((u16 *)&oam[address & 0x3FE]) = (b << 8) | b;
+ break;
+ case 13:
+ if(cpuEEPROMEnabled) {
+ eepromWrite(address, b);
+ break;
+ }
+ goto unwritable;
+ case 14:
+ if (!(saveType == 5) && (!eepromInUse | cpuSramEnabled | cpuFlashEnabled)) {
+
+ //if(!cpuEEPROMEnabled && (cpuSramEnabled | cpuFlashEnabled)) {
+
+ (*cpuSaveGameFunc)(address, b);
+ break;
+ }
+ // default
+ default:
+ unwritable:
+#ifdef DEV_VERSION
+ if(systemVerbose & VERBOSE_ILLEGAL_WRITE) {
+ log("Illegal byte write: %02x to %08x from %08x\n",
+ b,
+ address,
+ armMode ? armNextPC - 4 : armNextPC -2 );
+ }
+#endif
+ break;
+ }
+}
#endif //VBA_GBAinline_H
diff --git a/trunk/src/Sound.cpp b/trunk/src/Sound.cpp
index d4d0750a..ca3f63df 100644
--- a/trunk/src/Sound.cpp
+++ b/trunk/src/Sound.cpp
@@ -949,13 +949,13 @@ void soundChannel4()
}
-extern bool cpuDmaHack2;
+
void soundDirectSoundATimer()
{
if(soundDSAEnabled) {
if(soundDSFifoACount <= 16) {
- cpuDmaHack2 = CPUCheckDMA(3, 2);
+ CPUCheckDMA(3, 2);
if(soundDSFifoACount <= 16) {
soundEvent(FIFOA_L, (u16)0);
soundEvent(FIFOA_H, (u16)0);
@@ -989,7 +989,7 @@ void soundDirectSoundBTimer()
{
if(soundDSBEnabled) {
if(soundDSFifoBCount <= 16) {
- cpuDmaHack2 = CPUCheckDMA(3, 4);
+ CPUCheckDMA(3, 4);
if(soundDSFifoBCount <= 16) {
soundEvent(FIFOB_L, (u16)0);
soundEvent(FIFOB_H, (u16)0);
diff --git a/trunk/src/win32/IOViewer.cpp b/trunk/src/win32/IOViewer.cpp
index 33770388..1a96a0e5 100644
--- a/trunk/src/win32/IOViewer.cpp
+++ b/trunk/src/win32/IOViewer.cpp
@@ -26,7 +26,7 @@
#include "../System.h"
#include "../GBA.h"
#include "../Globals.h"
-
+#include "../GBAinline.h"
#include "IOViewerRegs.h"
#ifdef _DEBUG