mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-01 08:25:12 +01:00
7473 lines
210 KiB
C++
7473 lines
210 KiB
C++
// -*- C++ -*-
|
|
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
|
// Copyright (C) 1999-2003 Forgotten
|
|
// Copyright (C) 2004 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.
|
|
|
|
#ifdef BKPT_SUPPORT
|
|
#define CONSOLE_OUTPUT(a,b) \
|
|
extern void (*dbgOutput)(char *, u32);\
|
|
if((opcode == 0xe0000000) && (reg[0].I == 0xC0DED00D)) {\
|
|
dbgOutput((a), (b));\
|
|
}
|
|
#else
|
|
#define CONSOLE_OUTPUT(a,b)
|
|
#endif
|
|
|
|
#define OP_AND \
|
|
reg[dest].I = reg[(opcode>>16)&15].I & value;\
|
|
CONSOLE_OUTPUT(NULL,reg[2].I);
|
|
|
|
#define OP_ANDS \
|
|
reg[dest].I = reg[(opcode>>16)&15].I & value;\
|
|
\
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
|
|
Z_FLAG = (reg[dest].I) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define OP_EOR \
|
|
reg[dest].I = reg[(opcode>>16)&15].I ^ value;
|
|
|
|
#define OP_EORS \
|
|
reg[dest].I = reg[(opcode>>16)&15].I ^ value;\
|
|
\
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
|
|
Z_FLAG = (reg[dest].I) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
#ifdef C_CORE
|
|
#define NEG(i) ((i) >> 31)
|
|
#define POS(i) ((~(i)) >> 31)
|
|
#define ADDCARRY(a, b, c) \
|
|
C_FLAG = ((NEG(a) & NEG(b)) |\
|
|
(NEG(a) & POS(c)) |\
|
|
(NEG(b) & POS(c))) ? true : false;
|
|
#define ADDOVERFLOW(a, b, c) \
|
|
V_FLAG = ((NEG(a) & NEG(b) & POS(c)) |\
|
|
(POS(a) & POS(b) & NEG(c))) ? true : false;
|
|
#define SUBCARRY(a, b, c) \
|
|
C_FLAG = ((NEG(a) & POS(b)) |\
|
|
(NEG(a) & POS(c)) |\
|
|
(POS(b) & POS(c))) ? true : false;
|
|
#define SUBOVERFLOW(a, b, c)\
|
|
V_FLAG = ((NEG(a) & POS(b) & POS(c)) |\
|
|
(POS(a) & NEG(b) & NEG(c))) ? true : false;
|
|
#define OP_SUB \
|
|
{\
|
|
reg[dest].I = reg[base].I - value;\
|
|
}
|
|
#define OP_SUBS \
|
|
{\
|
|
u32 lhs = reg[base].I;\
|
|
u32 rhs = value;\
|
|
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);\
|
|
}
|
|
#define OP_RSB \
|
|
{\
|
|
reg[dest].I = value - reg[base].I;\
|
|
}
|
|
#define OP_RSBS \
|
|
{\
|
|
u32 lhs = reg[base].I;\
|
|
u32 rhs = value;\
|
|
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);\
|
|
}
|
|
#define OP_ADD \
|
|
{\
|
|
reg[dest].I = reg[base].I + value;\
|
|
}
|
|
#define OP_ADDS \
|
|
{\
|
|
u32 lhs = reg[base].I;\
|
|
u32 rhs = value;\
|
|
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);\
|
|
}
|
|
#define OP_ADC \
|
|
{\
|
|
reg[dest].I = reg[base].I + value + (u32)C_FLAG;\
|
|
}
|
|
#define OP_ADCS \
|
|
{\
|
|
u32 lhs = reg[base].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);\
|
|
}
|
|
#define OP_SBC \
|
|
{\
|
|
reg[dest].I = reg[base].I - value - !((u32)C_FLAG);\
|
|
}
|
|
#define OP_SBCS \
|
|
{\
|
|
u32 lhs = reg[base].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);\
|
|
}
|
|
#define OP_RSC \
|
|
{\
|
|
reg[dest].I = value - reg[base].I - !((u32)C_FLAG);\
|
|
}
|
|
#define OP_RSCS \
|
|
{\
|
|
u32 lhs = reg[base].I;\
|
|
u32 rhs = value;\
|
|
u32 res = rhs - lhs - !((u32)C_FLAG);\
|
|
reg[dest].I = res;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
SUBCARRY(rhs, lhs, res);\
|
|
SUBOVERFLOW(rhs, lhs, res);\
|
|
}
|
|
#define OP_CMP \
|
|
{\
|
|
u32 lhs = reg[base].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);\
|
|
}
|
|
#define OP_CMN \
|
|
{\
|
|
u32 lhs = reg[base].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);\
|
|
}
|
|
|
|
#define LOGICAL_LSL_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = (v >> (32 - shift)) & 1 ? true : false;\
|
|
value = v << shift;\
|
|
}
|
|
#define LOGICAL_LSR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
|
value = v >> shift;\
|
|
}
|
|
#define LOGICAL_ASR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false;\
|
|
value = (s32)v >> (int)shift;\
|
|
}
|
|
#define LOGICAL_ROR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define LOGICAL_RRX_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
shift = (int)C_FLAG;\
|
|
C_OUT = (v & 1) ? true : false;\
|
|
value = ((v >> 1) |\
|
|
(shift << 31));\
|
|
}
|
|
#define LOGICAL_ROR_IMM \
|
|
{\
|
|
u32 v = opcode & 0xff;\
|
|
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ARITHMETIC_LSL_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = v << shift;\
|
|
}
|
|
#define ARITHMETIC_LSR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = v >> shift;\
|
|
}
|
|
#define ARITHMETIC_ASR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = (s32)v >> (int)shift;\
|
|
}
|
|
#define ARITHMETIC_ROR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ARITHMETIC_RRX_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
shift = (int)C_FLAG;\
|
|
value = ((v >> 1) |\
|
|
(shift << 31));\
|
|
}
|
|
#define ARITHMETIC_ROR_IMM \
|
|
{\
|
|
u32 v = opcode & 0xff;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ROR_IMM_MSR \
|
|
{\
|
|
u32 v = opcode & 0xff;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ROR_VALUE \
|
|
{\
|
|
value = ((value << (32 - shift)) |\
|
|
(value >> shift));\
|
|
}
|
|
#define RCR_VALUE \
|
|
{\
|
|
shift = (int)C_FLAG;\
|
|
value = ((value >> 1) |\
|
|
(shift << 31));\
|
|
}
|
|
#else
|
|
#ifdef __GNUC__
|
|
#ifdef __POWERPC__
|
|
#define OP_SUB \
|
|
{\
|
|
reg[dest].I = reg[base].I - value;\
|
|
}
|
|
#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_RSB \
|
|
{\
|
|
reg[dest].I = value - reg[base].I;\
|
|
}
|
|
#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_ADD \
|
|
{\
|
|
reg[dest].I = reg[base].I + value;\
|
|
}
|
|
|
|
#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_ADC \
|
|
{\
|
|
reg[dest].I = reg[base].I + value + (u32)C_FLAG;\
|
|
}
|
|
#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_SBC \
|
|
{\
|
|
reg[dest].I = reg[base].I - value - (C_FLAG^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_RSC \
|
|
{\
|
|
reg[dest].I = value - reg[base].I - (C_FLAG^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; \
|
|
}
|
|
|
|
#define LOGICAL_LSL_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = (v >> (32 - shift)) & 1 ? true : false;\
|
|
value = v << shift;\
|
|
}
|
|
#define LOGICAL_LSR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
|
value = v >> shift;\
|
|
}
|
|
#define LOGICAL_ASR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = ((s32)v >> (int)(shift - 1)) & 1 ? true : false;\
|
|
value = (s32)v >> (int)shift;\
|
|
}
|
|
#define LOGICAL_ROR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define LOGICAL_RRX_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
shift = (int)C_FLAG;\
|
|
C_OUT = (v & 1) ? true : false;\
|
|
value = ((v >> 1) |\
|
|
(shift << 31));\
|
|
}
|
|
#define LOGICAL_ROR_IMM \
|
|
{\
|
|
u32 v = opcode & 0xff;\
|
|
C_OUT = (v >> (shift - 1)) & 1 ? true : false;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ARITHMETIC_LSL_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = v << shift;\
|
|
}
|
|
#define ARITHMETIC_LSR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = v >> shift;\
|
|
}
|
|
#define ARITHMETIC_ASR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = (s32)v >> (int)shift;\
|
|
}
|
|
#define ARITHMETIC_ROR_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ARITHMETIC_RRX_REG \
|
|
{\
|
|
u32 v = reg[opcode & 0x0f].I;\
|
|
shift = (int)C_FLAG;\
|
|
value = ((v >> 1) |\
|
|
(shift << 31));\
|
|
}
|
|
#define ARITHMETIC_ROR_IMM \
|
|
{\
|
|
u32 v = opcode & 0xff;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ROR_IMM_MSR \
|
|
{\
|
|
u32 v = opcode & 0xff;\
|
|
value = ((v << (32 - shift)) |\
|
|
(v >> shift));\
|
|
}
|
|
#define ROR_VALUE \
|
|
{\
|
|
value = ((value << (32 - shift)) |\
|
|
(value >> shift));\
|
|
}
|
|
#define RCR_VALUE \
|
|
{\
|
|
shift = (int)C_FLAG;\
|
|
value = ((value >> 1) |\
|
|
(shift << 31));\
|
|
}
|
|
#else
|
|
#define OP_SUB \
|
|
asm ("sub %1, %%ebx;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[base].I));
|
|
|
|
#define OP_SUBS \
|
|
asm ("sub %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[base].I));
|
|
|
|
#define OP_RSB \
|
|
asm ("sub %1, %%ebx;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (reg[base].I), "b" (value));
|
|
|
|
#define OP_RSBS \
|
|
asm ("sub %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (reg[base].I), "b" (value));
|
|
|
|
#define OP_ADD \
|
|
asm ("add %1, %%ebx;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[base].I));
|
|
|
|
#define OP_ADDS \
|
|
asm ("add %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[base].I));
|
|
|
|
#define OP_ADC \
|
|
asm ("bt $0, C_FLAG;"\
|
|
"adc %1, %%ebx;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[base].I));
|
|
|
|
#define OP_ADCS \
|
|
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[base].I));
|
|
|
|
#define OP_SBC \
|
|
asm ("bt $0, C_FLAG;"\
|
|
"cmc;"\
|
|
"sbb %1, %%ebx;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[base].I));
|
|
|
|
#define OP_SBCS \
|
|
asm ("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[base].I));
|
|
#define OP_RSC \
|
|
asm ("bt $0, C_FLAG;"\
|
|
"cmc;"\
|
|
"sbb %1, %%ebx;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (reg[base].I), "b" (value));
|
|
|
|
#define OP_RSCS \
|
|
asm ("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" (reg[base].I), "b" (value));
|
|
#define OP_CMP \
|
|
asm ("sub %0, %1;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
:\
|
|
: "r" (value), "r" (reg[base].I));
|
|
|
|
#define OP_CMN \
|
|
asm ("add %0, %1;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: \
|
|
: "r" (value), "r" (reg[base].I));
|
|
#define LOGICAL_LSL_REG \
|
|
asm("shl %%cl, %%eax;"\
|
|
"setcb %%cl;"\
|
|
: "=a" (value), "=c" (C_OUT)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define LOGICAL_LSR_REG \
|
|
asm("shr %%cl, %%eax;"\
|
|
"setcb %%cl;"\
|
|
: "=a" (value), "=c" (C_OUT)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define LOGICAL_ASR_REG \
|
|
asm("sar %%cl, %%eax;"\
|
|
"setcb %%cl;"\
|
|
: "=a" (value), "=c" (C_OUT)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define LOGICAL_ROR_REG \
|
|
asm("ror %%cl, %%eax;"\
|
|
"setcb %%cl;"\
|
|
: "=a" (value), "=c" (C_OUT)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define LOGICAL_RRX_REG \
|
|
asm("bt $0, C_FLAG;"\
|
|
"rcr $1, %%eax;"\
|
|
"setcb %%cl;"\
|
|
: "=a" (value), "=c" (C_OUT)\
|
|
: "a" (reg[opcode & 0x0f].I));
|
|
|
|
#define LOGICAL_ROR_IMM \
|
|
asm("ror %%cl, %%eax;"\
|
|
"setcb %%cl;"\
|
|
: "=a" (value), "=c" (C_OUT)\
|
|
: "a" (opcode & 0xff), "c" (shift));
|
|
#define ARITHMETIC_LSL_REG \
|
|
asm("\
|
|
shl %%cl, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define ARITHMETIC_LSR_REG \
|
|
asm("\
|
|
shr %%cl, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define ARITHMETIC_ASR_REG \
|
|
asm("\
|
|
sar %%cl, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define ARITHMETIC_ROR_REG \
|
|
asm("\
|
|
ror %%cl, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[opcode & 0x0f].I), "c" (shift));
|
|
|
|
#define ARITHMETIC_RRX_REG \
|
|
asm("\
|
|
bt $0, C_FLAG;\
|
|
rcr $1, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[opcode & 0x0f].I));
|
|
|
|
#define ARITHMETIC_ROR_IMM \
|
|
asm("\
|
|
ror %%cl, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (opcode & 0xff), "c" (shift));
|
|
#define ROR_IMM_MSR \
|
|
asm ("ror %%cl, %%eax;"\
|
|
: "=a" (value)\
|
|
: "a" (opcode & 0xFF), "c" (shift));
|
|
#define ROR_VALUE \
|
|
asm("ror %%cl, %0"\
|
|
: "=r" (value)\
|
|
: "r" (value), "c" (shift));
|
|
#define RCR_VALUE \
|
|
asm("bt $0, C_FLAG;"\
|
|
"rcr $1, %0"\
|
|
: "=r" (value)\
|
|
: "r" (value));
|
|
#endif
|
|
#else
|
|
#define OP_SUB \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm sub ebx, value\
|
|
__asm mov eax, dest\
|
|
__asm mov dword ptr [OFFSET reg+4*eax], ebx\
|
|
}
|
|
|
|
#define OP_SUBS \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm sub 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 setnc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
|
|
#define OP_RSB \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm mov eax, value\
|
|
__asm sub eax, ebx\
|
|
__asm mov ebx, dest\
|
|
__asm mov dword ptr [OFFSET reg+4*ebx], eax\
|
|
}
|
|
|
|
#define OP_RSBS \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm mov eax, value\
|
|
__asm sub eax, ebx\
|
|
__asm mov ebx, dest\
|
|
__asm mov dword ptr [OFFSET reg+4*ebx], eax\
|
|
__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 OP_ADD \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm add ebx, value\
|
|
__asm mov eax, dest\
|
|
__asm mov dword ptr [OFFSET reg+4*eax], ebx\
|
|
}
|
|
|
|
#define OP_ADDS \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm add 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 OP_ADC \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__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\
|
|
}
|
|
|
|
#define OP_ADCS \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__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 OP_SBC \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__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\
|
|
}
|
|
|
|
#define OP_SBCS \
|
|
{\
|
|
__asm mov ebx, base\
|
|
__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 OP_RSC \
|
|
{\
|
|
__asm mov ebx, value\
|
|
__asm mov eax, base\
|
|
__asm mov eax, dword ptr[OFFSET reg + 4*eax]\
|
|
__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\
|
|
}
|
|
|
|
#define OP_RSCS \
|
|
{\
|
|
__asm mov ebx, value\
|
|
__asm mov eax, base\
|
|
__asm mov eax, dword ptr[OFFSET reg + 4*eax]\
|
|
__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 OP_CMP \
|
|
{\
|
|
__asm mov eax, base\
|
|
__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\
|
|
}
|
|
|
|
#define OP_CMN \
|
|
{\
|
|
__asm mov eax, base\
|
|
__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 LOGICAL_LSL_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0f\
|
|
__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_OUT
|
|
|
|
#define LOGICAL_LSR_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0f\
|
|
__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_OUT
|
|
|
|
#define LOGICAL_ASR_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0f\
|
|
__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_OUT
|
|
|
|
#define LOGICAL_ROR_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0F\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm ror eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_OUT
|
|
|
|
#define LOGICAL_RRX_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0F\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm bt word ptr C_OUT, 0\
|
|
__asm rcr eax, 1\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_OUT
|
|
|
|
#define LOGICAL_ROR_IMM \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0xff\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm ror eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_OUT
|
|
#define ARITHMETIC_LSL_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0f\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm shl eax, cl\
|
|
__asm mov value, eax
|
|
|
|
#define ARITHMETIC_LSR_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0f\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm shr eax, cl\
|
|
__asm mov value, eax
|
|
|
|
#define ARITHMETIC_ASR_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0f\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm sar eax, cl\
|
|
__asm mov value, eax
|
|
|
|
#define ARITHMETIC_ROR_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0F\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm ror eax, cl\
|
|
__asm mov value, eax
|
|
|
|
#define ARITHMETIC_RRX_REG \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0x0F\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm bt word ptr C_FLAG, 0\
|
|
__asm rcr eax, 1\
|
|
__asm mov value, eax
|
|
|
|
#define ARITHMETIC_ROR_IMM \
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0xff\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm ror eax, cl\
|
|
__asm mov value, eax
|
|
#define ROR_IMM_MSR \
|
|
{\
|
|
__asm mov eax, opcode\
|
|
__asm and eax, 0xff\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm ror eax, CL\
|
|
__asm mov value, eax\
|
|
}
|
|
#define ROR_VALUE \
|
|
{\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm ror dword ptr value, cl\
|
|
}
|
|
#define RCR_VALUE \
|
|
{\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm bt word ptr C_FLAG, 0\
|
|
__asm rcr dword ptr value, 1\
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#define OP_TST \
|
|
u32 res = reg[base].I & value;\
|
|
N_FLAG = (res & 0x80000000) ? true : false;\
|
|
Z_FLAG = (res) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define OP_TEQ \
|
|
u32 res = reg[base].I ^ value;\
|
|
N_FLAG = (res & 0x80000000) ? true : false;\
|
|
Z_FLAG = (res) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define OP_ORR \
|
|
reg[dest].I = reg[base].I | value;
|
|
|
|
#define OP_ORRS \
|
|
reg[dest].I = reg[base].I | value;\
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
|
|
Z_FLAG = (reg[dest].I) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define OP_MOV \
|
|
reg[dest].I = value;
|
|
|
|
#define OP_MOVS \
|
|
reg[dest].I = value;\
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
|
|
Z_FLAG = (reg[dest].I) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define OP_BIC \
|
|
reg[dest].I = reg[base].I & (~value);
|
|
|
|
#define OP_BICS \
|
|
reg[dest].I = reg[base].I & (~value);\
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
|
|
Z_FLAG = (reg[dest].I) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define OP_MVN \
|
|
reg[dest].I = ~value;
|
|
|
|
#define OP_MVNS \
|
|
reg[dest].I = ~value; \
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;\
|
|
Z_FLAG = (reg[dest].I) ? false : true;\
|
|
C_FLAG = C_OUT;
|
|
|
|
#define CASE_16(BASE) \
|
|
case BASE:\
|
|
case BASE+1:\
|
|
case BASE+2:\
|
|
case BASE+3:\
|
|
case BASE+4:\
|
|
case BASE+5:\
|
|
case BASE+6:\
|
|
case BASE+7:\
|
|
case BASE+8:\
|
|
case BASE+9:\
|
|
case BASE+10:\
|
|
case BASE+11:\
|
|
case BASE+12:\
|
|
case BASE+13:\
|
|
case BASE+14:\
|
|
case BASE+15:
|
|
|
|
#define CASE_256(BASE) \
|
|
CASE_16(BASE)\
|
|
CASE_16(BASE+0x10)\
|
|
CASE_16(BASE+0x20)\
|
|
CASE_16(BASE+0x30)\
|
|
CASE_16(BASE+0x40)\
|
|
CASE_16(BASE+0x50)\
|
|
CASE_16(BASE+0x60)\
|
|
CASE_16(BASE+0x70)\
|
|
CASE_16(BASE+0x80)\
|
|
CASE_16(BASE+0x90)\
|
|
CASE_16(BASE+0xa0)\
|
|
CASE_16(BASE+0xb0)\
|
|
CASE_16(BASE+0xc0)\
|
|
CASE_16(BASE+0xd0)\
|
|
CASE_16(BASE+0xe0)\
|
|
CASE_16(BASE+0xf0)
|
|
|
|
#define LOGICAL_DATA_OPCODE(OPCODE, OPCODE2, BASE) \
|
|
case BASE: \
|
|
case BASE+8:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSL # */ \
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
\
|
|
if(shift) {\
|
|
LOGICAL_LSL_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+2:\
|
|
case BASE+10:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSR # */ \
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_LSR_REG\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\
|
|
}\
|
|
\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+4:\
|
|
case BASE+12:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ASR # */\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_ASR_REG\
|
|
} else {\
|
|
if(reg[opcode & 0x0F].I & 0x80000000){\
|
|
value = 0xFFFFFFFF;\
|
|
C_OUT = true;\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
} \
|
|
}\
|
|
\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+6:\
|
|
case BASE+14:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ROR # */\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_ROR_REG\
|
|
} else {\
|
|
LOGICAL_RRX_REG\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+1:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSL Rs */\
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
if(shift == 32) {\
|
|
value = 0;\
|
|
C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\
|
|
} else if(shift < 32) {\
|
|
LOGICAL_LSL_REG\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+3:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSR Rs */ \
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
if(shift == 32) {\
|
|
value = 0;\
|
|
C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\
|
|
} else if(shift < 32) {\
|
|
LOGICAL_LSR_REG\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+5:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ASR Rs */ \
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift < 32) {\
|
|
if(shift) {\
|
|
LOGICAL_ASR_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
} else {\
|
|
if(reg[opcode & 0x0F].I & 0x80000000){\
|
|
value = 0xFFFFFFFF;\
|
|
C_OUT = true;\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
}\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+7:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ROR Rs */\
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
shift &= 0x1f;\
|
|
if(shift) {\
|
|
LOGICAL_ROR_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
C_OUT = (value & 0x80000000 ? true : false);\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
C_OUT = (value & 0x80000000 ? true : false);\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+0x200:\
|
|
case BASE+0x201:\
|
|
case BASE+0x202:\
|
|
case BASE+0x203:\
|
|
case BASE+0x204:\
|
|
case BASE+0x205:\
|
|
case BASE+0x206:\
|
|
case BASE+0x207:\
|
|
case BASE+0x208:\
|
|
case BASE+0x209:\
|
|
case BASE+0x20a:\
|
|
case BASE+0x20b:\
|
|
case BASE+0x20c:\
|
|
case BASE+0x20d:\
|
|
case BASE+0x20e:\
|
|
case BASE+0x20f:\
|
|
{\
|
|
int shift = (opcode & 0xF00) >> 7;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int dest = (opcode >> 12) & 0x0F;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_ROR_IMM\
|
|
} else {\
|
|
value = opcode & 0xff;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;
|
|
|
|
#define LOGICAL_DATA_OPCODE_WITHOUT_base(OPCODE, OPCODE2, BASE) \
|
|
case BASE: \
|
|
case BASE+8:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSL # */ \
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
\
|
|
if(shift) {\
|
|
LOGICAL_LSL_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+2:\
|
|
case BASE+10:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSR # */ \
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_LSR_REG\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = (reg[opcode & 0x0F].I & 0x80000000) ? true : false;\
|
|
}\
|
|
\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+4:\
|
|
case BASE+12:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ASR # */\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_ASR_REG\
|
|
} else {\
|
|
if(reg[opcode & 0x0F].I & 0x80000000){\
|
|
value = 0xFFFFFFFF;\
|
|
C_OUT = true;\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
} \
|
|
}\
|
|
\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+6:\
|
|
case BASE+14:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ROR # */\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_ROR_REG\
|
|
} else {\
|
|
LOGICAL_RRX_REG\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+1:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSL Rs */\
|
|
clockTicks++;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
if(shift == 32) {\
|
|
value = 0;\
|
|
C_OUT = (reg[opcode & 0x0F].I & 1 ? true : false);\
|
|
} else if(shift < 32) {\
|
|
LOGICAL_LSL_REG\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+3:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSR Rs */ \
|
|
clockTicks++;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
if(shift == 32) {\
|
|
value = 0;\
|
|
C_OUT = (reg[opcode & 0x0F].I & 0x80000000 ? true : false);\
|
|
} else if(shift < 32) {\
|
|
LOGICAL_LSR_REG\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+5:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ASR Rs */ \
|
|
clockTicks++;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift < 32) {\
|
|
if(shift) {\
|
|
LOGICAL_ASR_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
} else {\
|
|
if(reg[opcode & 0x0F].I & 0x80000000){\
|
|
value = 0xFFFFFFFF;\
|
|
C_OUT = true;\
|
|
} else {\
|
|
value = 0;\
|
|
C_OUT = false;\
|
|
}\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+7:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ROR Rs */\
|
|
clockTicks++;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
shift &= 0x1f;\
|
|
if(shift) {\
|
|
LOGICAL_ROR_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
C_OUT = (value & 0x80000000 ? true : false);\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
C_OUT = (value & 0x80000000 ? true : false);\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+0x200:\
|
|
case BASE+0x201:\
|
|
case BASE+0x202:\
|
|
case BASE+0x203:\
|
|
case BASE+0x204:\
|
|
case BASE+0x205:\
|
|
case BASE+0x206:\
|
|
case BASE+0x207:\
|
|
case BASE+0x208:\
|
|
case BASE+0x209:\
|
|
case BASE+0x20a:\
|
|
case BASE+0x20b:\
|
|
case BASE+0x20c:\
|
|
case BASE+0x20d:\
|
|
case BASE+0x20e:\
|
|
case BASE+0x20f:\
|
|
{\
|
|
int shift = (opcode & 0xF00) >> 7;\
|
|
int dest = (opcode >> 12) & 0x0F;\
|
|
bool C_OUT = C_FLAG;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
LOGICAL_ROR_IMM\
|
|
} else {\
|
|
value = opcode & 0xff;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;
|
|
|
|
#define ARITHMETIC_DATA_OPCODE(OPCODE, OPCODE2, BASE) \
|
|
case BASE:\
|
|
case BASE+8:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSL # */\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
ARITHMETIC_LSL_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+2:\
|
|
case BASE+10:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSR # */\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
ARITHMETIC_LSR_REG\
|
|
} else {\
|
|
value = 0;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+4:\
|
|
case BASE+12:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ASR # */\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
ARITHMETIC_ASR_REG\
|
|
} else {\
|
|
if(reg[opcode & 0x0F].I & 0x80000000){\
|
|
value = 0xFFFFFFFF;\
|
|
} else value = 0;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+6:\
|
|
case BASE+14:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ROR # */\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = (opcode >> 7) & 0x1F;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
ARITHMETIC_ROR_REG\
|
|
} else {\
|
|
ARITHMETIC_RRX_REG\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+1:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSL Rs */\
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
if(shift == 32) {\
|
|
value = 0;\
|
|
} else if(shift < 32) {\
|
|
ARITHMETIC_LSL_REG\
|
|
} else value = 0;\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+3:\
|
|
{\
|
|
/* OP Rd,Rb,Rm LSR Rs */\
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
if(shift == 32) {\
|
|
value = 0;\
|
|
} else if(shift < 32) {\
|
|
ARITHMETIC_LSR_REG\
|
|
} else value = 0;\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+5:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ASR Rs */\
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift < 32) {\
|
|
if(shift) {\
|
|
ARITHMETIC_ASR_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
} else {\
|
|
if(reg[opcode & 0x0F].I & 0x80000000){\
|
|
value = 0xFFFFFFFF;\
|
|
} else value = 0;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+7:\
|
|
{\
|
|
/* OP Rd,Rb,Rm ROR Rs */\
|
|
clockTicks++;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int shift = reg[(opcode >> 8)&15].B.B0;\
|
|
int dest = (opcode>>12) & 15;\
|
|
u32 value;\
|
|
if(shift) {\
|
|
shift &= 0x1f;\
|
|
if(shift) {\
|
|
ARITHMETIC_ROR_REG\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
} else {\
|
|
value = reg[opcode & 0x0F].I;\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;\
|
|
case BASE+0x200:\
|
|
case BASE+0x201:\
|
|
case BASE+0x202:\
|
|
case BASE+0x203:\
|
|
case BASE+0x204:\
|
|
case BASE+0x205:\
|
|
case BASE+0x206:\
|
|
case BASE+0x207:\
|
|
case BASE+0x208:\
|
|
case BASE+0x209:\
|
|
case BASE+0x20a:\
|
|
case BASE+0x20b:\
|
|
case BASE+0x20c:\
|
|
case BASE+0x20d:\
|
|
case BASE+0x20e:\
|
|
case BASE+0x20f:\
|
|
{\
|
|
int shift = (opcode & 0xF00) >> 7;\
|
|
int base = (opcode >> 16) & 0x0F;\
|
|
int dest = (opcode >> 12) & 0x0F;\
|
|
u32 value;\
|
|
{\
|
|
ARITHMETIC_ROR_IMM\
|
|
}\
|
|
if(dest == 15) {\
|
|
OPCODE2\
|
|
/* todo */\
|
|
if(opcode & 0x00100000) {\
|
|
clockTicks++;\
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);\
|
|
}\
|
|
if(armState) {\
|
|
reg[15].I &= 0xFFFFFFFC;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 4;\
|
|
} else {\
|
|
reg[15].I &= 0xFFFFFFFE;\
|
|
armNextPC = reg[15].I;\
|
|
reg[15].I += 2;\
|
|
}\
|
|
} else {\
|
|
OPCODE \
|
|
}\
|
|
}\
|
|
break;
|
|
|
|
u32 opcode = CPUReadMemoryQuick(armNextPC);
|
|
|
|
clockTicks = memoryWaitFetch32[(armNextPC >> 24) & 15];
|
|
|
|
#ifndef FINAL_VERSION
|
|
if(armNextPC == stop)
|
|
{
|
|
armNextPC++;
|
|
}
|
|
#endif
|
|
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
int cond = opcode >> 28;
|
|
// suggested optimization for frequent cases
|
|
bool cond_res;
|
|
if(cond == 0x0e)
|
|
{
|
|
cond_res = true;
|
|
}
|
|
else
|
|
{
|
|
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:
|
|
cond_res = true;
|
|
break;
|
|
case 0x0F:
|
|
default:
|
|
// ???
|
|
cond_res = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(cond_res)
|
|
{
|
|
switch(((opcode>>16)&0xFF0) | ((opcode>>4)&0x0F))
|
|
{
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_AND, OP_AND, 0x000);
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_ANDS, OP_AND, 0x010);
|
|
case 0x009:
|
|
{
|
|
// MUL Rd, Rm, Rs
|
|
int dest = (opcode >> 16) & 0x0F;
|
|
int mult = (opcode & 0x0F);
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
reg[dest].I = reg[mult].I * rs;
|
|
if(((s32)rs)<0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 2;
|
|
else if ((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 3;
|
|
else if ((rs & 0xFF000000) == 0)
|
|
clockTicks += 4;
|
|
else
|
|
clockTicks += 5;
|
|
}
|
|
break;
|
|
case 0x019:
|
|
{
|
|
// MULS Rd, Rm, Rs
|
|
int dest = (opcode >> 16) & 0x0F;
|
|
int mult = (opcode & 0x0F);
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
reg[dest].I = reg[mult].I * rs;
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;
|
|
Z_FLAG = (reg[dest].I) ? false : true;
|
|
if(((s32)rs)<0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 2;
|
|
else if ((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 3;
|
|
else if ((rs & 0xFF000000) == 0)
|
|
clockTicks += 4;
|
|
else
|
|
clockTicks += 5;
|
|
}
|
|
break;
|
|
case 0x00b:
|
|
case 0x02b:
|
|
{
|
|
// STRH Rd, [Rn], -Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x04b:
|
|
case 0x06b:
|
|
{
|
|
// STRH Rd, [Rn], #-offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x08b:
|
|
case 0x0ab:
|
|
{
|
|
// STRH Rd, [Rn], Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x0cb:
|
|
case 0x0eb:
|
|
{
|
|
// STRH Rd, [Rn], #offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x10b:
|
|
{
|
|
// STRH Rd, [Rn, -Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
}
|
|
break;
|
|
case 0x12b:
|
|
{
|
|
// STRH Rd, [Rn, -Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x14b:
|
|
{
|
|
// STRH Rd, [Rn, -#offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
}
|
|
break;
|
|
case 0x16b:
|
|
{
|
|
// STRH Rd, [Rn, -#offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x18b:
|
|
{
|
|
// STRH Rd, [Rn, Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
}
|
|
break;
|
|
case 0x1ab:
|
|
{
|
|
// STRH Rd, [Rn, Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x1cb:
|
|
{
|
|
// STRH Rd, [Rn, #offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
}
|
|
break;
|
|
case 0x1eb:
|
|
{
|
|
// STRH Rd, [Rn, #offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 4 + CPUUpdateTicksAccess16(address);
|
|
CPUWriteHalfWord(address, reg[dest].W.W0);
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x01b:
|
|
case 0x03b:
|
|
{
|
|
// LDRH Rd, [Rn], -Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
{
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x05b:
|
|
case 0x07b:
|
|
{
|
|
// LDRH Rd, [Rn], #-offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
{
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x09b:
|
|
case 0x0bb:
|
|
{
|
|
// LDRH Rd, [Rn], Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
{
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x0db:
|
|
case 0x0fb:
|
|
{
|
|
// LDRH Rd, [Rn], #offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
{
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x11b:
|
|
{
|
|
// LDRH Rd, [Rn, -Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
}
|
|
break;
|
|
case 0x13b:
|
|
{
|
|
// LDRH Rd, [Rn, -Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x15b:
|
|
{
|
|
// LDRH Rd, [Rn, -#offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
}
|
|
break;
|
|
case 0x17b:
|
|
{
|
|
// LDRH Rd, [Rn, -#offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x19b:
|
|
{
|
|
// LDRH Rd, [Rn, Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
}
|
|
break;
|
|
case 0x1bb:
|
|
{
|
|
// LDRH Rd, [Rn, Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x1db:
|
|
{
|
|
// LDRH Rd, [Rn, #offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
}
|
|
break;
|
|
case 0x1fb:
|
|
{
|
|
// LDRH Rd, [Rn, #offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = CPUReadHalfWord(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x01d:
|
|
case 0x03d:
|
|
{
|
|
// LDRSB Rd, [Rn], -Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
{
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x05d:
|
|
case 0x07d:
|
|
{
|
|
// LDRSB Rd, [Rn], #-offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
{
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x09d:
|
|
case 0x0bd:
|
|
{
|
|
// LDRSB Rd, [Rn], Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
{
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x0dd:
|
|
case 0x0fd:
|
|
{
|
|
// LDRSB Rd, [Rn], #offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
{
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x11d:
|
|
{
|
|
// LDRSB Rd, [Rn, -Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
}
|
|
break;
|
|
case 0x13d:
|
|
{
|
|
// LDRSB Rd, [Rn, -Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x15d:
|
|
{
|
|
// LDRSB Rd, [Rn, -#offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
}
|
|
break;
|
|
case 0x17d:
|
|
{
|
|
// LDRSB Rd, [Rn, -#offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x19d:
|
|
{
|
|
// LDRSB Rd, [Rn, Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
}
|
|
break;
|
|
case 0x1bd:
|
|
{
|
|
// LDRSB Rd, [Rn, Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x1dd:
|
|
{
|
|
// LDRSB Rd, [Rn, #offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
}
|
|
break;
|
|
case 0x1fd:
|
|
{
|
|
// LDRSB Rd, [Rn, #offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s8)CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x01f:
|
|
case 0x03f:
|
|
{
|
|
// LDRSH Rd, [Rn], -Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
{
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x05f:
|
|
case 0x07f:
|
|
{
|
|
// LDRSH Rd, [Rn], #-offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
{
|
|
address -= offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x09f:
|
|
case 0x0bf:
|
|
{
|
|
// LDRSH Rd, [Rn], Rm
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
{
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x0df:
|
|
case 0x0ff:
|
|
{
|
|
// LDRSH Rd, [Rn], #offset
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I;
|
|
int offset = (opcode & 0x0F) | ((opcode >> 4) & 0xF0);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
{
|
|
address += offset;
|
|
reg[base].I = address;
|
|
}
|
|
}
|
|
break;
|
|
case 0x11f:
|
|
{
|
|
// LDRSH Rd, [Rn, -Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
}
|
|
break;
|
|
case 0x13f:
|
|
{
|
|
// LDRSH Rd, [Rn, -Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x15f:
|
|
{
|
|
// LDRSH Rd, [Rn, -#offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
}
|
|
break;
|
|
case 0x17f:
|
|
{
|
|
// LDRSH Rd, [Rn, -#offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I - ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x19f:
|
|
{
|
|
// LDRSH Rd, [Rn, Rm]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
}
|
|
break;
|
|
case 0x1bf:
|
|
{
|
|
// LDRSH Rd, [Rn, Rm]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + reg[opcode & 0x0F].I;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
case 0x1df:
|
|
{
|
|
// LDRSH Rd, [Rn, #offset]
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
}
|
|
break;
|
|
case 0x1ff:
|
|
{
|
|
// LDRSH Rd, [Rn, #offset]!
|
|
int base = (opcode >> 16) & 0x0F;
|
|
int dest = (opcode >> 12) & 0x0F;
|
|
u32 address = reg[base].I + ((opcode & 0x0F)|((opcode>>4)&0xF0));
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
reg[dest].I = (s16)CPUReadHalfWordSigned(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
}
|
|
break;
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EOR, OP_EOR, 0x020);
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_EORS, OP_EOR, 0x030);
|
|
case 0x029:
|
|
{
|
|
// MLA Rd, Rm, Rs, Rn
|
|
int dest = (opcode >> 16) & 0x0F;
|
|
int mult = (opcode & 0x0F);
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
reg[dest].I = reg[mult].I * rs + reg[(opcode>>12)&0x0f].I;
|
|
if(((s32)rs)<0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 3;
|
|
else if ((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 4;
|
|
else if ((rs & 0xFF000000) == 0)
|
|
clockTicks += 5;
|
|
else
|
|
clockTicks += 6;
|
|
}
|
|
break;
|
|
case 0x039:
|
|
{
|
|
// MLAS Rd, Rm, Rs, Rn
|
|
int dest = (opcode >> 16) & 0x0F;
|
|
int mult = (opcode & 0x0F);
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
reg[dest].I = reg[mult].I * rs + reg[(opcode>>12)&0x0f].I;
|
|
N_FLAG = (reg[dest].I & 0x80000000) ? true : false;
|
|
Z_FLAG = (reg[dest].I) ? false : true;
|
|
if(((s32)rs)<0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 3;
|
|
else if ((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 4;
|
|
else if ((rs & 0xFF000000) == 0)
|
|
clockTicks += 5;
|
|
else
|
|
clockTicks += 6;
|
|
}
|
|
break;
|
|
ARITHMETIC_DATA_OPCODE(OP_SUB, OP_SUB, 0x040);
|
|
ARITHMETIC_DATA_OPCODE(OP_SUBS, OP_SUB, 0x050);
|
|
ARITHMETIC_DATA_OPCODE(OP_RSB, OP_RSB, 0x060);
|
|
ARITHMETIC_DATA_OPCODE(OP_RSBS, OP_RSB, 0x070);
|
|
ARITHMETIC_DATA_OPCODE(OP_ADD, OP_ADD, 0x080);
|
|
ARITHMETIC_DATA_OPCODE(OP_ADDS, OP_ADD, 0x090);
|
|
case 0x089:
|
|
{
|
|
// UMULL RdLo, RdHi, Rn, Rs
|
|
u32 umult = reg[(opcode & 0x0F)].I;
|
|
u32 usource = reg[(opcode >> 8) & 0x0F].I;
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u64 uTemp = ((u64)umult)*((u64)usource);
|
|
reg[destLo].I = (u32)uTemp;
|
|
reg[destHi].I = (u32)(uTemp >> 32);
|
|
if ((usource & 0xFFFFFF00) == 0)
|
|
clockTicks += 2;
|
|
else if ((usource & 0xFFFF0000) == 0)
|
|
clockTicks += 3;
|
|
else if ((usource & 0xFF000000) == 0)
|
|
clockTicks += 4;
|
|
else
|
|
clockTicks += 5;
|
|
}
|
|
break;
|
|
case 0x099:
|
|
{
|
|
// UMULLS RdLo, RdHi, Rn, Rs
|
|
u32 umult = reg[(opcode & 0x0F)].I;
|
|
u32 usource = reg[(opcode >> 8) & 0x0F].I;
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u64 uTemp = ((u64)umult)*((u64)usource);
|
|
reg[destLo].I = (u32)uTemp;
|
|
reg[destHi].I = (u32)(uTemp >> 32);
|
|
Z_FLAG = (uTemp) ? false : true;
|
|
N_FLAG = (reg[destHi].I & 0x80000000) ? true : false;
|
|
if ((usource & 0xFFFFFF00) == 0)
|
|
clockTicks += 2;
|
|
else if ((usource & 0xFFFF0000) == 0)
|
|
clockTicks += 3;
|
|
else if ((usource & 0xFF000000) == 0)
|
|
clockTicks += 4;
|
|
else
|
|
clockTicks += 5;
|
|
}
|
|
break;
|
|
ARITHMETIC_DATA_OPCODE(OP_ADC, OP_ADC, 0x0a0);
|
|
ARITHMETIC_DATA_OPCODE(OP_ADCS, OP_ADC, 0x0b0);
|
|
case 0x0a9:
|
|
{
|
|
// UMLAL RdLo, RdHi, Rn, Rs
|
|
u32 umult = reg[(opcode & 0x0F)].I;
|
|
u32 usource = reg[(opcode >> 8) & 0x0F].I;
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u64 uTemp = (u64)reg[destHi].I;
|
|
uTemp <<= 32;
|
|
uTemp |= (u64)reg[destLo].I;
|
|
uTemp += ((u64)umult)*((u64)usource);
|
|
reg[destLo].I = (u32)uTemp;
|
|
reg[destHi].I = (u32)(uTemp >> 32);
|
|
if ((usource & 0xFFFFFF00) == 0)
|
|
clockTicks += 3;
|
|
else if ((usource & 0xFFFF0000) == 0)
|
|
clockTicks += 4;
|
|
else if ((usource & 0xFF000000) == 0)
|
|
clockTicks += 5;
|
|
else
|
|
clockTicks += 6;
|
|
}
|
|
break;
|
|
case 0x0b9:
|
|
{
|
|
// UMLALS RdLo, RdHi, Rn, Rs
|
|
u32 umult = reg[(opcode & 0x0F)].I;
|
|
u32 usource = reg[(opcode >> 8) & 0x0F].I;
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u64 uTemp = (u64)reg[destHi].I;
|
|
uTemp <<= 32;
|
|
uTemp |= (u64)reg[destLo].I;
|
|
uTemp += ((u64)umult)*((u64)usource);
|
|
reg[destLo].I = (u32)uTemp;
|
|
reg[destHi].I = (u32)(uTemp >> 32);
|
|
Z_FLAG = (uTemp) ? false : true;
|
|
N_FLAG = (reg[destHi].I & 0x80000000) ? true : false;
|
|
if ((usource & 0xFFFFFF00) == 0)
|
|
clockTicks += 3;
|
|
else if ((usource & 0xFFFF0000) == 0)
|
|
clockTicks += 4;
|
|
else if ((usource & 0xFF000000) == 0)
|
|
clockTicks += 5;
|
|
else
|
|
clockTicks += 6;
|
|
}
|
|
break;
|
|
ARITHMETIC_DATA_OPCODE(OP_SBC, OP_SBC, 0x0c0);
|
|
ARITHMETIC_DATA_OPCODE(OP_SBCS, OP_SBC, 0x0d0);
|
|
case 0x0c9:
|
|
{
|
|
// SMULL RdLo, RdHi, Rm, Rs
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
s64 m = (s32)reg[(opcode & 0x0F)].I;
|
|
s64 s = (s32)rs;
|
|
s64 sTemp = m*s;
|
|
reg[destLo].I = (u32)sTemp;
|
|
reg[destHi].I = (u32)(sTemp >> 32);
|
|
if(((s32)rs) < 0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 2;
|
|
else if((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 3;
|
|
else if((rs & 0xFF000000) == 0)
|
|
clockTicks += 4;
|
|
else
|
|
clockTicks += 5;
|
|
}
|
|
break;
|
|
case 0x0d9:
|
|
{
|
|
// SMULLS RdLo, RdHi, Rm, Rs
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
s64 m = (s32)reg[(opcode & 0x0F)].I;
|
|
s64 s = (s32)rs;
|
|
s64 sTemp = m*s;
|
|
reg[destLo].I = (u32)sTemp;
|
|
reg[destHi].I = (u32)(sTemp >> 32);
|
|
Z_FLAG = (sTemp) ? false : true;
|
|
N_FLAG = (sTemp < 0) ? true : false;
|
|
if(((s32)rs) < 0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 2;
|
|
else if((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 3;
|
|
else if((rs & 0xFF000000) == 0)
|
|
clockTicks += 4;
|
|
else
|
|
clockTicks += 5;
|
|
}
|
|
break;
|
|
ARITHMETIC_DATA_OPCODE(OP_RSC, OP_RSC, 0x0e0);
|
|
ARITHMETIC_DATA_OPCODE(OP_RSCS, OP_RSC, 0x0f0);
|
|
case 0x0e9:
|
|
{
|
|
// SMLAL RdLo, RdHi, Rm, Rs
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
s64 m = (s32)reg[(opcode & 0x0F)].I;
|
|
s64 s = (s32)rs;
|
|
s64 sTemp = (u64)reg[destHi].I;
|
|
sTemp <<= 32;
|
|
sTemp |= (u64)reg[destLo].I;
|
|
sTemp += m*s;
|
|
reg[destLo].I = (u32)sTemp;
|
|
reg[destHi].I = (u32)(sTemp >> 32);
|
|
if(((s32)rs) < 0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 3;
|
|
else if((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 4;
|
|
else if((rs & 0xFF000000) == 0)
|
|
clockTicks += 5;
|
|
else
|
|
clockTicks += 6;
|
|
}
|
|
break;
|
|
case 0x0f9:
|
|
{
|
|
// SMLALS RdLo, RdHi, Rm, Rs
|
|
int destLo = (opcode >> 12) & 0x0F;
|
|
int destHi = (opcode >> 16) & 0x0F;
|
|
u32 rs = reg[(opcode >> 8) & 0x0F].I;
|
|
s64 m = (s32)reg[(opcode & 0x0F)].I;
|
|
s64 s = (s32)rs;
|
|
s64 sTemp = (u64)reg[destHi].I;
|
|
sTemp <<= 32;
|
|
sTemp |= (u64)reg[destLo].I;
|
|
sTemp += m*s;
|
|
reg[destLo].I = (u32)sTemp;
|
|
reg[destHi].I = (u32)(sTemp >> 32);
|
|
Z_FLAG = (sTemp) ? false : true;
|
|
N_FLAG = (sTemp < 0) ? true : false;
|
|
if(((s32)rs) < 0)
|
|
rs = ~rs;
|
|
if((rs & 0xFFFFFF00) == 0)
|
|
clockTicks += 3;
|
|
else if((rs & 0xFFFF0000) == 0)
|
|
clockTicks += 4;
|
|
else if((rs & 0xFF000000) == 0)
|
|
clockTicks += 5;
|
|
else
|
|
clockTicks += 6;
|
|
}
|
|
break;
|
|
LOGICAL_DATA_OPCODE(OP_TST, OP_TST, 0x110);
|
|
case 0x100:
|
|
// MRS Rd, CPSR
|
|
// TODO: check if right instruction....
|
|
CPUUpdateCPSR();
|
|
reg[(opcode >> 12) & 0x0F].I = reg[16].I;
|
|
break;
|
|
case 0x109:
|
|
{
|
|
// SWP Rd, Rm, [Rn]
|
|
u32 address = reg[(opcode >> 16) & 15].I;
|
|
u32 temp = CPUReadMemory(address);
|
|
CPUWriteMemory(address, reg[opcode&15].I);
|
|
reg[(opcode >> 12) & 15].I = temp;
|
|
}
|
|
break;
|
|
LOGICAL_DATA_OPCODE(OP_TEQ, OP_TEQ, 0x130);
|
|
case 0x120:
|
|
{
|
|
// MSR CPSR_fields, Rm
|
|
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();
|
|
}
|
|
break;
|
|
case 0x121:
|
|
{
|
|
// BX Rm
|
|
// TODO: check if right instruction...
|
|
clockTicks += 3;
|
|
int base = opcode & 0x0F;
|
|
armState = reg[base].I & 1 ? false : true;
|
|
if(armState)
|
|
{
|
|
reg[15].I = reg[base].I & 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
else
|
|
{
|
|
reg[15].I = reg[base].I & 0xFFFFFFFE;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
}
|
|
}
|
|
break;
|
|
ARITHMETIC_DATA_OPCODE(OP_CMP, OP_CMP, 0x150);
|
|
case 0x140:
|
|
// MRS Rd, SPSR
|
|
// TODO: check if right instruction...
|
|
reg[(opcode >> 12) & 0x0F].I = reg[17].I;
|
|
break;
|
|
case 0x149:
|
|
{
|
|
// SWPB Rd, Rm, [Rn]
|
|
u32 address = reg[(opcode >> 16) & 15].I;
|
|
u32 temp = CPUReadByte(address);
|
|
CPUWriteByte(address, reg[opcode&15].B.B0);
|
|
reg[(opcode>>12)&15].I = temp;
|
|
}
|
|
break;
|
|
ARITHMETIC_DATA_OPCODE(OP_CMN, OP_CMN, 0x170);
|
|
case 0x160:
|
|
{
|
|
// MSR SPSR_fields, Rm
|
|
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);
|
|
}
|
|
}
|
|
break;
|
|
LOGICAL_DATA_OPCODE (OP_ORR, OP_ORR, 0x180);
|
|
LOGICAL_DATA_OPCODE (OP_ORRS, OP_ORR, 0x190);
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOV, OP_MOV, 0x1a0);
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MOVS, OP_MOV, 0x1b0);
|
|
LOGICAL_DATA_OPCODE (OP_BIC, OP_BIC, 0x1c0);
|
|
LOGICAL_DATA_OPCODE (OP_BICS, OP_BIC, 0x1d0);
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVN, OP_MVN, 0x1e0);
|
|
LOGICAL_DATA_OPCODE_WITHOUT_base(OP_MVNS, OP_MVN, 0x1f0);
|
|
#ifdef BKPT_SUPPORT
|
|
case 0x127:
|
|
case 0x7ff: // for GDB support
|
|
extern void (*dbgSignal)(int,int);
|
|
reg[15].I -= 4;
|
|
armNextPC -= 4;
|
|
dbgSignal(5, (opcode & 0x0f)|((opcode>>4) & 0xfff0));
|
|
return;
|
|
#endif
|
|
case 0x320:
|
|
case 0x321:
|
|
case 0x322:
|
|
case 0x323:
|
|
case 0x324:
|
|
case 0x325:
|
|
case 0x326:
|
|
case 0x327:
|
|
case 0x328:
|
|
case 0x329:
|
|
case 0x32a:
|
|
case 0x32b:
|
|
case 0x32c:
|
|
case 0x32d:
|
|
case 0x32e:
|
|
case 0x32f:
|
|
{
|
|
// MSR CPSR_fields, #
|
|
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();
|
|
}
|
|
break;
|
|
case 0x360:
|
|
case 0x361:
|
|
case 0x362:
|
|
case 0x363:
|
|
case 0x364:
|
|
case 0x365:
|
|
case 0x366:
|
|
case 0x367:
|
|
case 0x368:
|
|
case 0x369:
|
|
case 0x36a:
|
|
case 0x36b:
|
|
case 0x36c:
|
|
case 0x36d:
|
|
case 0x36e:
|
|
case 0x36f:
|
|
{
|
|
// MSR SPSR_fields, #
|
|
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);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x400)
|
|
// T versions shouldn't be different on GBA
|
|
CASE_16(0x420)
|
|
{
|
|
// STR Rd, [Rn], -#
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x480)
|
|
// T versions shouldn't be different on GBA
|
|
CASE_16(0x4a0)
|
|
{
|
|
// STR Rd, [Rn], #
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x500)
|
|
{
|
|
// STR Rd, [Rn, -#]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x520)
|
|
{
|
|
// STR Rd, [Rn, -#]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x580)
|
|
{
|
|
// STR Rd, [Rn, #]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x5a0)
|
|
{
|
|
// STR Rd, [Rn, #]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x410)
|
|
{
|
|
// LDR Rd, [Rn], -#
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I -= offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x430)
|
|
{
|
|
// LDRT Rd, [Rn], -#
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I -= offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x490)
|
|
{
|
|
// LDR Rd, [Rn], #
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I += offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x4b0)
|
|
{
|
|
// LDRT Rd, [Rn], #
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I += offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
CASE_16(0x510)
|
|
{
|
|
// LDR Rd, [Rn, -#]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x530)
|
|
{
|
|
// LDR Rd, [Rn, -#]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x590)
|
|
{
|
|
// LDR Rd, [Rn, #]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x5b0)
|
|
{
|
|
// LDR Rd, [Rn, #]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x440)
|
|
// T versions shouldn't be different on GBA
|
|
CASE_16(0x460)
|
|
{
|
|
// STRB Rd, [Rn], -#
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x4c0)
|
|
// T versions shouldn't be different on GBA
|
|
CASE_16(0x4e0)
|
|
// STRB Rd, [Rn], #
|
|
{
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x540)
|
|
{
|
|
// STRB Rd, [Rn, -#]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x560)
|
|
{
|
|
// STRB Rd, [Rn, -#]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x5c0)
|
|
{
|
|
// STRB Rd, [Rn, #]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x5e0)
|
|
{
|
|
// STRB Rd, [Rn, #]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x450)
|
|
// T versions shouldn't be different
|
|
CASE_16(0x470)
|
|
{
|
|
// LDRB Rd, [Rn], -#
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I -= offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x4d0)
|
|
CASE_16(0x4f0) // T versions should not be different
|
|
{
|
|
// LDRB Rd, [Rn], #
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I += offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x550)
|
|
{
|
|
// LDRB Rd, [Rn, -#]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x570)
|
|
{
|
|
// LDRB Rd, [Rn, -#]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x5d0)
|
|
{
|
|
// LDRB Rd, [Rn, #]
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
CASE_16(0x5f0)
|
|
{
|
|
// LDRB Rd, [Rn, #]!
|
|
int offset = opcode & 0xFFF;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x600:
|
|
case 0x608:
|
|
// T versions are the same
|
|
case 0x620:
|
|
case 0x628:
|
|
{
|
|
// STR Rd, [Rn], -Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x602:
|
|
case 0x60a:
|
|
// T versions are the same
|
|
case 0x622:
|
|
case 0x62a:
|
|
{
|
|
// STR Rd, [Rn], -Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x604:
|
|
case 0x60c:
|
|
// T versions are the same
|
|
case 0x624:
|
|
case 0x62c:
|
|
{
|
|
// STR Rd, [Rn], -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x606:
|
|
case 0x60e:
|
|
// T versions are the same
|
|
case 0x626:
|
|
case 0x62e:
|
|
{
|
|
// STR Rd, [Rn], -Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address - value;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x680:
|
|
case 0x688:
|
|
// T versions are the same
|
|
case 0x6a0:
|
|
case 0x6a8:
|
|
{
|
|
// STR Rd, [Rn], Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x682:
|
|
case 0x68a:
|
|
// T versions are the same
|
|
case 0x6a2:
|
|
case 0x6aa:
|
|
{
|
|
// STR Rd, [Rn], Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x684:
|
|
case 0x68c:
|
|
// T versions are the same
|
|
case 0x6a4:
|
|
case 0x6ac:
|
|
{
|
|
// STR Rd, [Rn], Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x686:
|
|
case 0x68e:
|
|
// T versions are the same
|
|
case 0x6a6:
|
|
case 0x6ae:
|
|
{
|
|
// STR Rd, [Rn], Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
reg[base].I = address + value;
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x700:
|
|
case 0x708:
|
|
{
|
|
// STR Rd, [Rn, -Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x702:
|
|
case 0x70a:
|
|
{
|
|
// STR Rd, [Rn, -Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x704:
|
|
case 0x70c:
|
|
{
|
|
// STR Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x706:
|
|
case 0x70e:
|
|
{
|
|
// STR Rd, [Rn, -Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x720:
|
|
case 0x728:
|
|
{
|
|
// STR Rd, [Rn, -Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x722:
|
|
case 0x72a:
|
|
{
|
|
// STR Rd, [Rn, -Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x724:
|
|
case 0x72c:
|
|
{
|
|
// STR Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x726:
|
|
case 0x72e:
|
|
{
|
|
// STR Rd, [Rn, -Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x780:
|
|
case 0x788:
|
|
{
|
|
// STR Rd, [Rn, Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x782:
|
|
case 0x78a:
|
|
{
|
|
// STR Rd, [Rn, Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x784:
|
|
case 0x78c:
|
|
{
|
|
// STR Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x786:
|
|
case 0x78e:
|
|
{
|
|
// STR Rd, [Rn, Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x7a0:
|
|
case 0x7a8:
|
|
{
|
|
// STR Rd, [Rn, Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x7a2:
|
|
case 0x7aa:
|
|
{
|
|
// STR Rd, [Rn, Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x7a4:
|
|
case 0x7ac:
|
|
{
|
|
// STR Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x7a6:
|
|
case 0x7ae:
|
|
{
|
|
// STR Rd, [Rn, Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
reg[base].I = address;
|
|
CPUWriteMemory(address, reg[dest].I);
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x610:
|
|
case 0x618:
|
|
// T versions are the same
|
|
case 0x630:
|
|
case 0x638:
|
|
{
|
|
// LDR Rd, [Rn], -Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address - offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x612:
|
|
case 0x61a:
|
|
// T versions are the same
|
|
case 0x632:
|
|
case 0x63a:
|
|
{
|
|
// LDR Rd, [Rn], -Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address - offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x614:
|
|
case 0x61c:
|
|
// T versions are the same
|
|
case 0x634:
|
|
case 0x63c:
|
|
{
|
|
// LDR Rd, [Rn], -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address - offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x616:
|
|
case 0x61e:
|
|
// T versions are the same
|
|
case 0x636:
|
|
case 0x63e:
|
|
{
|
|
// LDR Rd, [Rn], -Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address - value;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x690:
|
|
case 0x698:
|
|
// T versions are the same
|
|
case 0x6b0:
|
|
case 0x6b8:
|
|
{
|
|
// LDR Rd, [Rn], Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address + offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x692:
|
|
case 0x69a:
|
|
// T versions are the same
|
|
case 0x6b2:
|
|
case 0x6ba:
|
|
{
|
|
// LDR Rd, [Rn], Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address + offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x694:
|
|
case 0x69c:
|
|
// T versions are the same
|
|
case 0x6b4:
|
|
case 0x6bc:
|
|
{
|
|
// LDR Rd, [Rn], Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address + offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x696:
|
|
case 0x69e:
|
|
// T versions are the same
|
|
case 0x6b6:
|
|
case 0x6be:
|
|
{
|
|
// LDR Rd, [Rn], Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address + value;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x710:
|
|
case 0x718:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x712:
|
|
case 0x71a:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x714:
|
|
case 0x71c:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x716:
|
|
case 0x71e:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x730:
|
|
case 0x738:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x732:
|
|
case 0x73a:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x734:
|
|
case 0x73c:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x736:
|
|
case 0x73e:
|
|
{
|
|
// LDR Rd, [Rn, -Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x790:
|
|
case 0x798:
|
|
{
|
|
// LDR Rd, [Rn, Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x792:
|
|
case 0x79a:
|
|
{
|
|
// LDR Rd, [Rn, Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x794:
|
|
case 0x79c:
|
|
{
|
|
// LDR Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x796:
|
|
case 0x79e:
|
|
{
|
|
// LDR Rd, [Rn, Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x7b0:
|
|
case 0x7b8:
|
|
{
|
|
// LDR Rd, [Rn, Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x7b2:
|
|
case 0x7ba:
|
|
{
|
|
// LDR Rd, [Rn, Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x7b4:
|
|
case 0x7bc:
|
|
{
|
|
// LDR Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x7b6:
|
|
case 0x7be:
|
|
{
|
|
// LDR Rd, [Rn, Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
reg[dest].I = CPUReadMemory(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess32(address);
|
|
if(dest == 15)
|
|
{
|
|
clockTicks += 2;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
case 0x640:
|
|
case 0x648:
|
|
// T versions are the same
|
|
case 0x660:
|
|
case 0x668:
|
|
{
|
|
// STRB Rd, [Rn], -Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x642:
|
|
case 0x64a:
|
|
// T versions are the same
|
|
case 0x662:
|
|
case 0x66a:
|
|
{
|
|
// STRB Rd, [Rn], -Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x644:
|
|
case 0x64c:
|
|
// T versions are the same
|
|
case 0x664:
|
|
case 0x66c:
|
|
{
|
|
// STRB Rd, [Rn], -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address - offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x646:
|
|
case 0x64e:
|
|
// T versions are the same
|
|
case 0x666:
|
|
case 0x66e:
|
|
{
|
|
// STRB Rd, [Rn], -Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address - value;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6c0:
|
|
case 0x6c8:
|
|
// T versions are the same
|
|
case 0x6e0:
|
|
case 0x6e8:
|
|
{
|
|
// STRB Rd, [Rn], Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6c2:
|
|
case 0x6ca:
|
|
// T versions are the same
|
|
case 0x6e2:
|
|
case 0x6ea:
|
|
{
|
|
// STRB Rd, [Rn], Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6c4:
|
|
case 0x6cc:
|
|
// T versions are the same
|
|
case 0x6e4:
|
|
case 0x6ec:
|
|
{
|
|
// STR Rd, [Rn], Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address + offset;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6c6:
|
|
case 0x6ce:
|
|
// T versions are the same
|
|
case 0x6e6:
|
|
case 0x6ee:
|
|
{
|
|
// STRB Rd, [Rn], Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
reg[base].I = address + value;
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x740:
|
|
case 0x748:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x742:
|
|
case 0x74a:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x744:
|
|
case 0x74c:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x746:
|
|
case 0x74e:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x760:
|
|
case 0x768:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x762:
|
|
case 0x76a:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x764:
|
|
case 0x76c:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x766:
|
|
case 0x76e:
|
|
{
|
|
// STRB Rd, [Rn, -Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7c0:
|
|
case 0x7c8:
|
|
{
|
|
// STRB Rd, [Rn, Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7c2:
|
|
case 0x7ca:
|
|
{
|
|
// STRB Rd, [Rn, Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7c4:
|
|
case 0x7cc:
|
|
{
|
|
// STRB Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7c6:
|
|
case 0x7ce:
|
|
{
|
|
// STRB Rd, [Rn, Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7e0:
|
|
case 0x7e8:
|
|
{
|
|
// STRB Rd, [Rn, Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7e2:
|
|
case 0x7ea:
|
|
{
|
|
// STRB Rd, [Rn, Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7e4:
|
|
case 0x7ec:
|
|
{
|
|
// STRB Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7e6:
|
|
case 0x7ee:
|
|
{
|
|
// STRB Rd, [Rn, Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
reg[base].I = address;
|
|
CPUWriteByte(address, reg[dest].B.B0);
|
|
clockTicks += 2 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x650:
|
|
case 0x658:
|
|
// T versions are the same
|
|
case 0x670:
|
|
case 0x678:
|
|
{
|
|
// LDRB Rd, [Rn], -Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address - offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x652:
|
|
case 0x65a:
|
|
// T versions are the same
|
|
case 0x672:
|
|
case 0x67a:
|
|
{
|
|
// LDRB Rd, [Rn], -Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address - offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x654:
|
|
case 0x65c:
|
|
// T versions are the same
|
|
case 0x674:
|
|
case 0x67c:
|
|
{
|
|
// LDRB Rd, [Rn], -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address - offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x656:
|
|
case 0x65e:
|
|
// T versions are the same
|
|
case 0x676:
|
|
case 0x67e:
|
|
{
|
|
// LDRB Rd, [Rn], -Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address - value;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6d0:
|
|
case 0x6d8:
|
|
// T versions are the same
|
|
case 0x6f0:
|
|
case 0x6f8:
|
|
{
|
|
// LDRB Rd, [Rn], Rm, LSL #
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address + offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6d2:
|
|
case 0x6da:
|
|
// T versions are the same
|
|
case 0x6f2:
|
|
case 0x6fa:
|
|
{
|
|
// LDRB Rd, [Rn], Rm, LSR #
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address + offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6d4:
|
|
case 0x6dc:
|
|
// T versions are the same
|
|
case 0x6f4:
|
|
case 0x6fc:
|
|
{
|
|
// LDRB Rd, [Rn], Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address + offset;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x6d6:
|
|
case 0x6de:
|
|
// T versions are the same
|
|
case 0x6f6:
|
|
case 0x6fe:
|
|
{
|
|
// LDRB Rd, [Rn], Rm, ROR #
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address + value;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x750:
|
|
case 0x758:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x752:
|
|
case 0x75a:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x754:
|
|
case 0x75c:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x756:
|
|
case 0x75e:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x770:
|
|
case 0x778:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x772:
|
|
case 0x77a:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x774:
|
|
case 0x77c:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x776:
|
|
case 0x77e:
|
|
{
|
|
// LDRB Rd, [Rn, -Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I - value;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7d0:
|
|
case 0x7d8:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, LSL #]
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7d2:
|
|
case 0x7da:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, LSR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7d4:
|
|
case 0x7dc:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7d6:
|
|
case 0x7de:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, ROR #]
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
reg[dest].I = CPUReadByte(address);
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7f0:
|
|
case 0x7f8:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, LSL #]!
|
|
int offset = reg[opcode & 15].I << ((opcode>>7)& 31);
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7f2:
|
|
case 0x7fa:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, LSR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
int offset = shift ? reg[opcode & 15].I >> shift : 0;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7f4:
|
|
case 0x7fc:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, 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;
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + offset;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x7f6:
|
|
case 0x7fe:
|
|
{
|
|
// LDRB Rd, [Rn, Rm, ROR #]!
|
|
int shift = (opcode >> 7) & 31;
|
|
u32 value = reg[opcode & 15].I;
|
|
if(shift)
|
|
{
|
|
ROR_VALUE;
|
|
}
|
|
else
|
|
{
|
|
RCR_VALUE;
|
|
}
|
|
int dest = (opcode >> 12) & 15;
|
|
int base = (opcode >> 16) & 15;
|
|
u32 address = reg[base].I + value;
|
|
reg[dest].I = CPUReadByte(address);
|
|
if(dest != base)
|
|
reg[base].I = address;
|
|
clockTicks += 3 + CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
#define STMW_REG(val,num) \
|
|
if(opcode & (val)) {\
|
|
CPUWriteMemory(address, reg[(num)].I);\
|
|
if(!offset) {\
|
|
reg[base].I = temp;\
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);\
|
|
offset = 1;\
|
|
} else {\
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\
|
|
}\
|
|
address += 4;\
|
|
}
|
|
#define STM_REG(val,num) \
|
|
if(opcode & (val)) {\
|
|
CPUWriteMemory(address, reg[(num)].I);\
|
|
if(!offset) {\
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);\
|
|
offset = 1;\
|
|
} else {\
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\
|
|
}\
|
|
address += 4;\
|
|
}
|
|
|
|
CASE_16(0x800)
|
|
// STMDA Rn, {Rlist}
|
|
{
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp + 4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x820)
|
|
{
|
|
// STMDA Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x840)
|
|
{
|
|
// STMDA Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
STM_REG(256, R8_FIQ);
|
|
STM_REG(512, R9_FIQ);
|
|
STM_REG(1024, R10_FIQ);
|
|
STM_REG(2048, R11_FIQ);
|
|
STM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STM_REG(8192, R13_USR);
|
|
STM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
}
|
|
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x860)
|
|
{
|
|
// STMDA Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
STMW_REG(256, R8_FIQ);
|
|
STMW_REG(512, R9_FIQ);
|
|
STMW_REG(1024, R10_FIQ);
|
|
STMW_REG(2048, R11_FIQ);
|
|
STMW_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STMW_REG(8192, R13_USR);
|
|
STMW_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
}
|
|
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
CASE_16(0x880)
|
|
{
|
|
// STMIA Rn, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x8a0)
|
|
{
|
|
// STMIA Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] +
|
|
cpuBitsSet[(opcode >> 8) & 255]);
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
{
|
|
reg[base].I = temp;
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x8c0)
|
|
{
|
|
// STMIA Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
if(armMode == 0x11)
|
|
{
|
|
STM_REG(256, R8_FIQ);
|
|
STM_REG(512, R9_FIQ);
|
|
STM_REG(1024, R10_FIQ);
|
|
STM_REG(2048, R11_FIQ);
|
|
STM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
}
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STM_REG(8192, R13_USR);
|
|
STM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
}
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x8e0)
|
|
{
|
|
// STMIA Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] +
|
|
cpuBitsSet[(opcode >> 8) & 255]);
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
if(armMode == 0x11)
|
|
{
|
|
STMW_REG(256, R8_FIQ);
|
|
STMW_REG(512, R9_FIQ);
|
|
STMW_REG(1024, R10_FIQ);
|
|
STMW_REG(2048, R11_FIQ);
|
|
STMW_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
}
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STMW_REG(8192, R13_USR);
|
|
STMW_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
}
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
{
|
|
reg[base].I = temp;
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
|
|
CASE_16(0x900)
|
|
{
|
|
// STMDB Rn, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x920)
|
|
{
|
|
// STMDB Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x940)
|
|
{
|
|
// STMDB Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
STM_REG(256, R8_FIQ);
|
|
STM_REG(512, R9_FIQ);
|
|
STM_REG(1024, R10_FIQ);
|
|
STM_REG(2048, R11_FIQ);
|
|
STM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STM_REG(8192, R13_USR);
|
|
STM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
}
|
|
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x960)
|
|
{
|
|
// STMDB Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
STMW_REG(256, R8_FIQ);
|
|
STMW_REG(512, R9_FIQ);
|
|
STMW_REG(1024, R10_FIQ);
|
|
STMW_REG(2048, R11_FIQ);
|
|
STMW_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STMW_REG(8192, R13_USR);
|
|
STMW_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
}
|
|
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
CASE_16(0x980)
|
|
// STMIB Rn, {Rlist}
|
|
{
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = (reg[base].I+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x9a0)
|
|
{
|
|
// STMIB Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = (reg[base].I+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] +
|
|
cpuBitsSet[(opcode >> 8) & 255]);
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
{
|
|
reg[base].I = temp;
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x9c0)
|
|
{
|
|
// STMIB Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = (reg[base].I+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
STM_REG(1, 0);
|
|
STM_REG(2, 1);
|
|
STM_REG(4, 2);
|
|
STM_REG(8, 3);
|
|
STM_REG(16, 4);
|
|
STM_REG(32, 5);
|
|
STM_REG(64, 6);
|
|
STM_REG(128, 7);
|
|
if(armMode == 0x11)
|
|
{
|
|
STM_REG(256, R8_FIQ);
|
|
STM_REG(512, R9_FIQ);
|
|
STM_REG(1024, R10_FIQ);
|
|
STM_REG(2048, R11_FIQ);
|
|
STM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(256, 8);
|
|
STM_REG(512, 9);
|
|
STM_REG(1024, 10);
|
|
STM_REG(2048, 11);
|
|
STM_REG(4096, 12);
|
|
}
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STM_REG(8192, R13_USR);
|
|
STM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STM_REG(8192, 13);
|
|
STM_REG(16384, 14);
|
|
}
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x9e0)
|
|
{
|
|
// STMIB Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = (reg[base].I+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
u32 temp = reg[base].I + 4*(cpuBitsSet[opcode & 0xFF] +
|
|
cpuBitsSet[(opcode >> 8) & 255]);
|
|
STMW_REG(1, 0);
|
|
STMW_REG(2, 1);
|
|
STMW_REG(4, 2);
|
|
STMW_REG(8, 3);
|
|
STMW_REG(16, 4);
|
|
STMW_REG(32, 5);
|
|
STMW_REG(64, 6);
|
|
STMW_REG(128, 7);
|
|
if(armMode == 0x11)
|
|
{
|
|
STMW_REG(256, R8_FIQ);
|
|
STMW_REG(512, R9_FIQ);
|
|
STMW_REG(1024, R10_FIQ);
|
|
STMW_REG(2048, R11_FIQ);
|
|
STMW_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(256, 8);
|
|
STMW_REG(512, 9);
|
|
STMW_REG(1024, 10);
|
|
STMW_REG(2048, 11);
|
|
STMW_REG(4096, 12);
|
|
}
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
STMW_REG(8192, R13_USR);
|
|
STMW_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
STMW_REG(8192, 13);
|
|
STMW_REG(16384, 14);
|
|
}
|
|
if(opcode & 32768)
|
|
{
|
|
CPUWriteMemory(address, reg[15].I+4);
|
|
if(!offset)
|
|
{
|
|
reg[base].I = temp;
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);
|
|
}
|
|
else
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);
|
|
}
|
|
}
|
|
break;
|
|
|
|
#define LDM_REG(val,num) \
|
|
if(opcode & (val)) {\
|
|
reg[(num)].I = CPUReadMemory(address);\
|
|
if(offset)\
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\
|
|
else {\
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);\
|
|
offset = 1;\
|
|
}\
|
|
address += 4;\
|
|
}
|
|
|
|
CASE_16(0x810)
|
|
{
|
|
// LDMDA Rn, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp + 4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x830)
|
|
{
|
|
// LDMDA Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp + 4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
break;
|
|
CASE_16(0x850)
|
|
{
|
|
// LDMDA Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp + 4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x870)
|
|
{
|
|
// LDMDA Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = (temp + 4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if(!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
CASE_16(0x890)
|
|
{
|
|
// LDMIA Rn, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x8b0)
|
|
{
|
|
// LDMIA Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I +
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
break;
|
|
CASE_16(0x8d0)
|
|
{
|
|
// LDMIA Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x8f0)
|
|
{
|
|
// LDMIA Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I +
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = reg[base].I & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if(!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
CASE_16(0x910)
|
|
{
|
|
// LDMDB Rn, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x930)
|
|
{
|
|
// LDMDB Rn!, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
break;
|
|
CASE_16(0x950)
|
|
{
|
|
// LDMDB Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x970)
|
|
{
|
|
// LDMDB Rn!, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 temp = reg[base].I -
|
|
4 * (cpuBitsSet[opcode & 255] + cpuBitsSet[(opcode >> 8) & 255]);
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if(!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
|
|
CASE_16(0x990)
|
|
{
|
|
// LDMIB Rn, {Rlist}
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = (reg[base].I+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x9b0)
|
|
{
|
|
// LDMIB Rn!, {Rlist}
|
|
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;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
if(opcode & 32768)
|
|
{
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
break;
|
|
CASE_16(0x9d0)
|
|
{
|
|
// LDMIB Rn, {Rlist}^
|
|
int base = (opcode & 0x000F0000) >> 16;
|
|
u32 address = (reg[base].I+4) & 0xFFFFFFFC;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if (!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
CASE_16(0x9f0)
|
|
{
|
|
// LDMIB Rn!, {Rlist}^
|
|
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;
|
|
clockTicks += 2;
|
|
int offset = 0;
|
|
if(opcode & 0x8000)
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
|
|
reg[15].I = CPUReadMemory(address);
|
|
if(!offset)
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);
|
|
else
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
|
|
CPUSwitchMode(reg[17].I & 0x1f, false);
|
|
if(armState)
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFC;
|
|
reg[15].I = armNextPC + 4;
|
|
}
|
|
else
|
|
{
|
|
armNextPC = reg[15].I & 0xFFFFFFFE;
|
|
reg[15].I = armNextPC + 2;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(1, 0);
|
|
LDM_REG(2, 1);
|
|
LDM_REG(4, 2);
|
|
LDM_REG(8, 3);
|
|
LDM_REG(16, 4);
|
|
LDM_REG(32, 5);
|
|
LDM_REG(64, 6);
|
|
LDM_REG(128, 7);
|
|
|
|
if(armMode == 0x11)
|
|
{
|
|
LDM_REG(256, R8_FIQ);
|
|
LDM_REG(512, R9_FIQ);
|
|
LDM_REG(1024, R10_FIQ);
|
|
LDM_REG(2048, R11_FIQ);
|
|
LDM_REG(4096, R12_FIQ);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(256, 8);
|
|
LDM_REG(512, 9);
|
|
LDM_REG(1024, 10);
|
|
LDM_REG(2048, 11);
|
|
LDM_REG(4096, 12);
|
|
}
|
|
|
|
if(armMode != 0x10 && armMode != 0x1f)
|
|
{
|
|
LDM_REG(8192, R13_USR);
|
|
LDM_REG(16384, R14_USR);
|
|
}
|
|
else
|
|
{
|
|
LDM_REG(8192, 13);
|
|
LDM_REG(16384, 14);
|
|
}
|
|
|
|
if(!(opcode & (1 << base)))
|
|
reg[base].I = temp;
|
|
}
|
|
}
|
|
break;
|
|
CASE_256(0xa00)
|
|
{
|
|
// B <offset>
|
|
clockTicks += 3;
|
|
int offset = opcode & 0x00FFFFFF;
|
|
if(offset & 0x00800000)
|
|
{
|
|
offset |= 0xFF000000;
|
|
}
|
|
offset <<= 2;
|
|
reg[15].I += offset;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
break;
|
|
CASE_256(0xb00)
|
|
{
|
|
// BL <offset>
|
|
clockTicks += 3;
|
|
int offset = opcode & 0x00FFFFFF;
|
|
if(offset & 0x00800000)
|
|
{
|
|
offset |= 0xFF000000;
|
|
}
|
|
offset <<= 2;
|
|
reg[14].I = reg[15].I - 4;
|
|
reg[15].I += offset;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
break;
|
|
CASE_256(0xf00)
|
|
// SWI <comment>
|
|
clockTicks += 3;
|
|
CPUSoftwareInterrupt(opcode & 0x00FFFFFF);
|
|
break;
|
|
#ifdef GP_SUPPORT
|
|
case 0xe11:
|
|
case 0xe13:
|
|
case 0xe15:
|
|
case 0xe17:
|
|
case 0xe19:
|
|
case 0xe1b:
|
|
case 0xe1d:
|
|
case 0xe1f:
|
|
// MRC
|
|
break;
|
|
case 0xe01:
|
|
case 0xe03:
|
|
case 0xe05:
|
|
case 0xe07:
|
|
case 0xe09:
|
|
case 0xe0b:
|
|
case 0xe0d:
|
|
case 0xe0f:
|
|
// MRC
|
|
break;
|
|
#endif
|
|
default:
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_UNDEFINED)
|
|
log("Undefined ARM instruction %08x at %08x\n", opcode,
|
|
armNextPC-4);
|
|
#endif
|
|
CPUUndefinedException();
|
|
break;
|
|
// END
|
|
}
|
|
}
|