mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-01 16:35:11 +01:00
2475 lines
63 KiB
C++
2475 lines
63 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 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 ADD_RD_RS_RN \
|
|
{\
|
|
u32 lhs = reg[source].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 ADD_RD_RS_O3 \
|
|
{\
|
|
u32 lhs = reg[source].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 ADD_RN_O8(d) \
|
|
{\
|
|
u32 lhs = reg[(d)].I;\
|
|
u32 rhs = (opcode & 255);\
|
|
u32 res = lhs + rhs;\
|
|
reg[(d)].I = res;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
ADDCARRY(lhs, rhs, res);\
|
|
ADDOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#define CMN_RD_RS \
|
|
{\
|
|
u32 lhs = reg[dest].I;\
|
|
u32 rhs = value;\
|
|
u32 res = lhs + rhs;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
ADDCARRY(lhs, rhs, res);\
|
|
ADDOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#define ADC_RD_RS \
|
|
{\
|
|
u32 lhs = reg[dest].I;\
|
|
u32 rhs = value;\
|
|
u32 res = lhs + rhs + (u32)C_FLAG;\
|
|
reg[dest].I = res;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
ADDCARRY(lhs, rhs, res);\
|
|
ADDOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#define SUB_RD_RS_RN \
|
|
{\
|
|
u32 lhs = reg[source].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 SUB_RD_RS_O3 \
|
|
{\
|
|
u32 lhs = reg[source].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 SUB_RN_O8(d) \
|
|
{\
|
|
u32 lhs = reg[(d)].I;\
|
|
u32 rhs = (opcode & 255);\
|
|
u32 res = lhs - rhs;\
|
|
reg[(d)].I = res;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
SUBCARRY(lhs, rhs, res);\
|
|
SUBOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#define CMP_RN_O8(d) \
|
|
{\
|
|
u32 lhs = reg[(d)].I;\
|
|
u32 rhs = (opcode & 255);\
|
|
u32 res = lhs - rhs;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
SUBCARRY(lhs, rhs, res);\
|
|
SUBOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#define SBC_RD_RS \
|
|
{\
|
|
u32 lhs = reg[dest].I;\
|
|
u32 rhs = value;\
|
|
u32 res = lhs - rhs - !((u32)C_FLAG);\
|
|
reg[dest].I = res;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
SUBCARRY(lhs, rhs, res);\
|
|
SUBOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#define LSL_RD_RM_I5 \
|
|
{\
|
|
C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\
|
|
value = reg[source].I << shift;\
|
|
}
|
|
#define LSL_RD_RS \
|
|
{\
|
|
C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\
|
|
value = reg[dest].I << value;\
|
|
}
|
|
#define LSR_RD_RM_I5 \
|
|
{\
|
|
C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\
|
|
value = reg[source].I >> shift;\
|
|
}
|
|
#define LSR_RD_RS \
|
|
{\
|
|
C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
|
|
value = reg[dest].I >> value;\
|
|
}
|
|
#define ASR_RD_RM_I5 \
|
|
{\
|
|
C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\
|
|
value = (s32)reg[source].I >> (int)shift;\
|
|
}
|
|
#define ASR_RD_RS \
|
|
{\
|
|
C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\
|
|
value = (s32)reg[dest].I >> (int)value;\
|
|
}
|
|
#define ROR_RD_RS \
|
|
{\
|
|
C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
|
|
value = ((reg[dest].I << (32 - value)) |\
|
|
(reg[dest].I >> value));\
|
|
}
|
|
#define NEG_RD_RS \
|
|
{\
|
|
u32 lhs = reg[source].I;\
|
|
u32 rhs = 0;\
|
|
u32 res = rhs - lhs;\
|
|
reg[dest].I = res;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
SUBCARRY(rhs, lhs, res);\
|
|
SUBOVERFLOW(rhs, lhs, res);\
|
|
}
|
|
#define CMP_RD_RS \
|
|
{\
|
|
u32 lhs = reg[dest].I;\
|
|
u32 rhs = value;\
|
|
u32 res = lhs - rhs;\
|
|
Z_FLAG = (res == 0) ? true : false;\
|
|
N_FLAG = NEG(res) ? true : false;\
|
|
SUBCARRY(lhs, rhs, res);\
|
|
SUBOVERFLOW(lhs, rhs, res);\
|
|
}
|
|
#else
|
|
#ifdef __GNUC__
|
|
#ifdef __POWERPC__
|
|
#define ADD_RD_RS_RN \
|
|
{ \
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("addco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[source].I), \
|
|
"r" (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 ADD_RD_RS_O3 ADD_RD_RS_RN
|
|
#define ADD_RN_O8(d) \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("addco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[(d)].I), \
|
|
"r" (opcode & 255) \
|
|
); \
|
|
reg[(d)].I = Result; \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define CMN_RD_RS \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("addco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[dest].I), \
|
|
"r" (value) \
|
|
); \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define ADC_RD_RS \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("mtspr xer, %4\n" \
|
|
"addeo. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[dest].I), \
|
|
"r" (value), \
|
|
"r" (C_FLAG << 29) \
|
|
); \
|
|
reg[dest].I = Result; \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define SUB_RD_RS_RN \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("subco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[source].I), \
|
|
"r" (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 SUB_RD_RS_O3 SUB_RD_RS_RN
|
|
#define SUB_RN_O8(d) \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("subco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[(d)].I), \
|
|
"r" (opcode & 255) \
|
|
); \
|
|
reg[(d)].I = Result; \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define CMP_RN_O8(d) \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("subco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[(d)].I), \
|
|
"r" (opcode & 255) \
|
|
); \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define SBC_RD_RS \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("mtspr xer, %4\n" \
|
|
"subfeo. %0, %3, %2\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[dest].I), \
|
|
"r" (value), \
|
|
"r" (C_FLAG << 29) \
|
|
); \
|
|
reg[dest].I = Result; \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define LSL_RD_RM_I5 \
|
|
{\
|
|
C_FLAG = (reg[source].I >> (32 - shift)) & 1 ? true : false;\
|
|
value = reg[source].I << shift;\
|
|
}
|
|
#define LSL_RD_RS \
|
|
{\
|
|
C_FLAG = (reg[dest].I >> (32 - value)) & 1 ? true : false;\
|
|
value = reg[dest].I << value;\
|
|
}
|
|
#define LSR_RD_RM_I5 \
|
|
{\
|
|
C_FLAG = (reg[source].I >> (shift - 1)) & 1 ? true : false;\
|
|
value = reg[source].I >> shift;\
|
|
}
|
|
#define LSR_RD_RS \
|
|
{\
|
|
C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
|
|
value = reg[dest].I >> value;\
|
|
}
|
|
#define ASR_RD_RM_I5 \
|
|
{\
|
|
C_FLAG = ((s32)reg[source].I >> (int)(shift - 1)) & 1 ? true : false;\
|
|
value = (s32)reg[source].I >> (int)shift;\
|
|
}
|
|
#define ASR_RD_RS \
|
|
{\
|
|
C_FLAG = ((s32)reg[dest].I >> (int)(value - 1)) & 1 ? true : false;\
|
|
value = (s32)reg[dest].I >> (int)value;\
|
|
}
|
|
#define ROR_RD_RS \
|
|
{\
|
|
C_FLAG = (reg[dest].I >> (value - 1)) & 1 ? true : false;\
|
|
value = ((reg[dest].I << (32 - value)) |\
|
|
(reg[dest].I >> value));\
|
|
}
|
|
#define NEG_RD_RS \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("subfco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[source].I), \
|
|
"r" (0) \
|
|
); \
|
|
reg[dest].I = Result; \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#define CMP_RD_RS \
|
|
{\
|
|
register int Flags; \
|
|
register int Result; \
|
|
asm volatile("subco. %0, %2, %3\n" \
|
|
"mcrxr cr1\n" \
|
|
"mfcr %1\n" \
|
|
: "=r" (Result), \
|
|
"=r" (Flags) \
|
|
: "r" (reg[dest].I), \
|
|
"r" (value) \
|
|
); \
|
|
Z_FLAG = (Flags >> 29) & 1; \
|
|
N_FLAG = (Flags >> 31) & 1; \
|
|
C_FLAG = (Flags >> 25) & 1; \
|
|
V_FLAG = (Flags >> 26) & 1; \
|
|
}
|
|
#else
|
|
#define ADD_RD_RS_RN \
|
|
asm ("add %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[source].I));
|
|
#define ADD_RD_RS_O3 \
|
|
asm ("add %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[source].I));
|
|
#define ADD_RN_O8(d) \
|
|
asm ("add %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[(d)].I)\
|
|
: "r" (opcode & 255), "b" (reg[(d)].I));
|
|
#define CMN_RD_RS \
|
|
asm ("add %0, %1;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: \
|
|
: "r" (value), "r" (reg[dest].I):"1");
|
|
#define ADC_RD_RS \
|
|
asm ("bt $0, C_FLAG;"\
|
|
"adc %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setcb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[dest].I));
|
|
#define SUB_RD_RS_RN \
|
|
asm ("sub %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[source].I));
|
|
#define SUB_RD_RS_O3 \
|
|
asm ("sub %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[source].I));
|
|
#define SUB_RN_O8(d) \
|
|
asm ("sub %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[(d)].I)\
|
|
: "r" (opcode & 255), "b" (reg[(d)].I));
|
|
#define CMP_RN_O8(d) \
|
|
asm ("sub %0, %1;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: \
|
|
: "r" (opcode & 255), "r" (reg[(d)].I) : "1");
|
|
#define SBC_RD_RS \
|
|
asm volatile ("bt $0, C_FLAG;"\
|
|
"cmc;"\
|
|
"sbb %1, %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "r" (value), "b" (reg[dest].I) : "cc", "memory");
|
|
#define LSL_RD_RM_I5 \
|
|
asm ("shl %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[source].I), "c" (shift));
|
|
#define LSL_RD_RS \
|
|
asm ("shl %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[dest].I), "c" (value));
|
|
#define LSR_RD_RM_I5 \
|
|
asm ("shr %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[source].I), "c" (shift));
|
|
#define LSR_RD_RS \
|
|
asm ("shr %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[dest].I), "c" (value));
|
|
#define ASR_RD_RM_I5 \
|
|
asm ("sar %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[source].I), "c" (shift));
|
|
#define ASR_RD_RS \
|
|
asm ("sar %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[dest].I), "c" (value));
|
|
#define ROR_RD_RS \
|
|
asm ("ror %%cl, %%eax;"\
|
|
"setcb C_FLAG;"\
|
|
: "=a" (value)\
|
|
: "a" (reg[dest].I), "c" (value));
|
|
#define NEG_RD_RS \
|
|
asm ("neg %%ebx;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: "=b" (reg[dest].I)\
|
|
: "b" (reg[source].I));
|
|
#define CMP_RD_RS \
|
|
asm ("sub %0, %1;"\
|
|
"setsb N_FLAG;"\
|
|
"setzb Z_FLAG;"\
|
|
"setncb C_FLAG;"\
|
|
"setob V_FLAG;"\
|
|
: \
|
|
: "r" (value), "r" (reg[dest].I):"1");
|
|
#endif
|
|
#else
|
|
#define ADD_RD_RS_RN \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*eax]\
|
|
__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 ADD_RD_RS_O3 \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*eax]\
|
|
__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 ADD_RN_O8(d) \
|
|
{\
|
|
__asm mov ebx, opcode\
|
|
__asm and ebx, 255\
|
|
__asm add dword ptr [OFFSET reg+4*(d)], ebx\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define CMN_RD_RS \
|
|
{\
|
|
__asm mov eax, dest\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*eax]\
|
|
__asm add ebx, value\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define ADC_RD_RS \
|
|
{\
|
|
__asm mov ebx, dest\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm bt word ptr C_FLAG, 0\
|
|
__asm adc ebx, value\
|
|
__asm mov eax, dest\
|
|
__asm mov dword ptr [OFFSET reg+4*eax], ebx\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define SUB_RD_RS_RN \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*eax]\
|
|
__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 SUB_RD_RS_O3 \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*eax]\
|
|
__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 SUB_RN_O8(d) \
|
|
{\
|
|
__asm mov ebx, opcode\
|
|
__asm and ebx, 255\
|
|
__asm sub dword ptr [OFFSET reg + 4*(d)], ebx\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setnc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define CMP_RN_O8(d) \
|
|
{\
|
|
__asm mov eax, dword ptr [OFFSET reg+4*(d)]\
|
|
__asm mov ebx, opcode\
|
|
__asm and ebx, 255\
|
|
__asm sub eax, ebx\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setnc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define SBC_RD_RS \
|
|
{\
|
|
__asm mov ebx, dest\
|
|
__asm mov ebx, dword ptr [OFFSET reg + 4*ebx]\
|
|
__asm mov eax, value\
|
|
__asm bt word ptr C_FLAG, 0\
|
|
__asm cmc\
|
|
__asm sbb ebx, eax\
|
|
__asm mov eax, dest\
|
|
__asm mov dword ptr [OFFSET reg + 4*eax], ebx\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setnc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define LSL_RD_RM_I5 \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm shl eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define LSL_RD_RS \
|
|
{\
|
|
__asm mov eax, dest\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr value\
|
|
__asm shl eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define LSR_RD_RM_I5 \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm shr eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define LSR_RD_RS \
|
|
{\
|
|
__asm mov eax, dest\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4 * eax]\
|
|
__asm mov cl, byte ptr value\
|
|
__asm shr eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define ASR_RD_RM_I5 \
|
|
{\
|
|
__asm mov eax, source\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm mov cl, byte ptr shift\
|
|
__asm sar eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define ASR_RD_RS \
|
|
{\
|
|
__asm mov eax, dest\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm mov cl, byte ptr value\
|
|
__asm sar eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define ROR_RD_RS \
|
|
{\
|
|
__asm mov eax, dest\
|
|
__asm mov eax, dword ptr [OFFSET reg + 4*eax]\
|
|
__asm mov cl, byte ptr value\
|
|
__asm ror eax, cl\
|
|
__asm mov value, eax\
|
|
__asm setc byte ptr C_FLAG\
|
|
}
|
|
#define NEG_RD_RS \
|
|
{\
|
|
__asm mov ebx, source\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*ebx]\
|
|
__asm neg ebx\
|
|
__asm mov eax, dest\
|
|
__asm mov dword ptr [OFFSET reg+4*eax],ebx\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setnc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#define CMP_RD_RS \
|
|
{\
|
|
__asm mov eax, dest\
|
|
__asm mov ebx, dword ptr [OFFSET reg+4*eax]\
|
|
__asm sub ebx, value\
|
|
__asm sets byte ptr N_FLAG\
|
|
__asm setz byte ptr Z_FLAG\
|
|
__asm setnc byte ptr C_FLAG\
|
|
__asm seto byte ptr V_FLAG\
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
u32 opcode = CPUReadHalfWordQuick(armNextPC);
|
|
clockTicks = thumbCycles[opcode >> 8] + memoryWaitFetch[(armNextPC >> 24) & 15];
|
|
#ifndef FINAL_VERSION
|
|
if(armNextPC == stop) {
|
|
armNextPC = armNextPC++;
|
|
}
|
|
#endif
|
|
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
|
|
switch(opcode >> 8) {
|
|
case 0x00:
|
|
case 0x01:
|
|
case 0x02:
|
|
case 0x03:
|
|
case 0x04:
|
|
case 0x05:
|
|
case 0x06:
|
|
case 0x07:
|
|
{
|
|
// LSL Rd, Rm, #Imm 5
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
int shift = (opcode >> 6) & 0x1f;
|
|
u32 value;
|
|
|
|
if(shift) {
|
|
LSL_RD_RM_I5;
|
|
} else {
|
|
value = reg[source].I;
|
|
}
|
|
reg[dest].I = value;
|
|
// C_FLAG set above
|
|
N_FLAG = (value & 0x80000000 ? true : false);
|
|
Z_FLAG = (value ? false : true);
|
|
}
|
|
break;
|
|
case 0x08:
|
|
case 0x09:
|
|
case 0x0a:
|
|
case 0x0b:
|
|
case 0x0c:
|
|
case 0x0d:
|
|
case 0x0e:
|
|
case 0x0f:
|
|
{
|
|
// LSR Rd, Rm, #Imm 5
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
int shift = (opcode >> 6) & 0x1f;
|
|
u32 value;
|
|
|
|
if(shift) {
|
|
LSR_RD_RM_I5;
|
|
} else {
|
|
C_FLAG = reg[source].I & 0x80000000 ? true : false;
|
|
value = 0;
|
|
}
|
|
reg[dest].I = value;
|
|
// C_FLAG set above
|
|
N_FLAG = (value & 0x80000000 ? true : false);
|
|
Z_FLAG = (value ? false : true);
|
|
}
|
|
break;
|
|
case 0x10:
|
|
case 0x11:
|
|
case 0x12:
|
|
case 0x13:
|
|
case 0x14:
|
|
case 0x15:
|
|
case 0x16:
|
|
case 0x17:
|
|
{
|
|
// ASR Rd, Rm, #Imm 5
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
int shift = (opcode >> 6) & 0x1f;
|
|
u32 value;
|
|
|
|
if(shift) {
|
|
ASR_RD_RM_I5;
|
|
} else {
|
|
if(reg[source].I & 0x80000000) {
|
|
value = 0xFFFFFFFF;
|
|
C_FLAG = true;
|
|
} else {
|
|
value = 0;
|
|
C_FLAG = false;
|
|
}
|
|
}
|
|
reg[dest].I = value;
|
|
// C_FLAG set above
|
|
N_FLAG = (value & 0x80000000 ? true : false);
|
|
Z_FLAG = (value ? false :true);
|
|
}
|
|
break;
|
|
case 0x18:
|
|
case 0x19:
|
|
{
|
|
// ADD Rd, Rs, Rn
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
u32 value = reg[(opcode>>6)& 0x07].I;
|
|
ADD_RD_RS_RN;
|
|
}
|
|
break;
|
|
case 0x1a:
|
|
case 0x1b:
|
|
{
|
|
// SUB Rd, Rs, Rn
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
u32 value = reg[(opcode>>6)& 0x07].I;
|
|
SUB_RD_RS_RN;
|
|
}
|
|
break;
|
|
case 0x1c:
|
|
case 0x1d:
|
|
{
|
|
// ADD Rd, Rs, #Offset3
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
u32 value = (opcode >> 6) & 7;
|
|
ADD_RD_RS_O3;
|
|
}
|
|
break;
|
|
case 0x1e:
|
|
case 0x1f:
|
|
{
|
|
// SUB Rd, Rs, #Offset3
|
|
int dest = opcode & 0x07;
|
|
int source = (opcode >> 3) & 0x07;
|
|
u32 value = (opcode >> 6) & 7;
|
|
SUB_RD_RS_O3;
|
|
}
|
|
break;
|
|
case 0x20:
|
|
// MOV R0, #Offset8
|
|
reg[0].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[0].I ? false : true);
|
|
break;
|
|
case 0x21:
|
|
// MOV R1, #Offset8
|
|
reg[1].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[1].I ? false : true);
|
|
break;
|
|
case 0x22:
|
|
// MOV R2, #Offset8
|
|
reg[2].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[2].I ? false : true);
|
|
break;
|
|
case 0x23:
|
|
// MOV R3, #Offset8
|
|
reg[3].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[3].I ? false : true);
|
|
break;
|
|
case 0x24:
|
|
// MOV R4, #Offset8
|
|
reg[4].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[4].I ? false : true);
|
|
break;
|
|
case 0x25:
|
|
// MOV R5, #Offset8
|
|
reg[5].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[5].I ? false : true);
|
|
break;
|
|
case 0x26:
|
|
// MOV R6, #Offset8
|
|
reg[6].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[6].I ? false : true);
|
|
break;
|
|
case 0x27:
|
|
// MOV R7, #Offset8
|
|
reg[7].I = opcode & 255;
|
|
N_FLAG = false;
|
|
Z_FLAG = (reg[7].I ? false : true);
|
|
break;
|
|
case 0x28:
|
|
// CMP R0, #Offset8
|
|
CMP_RN_O8(0);
|
|
break;
|
|
case 0x29:
|
|
// CMP R1, #Offset8
|
|
CMP_RN_O8(1);
|
|
break;
|
|
case 0x2a:
|
|
// CMP R2, #Offset8
|
|
CMP_RN_O8(2);
|
|
break;
|
|
case 0x2b:
|
|
// CMP R3, #Offset8
|
|
CMP_RN_O8(3);
|
|
break;
|
|
case 0x2c:
|
|
// CMP R4, #Offset8
|
|
CMP_RN_O8(4);
|
|
break;
|
|
case 0x2d:
|
|
// CMP R5, #Offset8
|
|
CMP_RN_O8(5);
|
|
break;
|
|
case 0x2e:
|
|
// CMP R6, #Offset8
|
|
CMP_RN_O8(6);
|
|
break;
|
|
case 0x2f:
|
|
// CMP R7, #Offset8
|
|
CMP_RN_O8(7);
|
|
break;
|
|
case 0x30:
|
|
// ADD R0,#Offset8
|
|
ADD_RN_O8(0);
|
|
break;
|
|
case 0x31:
|
|
// ADD R1,#Offset8
|
|
ADD_RN_O8(1);
|
|
break;
|
|
case 0x32:
|
|
// ADD R2,#Offset8
|
|
ADD_RN_O8(2);
|
|
break;
|
|
case 0x33:
|
|
// ADD R3,#Offset8
|
|
ADD_RN_O8(3);
|
|
break;
|
|
case 0x34:
|
|
// ADD R4,#Offset8
|
|
ADD_RN_O8(4);
|
|
break;
|
|
case 0x35:
|
|
// ADD R5,#Offset8
|
|
ADD_RN_O8(5);
|
|
break;
|
|
case 0x36:
|
|
// ADD R6,#Offset8
|
|
ADD_RN_O8(6);
|
|
break;
|
|
case 0x37:
|
|
// ADD R7,#Offset8
|
|
ADD_RN_O8(7);
|
|
break;
|
|
case 0x38:
|
|
// SUB R0,#Offset8
|
|
SUB_RN_O8(0);
|
|
break;
|
|
case 0x39:
|
|
// SUB R1,#Offset8
|
|
SUB_RN_O8(1);
|
|
break;
|
|
case 0x3a:
|
|
// SUB R2,#Offset8
|
|
SUB_RN_O8(2);
|
|
break;
|
|
case 0x3b:
|
|
// SUB R3,#Offset8
|
|
SUB_RN_O8(3);
|
|
break;
|
|
case 0x3c:
|
|
// SUB R4,#Offset8
|
|
SUB_RN_O8(4);
|
|
break;
|
|
case 0x3d:
|
|
// SUB R5,#Offset8
|
|
SUB_RN_O8(5);
|
|
break;
|
|
case 0x3e:
|
|
// SUB R6,#Offset8
|
|
SUB_RN_O8(6);
|
|
break;
|
|
case 0x3f:
|
|
// SUB R7,#Offset8
|
|
SUB_RN_O8(7);
|
|
break;
|
|
case 0x40:
|
|
switch((opcode >> 6) & 3) {
|
|
case 0x00:
|
|
{
|
|
// AND Rd, Rs
|
|
int dest = opcode & 7;
|
|
reg[dest].I &= reg[(opcode >> 3)&7].I;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
#ifdef BKPT_SUPPORT
|
|
#define THUMB_CONSOLE_OUTPUT(a,b) \
|
|
if((opcode == 0x4000) && (reg[0].I == 0xC0DED00D)) {\
|
|
extern void (*dbgOutput)(char *, u32);\
|
|
dbgOutput((a), (b));\
|
|
}
|
|
#else
|
|
#define THUMB_CONSOLE_OUTPUT(a,b)
|
|
#endif
|
|
THUMB_CONSOLE_OUTPUT(NULL, reg[2].I);
|
|
}
|
|
break;
|
|
case 0x01:
|
|
// EOR Rd, Rs
|
|
{
|
|
int dest = opcode & 7;
|
|
reg[dest].I ^= reg[(opcode >> 3)&7].I;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
}
|
|
break;
|
|
case 0x02:
|
|
// LSL Rd, Rs
|
|
{
|
|
int dest = opcode & 7;
|
|
u32 value = reg[(opcode >> 3)&7].B.B0;
|
|
if(value) {
|
|
if(value == 32) {
|
|
value = 0;
|
|
C_FLAG = (reg[dest].I & 1 ? true : false);
|
|
} else if(value < 32) {
|
|
LSL_RD_RS;
|
|
} else {
|
|
value = 0;
|
|
C_FLAG = false;
|
|
}
|
|
reg[dest].I = value;
|
|
}
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
case 0x03:
|
|
{
|
|
// LSR Rd, Rs
|
|
int dest = opcode & 7;
|
|
u32 value = reg[(opcode >> 3)&7].B.B0;
|
|
if(value) {
|
|
if(value == 32) {
|
|
value = 0;
|
|
C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
|
|
} else if(value < 32) {
|
|
LSR_RD_RS;
|
|
} else {
|
|
value = 0;
|
|
C_FLAG = false;
|
|
}
|
|
reg[dest].I = value;
|
|
}
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 0x41:
|
|
switch((opcode >> 6) & 3) {
|
|
case 0x00:
|
|
{
|
|
// ASR Rd, Rs
|
|
int dest = opcode & 7;
|
|
u32 value = reg[(opcode >> 3)&7].B.B0;
|
|
// ASR
|
|
if(value) {
|
|
if(value < 32) {
|
|
ASR_RD_RS;
|
|
reg[dest].I = value;
|
|
} else {
|
|
if(reg[dest].I & 0x80000000){
|
|
reg[dest].I = 0xFFFFFFFF;
|
|
C_FLAG = true;
|
|
} else {
|
|
reg[dest].I = 0x00000000;
|
|
C_FLAG = false;
|
|
}
|
|
}
|
|
}
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
case 0x01:
|
|
{
|
|
// ADC Rd, Rs
|
|
int dest = opcode & 0x07;
|
|
u32 value = reg[(opcode >> 3)&7].I;
|
|
// ADC
|
|
ADC_RD_RS;
|
|
}
|
|
break;
|
|
case 0x02:
|
|
{
|
|
// SBC Rd, Rs
|
|
int dest = opcode & 0x07;
|
|
u32 value = reg[(opcode >> 3)&7].I;
|
|
|
|
// SBC
|
|
SBC_RD_RS;
|
|
}
|
|
break;
|
|
case 0x03:
|
|
// ROR Rd, Rs
|
|
{
|
|
int dest = opcode & 7;
|
|
u32 value = reg[(opcode >> 3)&7].B.B0;
|
|
|
|
if(value) {
|
|
value = value & 0x1f;
|
|
if(value == 0) {
|
|
C_FLAG = (reg[dest].I & 0x80000000 ? true : false);
|
|
} else {
|
|
ROR_RD_RS;
|
|
reg[dest].I = value;
|
|
}
|
|
}
|
|
clockTicks++;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 0x42:
|
|
switch((opcode >> 6) & 3) {
|
|
case 0x00:
|
|
{
|
|
// TST Rd, Rs
|
|
u32 value = reg[opcode & 7].I & reg[(opcode >> 3) & 7].I;
|
|
N_FLAG = value & 0x80000000 ? true : false;
|
|
Z_FLAG = value ? false : true;
|
|
}
|
|
break;
|
|
case 0x01:
|
|
{
|
|
// NEG Rd, Rs
|
|
int dest = opcode & 7;
|
|
int source = (opcode >> 3) & 7;
|
|
NEG_RD_RS;
|
|
}
|
|
break;
|
|
case 0x02:
|
|
{
|
|
// CMP Rd, Rs
|
|
int dest = opcode & 7;
|
|
u32 value = reg[(opcode >> 3)&7].I;
|
|
CMP_RD_RS;
|
|
}
|
|
break;
|
|
case 0x03:
|
|
{
|
|
// CMN Rd, Rs
|
|
int dest = opcode & 7;
|
|
u32 value = reg[(opcode >> 3)&7].I;
|
|
// CMN
|
|
CMN_RD_RS;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 0x43:
|
|
switch((opcode >> 6) & 3) {
|
|
case 0x00:
|
|
{
|
|
// ORR Rd, Rs
|
|
int dest = opcode & 7;
|
|
reg[dest].I |= reg[(opcode >> 3) & 7].I;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
}
|
|
break;
|
|
case 0x01:
|
|
{
|
|
// MUL Rd, Rs
|
|
int dest = opcode & 7;
|
|
u32 rm = reg[(opcode >> 3) & 7].I;
|
|
reg[dest].I = reg[dest].I * rm;
|
|
if (((s32)rm) < 0)
|
|
rm = ~rm;
|
|
if ((rm & 0xFFFFFF00) == 0)
|
|
clockTicks += 1;
|
|
else if ((rm & 0xFFFF0000) == 0)
|
|
clockTicks += 2;
|
|
else if ((rm & 0xFF000000) == 0)
|
|
clockTicks += 3;
|
|
else
|
|
clockTicks += 4;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
}
|
|
break;
|
|
case 0x02:
|
|
{
|
|
// BIC Rd, Rs
|
|
int dest = opcode & 7;
|
|
reg[dest].I &= (~reg[(opcode >> 3) & 7].I);
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
}
|
|
break;
|
|
case 0x03:
|
|
{
|
|
// MVN Rd, Rs
|
|
int dest = opcode & 7;
|
|
reg[dest].I = ~reg[(opcode >> 3) & 7].I;
|
|
Z_FLAG = reg[dest].I ? false : true;
|
|
N_FLAG = reg[dest].I & 0x80000000 ? true : false;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
case 0x44:
|
|
{
|
|
int dest = opcode & 7;
|
|
int base = (opcode >> 3) & 7;
|
|
switch((opcode >> 6)& 3) {
|
|
default:
|
|
goto unknown_thumb;
|
|
case 1:
|
|
// ADD Rd, Hs
|
|
reg[dest].I += reg[base+8].I;
|
|
break;
|
|
case 2:
|
|
// ADD Hd, Rs
|
|
reg[dest+8].I += reg[base].I;
|
|
if(dest == 7) {
|
|
reg[15].I &= 0xFFFFFFFE;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
case 3:
|
|
// ADD Hd, Hs
|
|
reg[dest+8].I += reg[base+8].I;
|
|
if(dest == 7) {
|
|
reg[15].I &= 0xFFFFFFFE;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 0x45:
|
|
{
|
|
int dest = opcode & 7;
|
|
int base = (opcode >> 3) & 7;
|
|
u32 value;
|
|
switch((opcode >> 6) & 3) {
|
|
case 0:
|
|
// CMP Rd, Hs
|
|
value = reg[base].I;
|
|
CMP_RD_RS;
|
|
break;
|
|
case 1:
|
|
// CMP Rd, Hs
|
|
value = reg[base+8].I;
|
|
CMP_RD_RS;
|
|
break;
|
|
case 2:
|
|
// CMP Hd, Rs
|
|
value = reg[base].I;
|
|
dest += 8;
|
|
CMP_RD_RS;
|
|
break;
|
|
case 3:
|
|
// CMP Hd, Hs
|
|
value = reg[base+8].I;
|
|
dest += 8;
|
|
CMP_RD_RS;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 0x46:
|
|
{
|
|
int dest = opcode & 7;
|
|
int base = (opcode >> 3) & 7;
|
|
switch((opcode >> 6) & 3) {
|
|
case 0:
|
|
// this form should not be used...
|
|
// MOV Rd, Rs
|
|
reg[dest].I = reg[base].I;
|
|
break;
|
|
case 1:
|
|
// MOV Rd, Hs
|
|
reg[dest].I = reg[base+8].I;
|
|
break;
|
|
case 2:
|
|
// MOV Hd, Rs
|
|
reg[dest+8].I = reg[base].I;
|
|
if(dest == 7) {
|
|
reg[15].I &= 0xFFFFFFFE;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
case 3:
|
|
// MOV Hd, Hs
|
|
reg[dest+8].I = reg[base+8].I;
|
|
if(dest == 7) {
|
|
reg[15].I &= 0xFFFFFFFE;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
case 0x47:
|
|
{
|
|
int base = (opcode >> 3) & 7;
|
|
switch((opcode >>6) & 3) {
|
|
case 0:
|
|
// BX Rs
|
|
reg[15].I = (reg[base].I) & 0xFFFFFFFE;
|
|
if(reg[base].I & 1) {
|
|
armState = false;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
} else {
|
|
armState = true;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
break;
|
|
case 1:
|
|
// BX Hs
|
|
reg[15].I = (reg[8+base].I) & 0xFFFFFFFE;
|
|
if(reg[8+base].I & 1) {
|
|
armState = false;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
} else {
|
|
armState = true;
|
|
reg[15].I &= 0xFFFFFFFC;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 4;
|
|
}
|
|
break;
|
|
default:
|
|
goto unknown_thumb;
|
|
}
|
|
}
|
|
break;
|
|
case 0x48:
|
|
// LDR R0,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[0].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x49:
|
|
// LDR R1,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[1].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x4a:
|
|
// LDR R2,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[2].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x4b:
|
|
// LDR R3,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[3].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x4c:
|
|
// LDR R4,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[4].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x4d:
|
|
// LDR R5,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[5].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x4e:
|
|
// LDR R6,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[6].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x4f:
|
|
// LDR R7,[PC, #Imm]
|
|
{
|
|
u32 address = (reg[15].I & 0xFFFFFFFC) + ((opcode & 0xFF) << 2);
|
|
reg[7].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x50:
|
|
case 0x51:
|
|
// STR Rd, [Rs, Rn]
|
|
{
|
|
u32
|
|
address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
CPUWriteMemory(address,
|
|
reg[opcode & 7].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x52:
|
|
case 0x53:
|
|
// STRH Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
CPUWriteHalfWord(address,
|
|
reg[opcode&7].W.W0);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x54:
|
|
case 0x55:
|
|
// STRB Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode >>6)&7].I;
|
|
CPUWriteByte(address,
|
|
reg[opcode & 7].B.B0);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x56:
|
|
case 0x57:
|
|
// LDSB Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
reg[opcode&7].I = (s8)CPUReadByte(address);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x58:
|
|
case 0x59:
|
|
// LDR Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
reg[opcode&7].I = CPUReadMemory(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x5a:
|
|
case 0x5b:
|
|
// LDRH Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
reg[opcode&7].I = CPUReadHalfWord(address);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x5c:
|
|
case 0x5d:
|
|
// LDRB Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
reg[opcode&7].I = CPUReadByte(address);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x5e:
|
|
case 0x5f:
|
|
// LDSH Rd, [Rs, Rn]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + reg[(opcode>>6)&7].I;
|
|
reg[opcode&7].I = (s16)CPUReadHalfWordSigned(address);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x60:
|
|
case 0x61:
|
|
case 0x62:
|
|
case 0x63:
|
|
case 0x64:
|
|
case 0x65:
|
|
case 0x66:
|
|
case 0x67:
|
|
// STR Rd, [Rs, #Imm]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2);
|
|
CPUWriteMemory(address,
|
|
reg[opcode&7].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x68:
|
|
case 0x69:
|
|
case 0x6a:
|
|
case 0x6b:
|
|
case 0x6c:
|
|
case 0x6d:
|
|
case 0x6e:
|
|
case 0x6f:
|
|
// LDR Rd, [Rs, #Imm]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<2);
|
|
reg[opcode&7].I = CPUReadMemory(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x70:
|
|
case 0x71:
|
|
case 0x72:
|
|
case 0x73:
|
|
case 0x74:
|
|
case 0x75:
|
|
case 0x76:
|
|
case 0x77:
|
|
// STRB Rd, [Rs, #Imm]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31));
|
|
CPUWriteByte(address,
|
|
reg[opcode&7].B.B0);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x78:
|
|
case 0x79:
|
|
case 0x7a:
|
|
case 0x7b:
|
|
case 0x7c:
|
|
case 0x7d:
|
|
case 0x7e:
|
|
case 0x7f:
|
|
// LDRB Rd, [Rs, #Imm]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31));
|
|
reg[opcode&7].I = CPUReadByte(address);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x80:
|
|
case 0x81:
|
|
case 0x82:
|
|
case 0x83:
|
|
case 0x84:
|
|
case 0x85:
|
|
case 0x86:
|
|
case 0x87:
|
|
// STRH Rd, [Rs, #Imm]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1);
|
|
CPUWriteHalfWord(address,
|
|
reg[opcode&7].W.W0);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x88:
|
|
case 0x89:
|
|
case 0x8a:
|
|
case 0x8b:
|
|
case 0x8c:
|
|
case 0x8d:
|
|
case 0x8e:
|
|
case 0x8f:
|
|
// LDRH Rd, [Rs, #Imm]
|
|
{
|
|
u32 address = reg[(opcode>>3)&7].I + (((opcode>>6)&31)<<1);
|
|
reg[opcode&7].I = CPUReadHalfWord(address);
|
|
clockTicks += CPUUpdateTicksAccess16(address);
|
|
}
|
|
break;
|
|
case 0x90:
|
|
// STR R0, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[0].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x91:
|
|
// STR R1, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[1].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x92:
|
|
// STR R2, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[2].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x93:
|
|
// STR R3, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[3].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x94:
|
|
// STR R4, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[4].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x95:
|
|
// STR R5, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[5].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x96:
|
|
// STR R6, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[6].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x97:
|
|
// STR R7, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
CPUWriteMemory(address, reg[7].I);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x98:
|
|
// LDR R0, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[0].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x99:
|
|
// LDR R1, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[1].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x9a:
|
|
// LDR R2, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[2].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x9b:
|
|
// LDR R3, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[3].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x9c:
|
|
// LDR R4, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[4].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x9d:
|
|
// LDR R5, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[5].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x9e:
|
|
// LDR R6, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[6].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0x9f:
|
|
// LDR R7, [SP, #Imm]
|
|
{
|
|
u32 address = reg[13].I + ((opcode&255)<<2);
|
|
reg[7].I = CPUReadMemoryQuick(address);
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
}
|
|
break;
|
|
case 0xa0:
|
|
// ADD R0, PC, Imm
|
|
reg[0].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa1:
|
|
// ADD R1, PC, Imm
|
|
reg[1].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa2:
|
|
// ADD R2, PC, Imm
|
|
reg[2].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa3:
|
|
// ADD R3, PC, Imm
|
|
reg[3].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa4:
|
|
// ADD R4, PC, Imm
|
|
reg[4].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa5:
|
|
// ADD R5, PC, Imm
|
|
reg[5].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa6:
|
|
// ADD R6, PC, Imm
|
|
reg[6].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa7:
|
|
// ADD R7, PC, Imm
|
|
reg[7].I = (reg[15].I & 0xFFFFFFFC) + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa8:
|
|
// ADD R0, SP, Imm
|
|
reg[0].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xa9:
|
|
// ADD R1, SP, Imm
|
|
reg[1].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xaa:
|
|
// ADD R2, SP, Imm
|
|
reg[2].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xab:
|
|
// ADD R3, SP, Imm
|
|
reg[3].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xac:
|
|
// ADD R4, SP, Imm
|
|
reg[4].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xad:
|
|
// ADD R5, SP, Imm
|
|
reg[5].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xae:
|
|
// ADD R6, SP, Imm
|
|
reg[6].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xaf:
|
|
// ADD R7, SP, Imm
|
|
reg[7].I = reg[13].I + ((opcode&255)<<2);
|
|
break;
|
|
case 0xb0:
|
|
{
|
|
// ADD SP, Imm
|
|
int offset = (opcode & 127) << 2;
|
|
if(opcode & 0x80)
|
|
offset = -offset;
|
|
reg[13].I += offset;
|
|
}
|
|
break;
|
|
#define PUSH_REG(val, r) \
|
|
if(opcode & (val)) {\
|
|
CPUWriteMemory(address, reg[(r)].I);\
|
|
if(offset)\
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\
|
|
else\
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);\
|
|
offset = 1;\
|
|
address += 4;\
|
|
}
|
|
case 0xb4:
|
|
// PUSH {Rlist}
|
|
{
|
|
int offset = 0;
|
|
u32 temp = reg[13].I - 4 * cpuBitsSet[opcode & 0xff];
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
PUSH_REG(1, 0);
|
|
PUSH_REG(2, 1);
|
|
PUSH_REG(4, 2);
|
|
PUSH_REG(8, 3);
|
|
PUSH_REG(16, 4);
|
|
PUSH_REG(32, 5);
|
|
PUSH_REG(64, 6);
|
|
PUSH_REG(128, 7);
|
|
reg[13].I = temp;
|
|
}
|
|
break;
|
|
case 0xb5:
|
|
// PUSH {Rlist, LR}
|
|
{
|
|
int offset = 0;
|
|
u32 temp = reg[13].I - 4 - 4 * cpuBitsSet[opcode & 0xff];
|
|
u32 address = temp & 0xFFFFFFFC;
|
|
PUSH_REG(1, 0);
|
|
PUSH_REG(2, 1);
|
|
PUSH_REG(4, 2);
|
|
PUSH_REG(8, 3);
|
|
PUSH_REG(16, 4);
|
|
PUSH_REG(32, 5);
|
|
PUSH_REG(64, 6);
|
|
PUSH_REG(128, 7);
|
|
PUSH_REG(256, 14);
|
|
reg[13].I = temp;
|
|
}
|
|
break;
|
|
#define POP_REG(val, r) \
|
|
if(opcode & (val)) {\
|
|
reg[(r)].I = CPUReadMemory(address);\
|
|
if(offset)\
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);\
|
|
else\
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);\
|
|
offset = 1;\
|
|
address += 4;\
|
|
}
|
|
case 0xbc:
|
|
// POP {Rlist}
|
|
{
|
|
int offset = 0;
|
|
u32 address = reg[13].I & 0xFFFFFFFC;
|
|
u32 temp = reg[13].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
POP_REG(1, 0);
|
|
POP_REG(2, 1);
|
|
POP_REG(4, 2);
|
|
POP_REG(8, 3);
|
|
POP_REG(16, 4);
|
|
POP_REG(32, 5);
|
|
POP_REG(64, 6);
|
|
POP_REG(128, 7);
|
|
reg[13].I = temp;
|
|
}
|
|
break;
|
|
case 0xbd:
|
|
// POP {Rlist, PC}
|
|
{
|
|
int offset = 0;
|
|
u32 address = reg[13].I & 0xFFFFFFFC;
|
|
u32 temp = reg[13].I + 4 + 4*cpuBitsSet[opcode & 0xFF];
|
|
POP_REG(1, 0);
|
|
POP_REG(2, 1);
|
|
POP_REG(4, 2);
|
|
POP_REG(8, 3);
|
|
POP_REG(16, 4);
|
|
POP_REG(32, 5);
|
|
POP_REG(64, 6);
|
|
POP_REG(128, 7);
|
|
reg[15].I = (CPUReadMemory(address) & 0xFFFFFFFE);
|
|
if(offset)
|
|
clockTicks += CPUUpdateTicksAccessSeq32(address);
|
|
else
|
|
clockTicks += CPUUpdateTicksAccess32(address);
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
reg[13].I = temp;
|
|
}
|
|
break;
|
|
#define THUMB_STM_REG(val,r,b) \
|
|
if(opcode & (val)) {\
|
|
CPUWriteMemory(address, reg[(r)].I);\
|
|
if(!offset) {\
|
|
reg[(b)].I = temp;\
|
|
clockTicks += 1 + CPUUpdateTicksAccess32(address);\
|
|
} else \
|
|
clockTicks += 1 + CPUUpdateTicksAccessSeq32(address);\
|
|
offset = 1;\
|
|
address += 4;\
|
|
}
|
|
case 0xc0:
|
|
{
|
|
// STM R0!, {Rlist}
|
|
u32 address = reg[0].I & 0xFFFFFFFC;
|
|
u32 temp = reg[0].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 0);
|
|
THUMB_STM_REG(2, 1, 0);
|
|
THUMB_STM_REG(4, 2, 0);
|
|
THUMB_STM_REG(8, 3, 0);
|
|
THUMB_STM_REG(16, 4, 0);
|
|
THUMB_STM_REG(32, 5, 0);
|
|
THUMB_STM_REG(64, 6, 0);
|
|
THUMB_STM_REG(128, 7, 0);
|
|
}
|
|
break;
|
|
case 0xc1:
|
|
{
|
|
// STM R1!, {Rlist}
|
|
u32 address = reg[1].I & 0xFFFFFFFC;
|
|
u32 temp = reg[1].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 1);
|
|
THUMB_STM_REG(2, 1, 1);
|
|
THUMB_STM_REG(4, 2, 1);
|
|
THUMB_STM_REG(8, 3, 1);
|
|
THUMB_STM_REG(16, 4, 1);
|
|
THUMB_STM_REG(32, 5, 1);
|
|
THUMB_STM_REG(64, 6, 1);
|
|
THUMB_STM_REG(128, 7, 1);
|
|
}
|
|
break;
|
|
case 0xc2:
|
|
{
|
|
// STM R2!, {Rlist}
|
|
u32 address = reg[2].I & 0xFFFFFFFC;
|
|
u32 temp = reg[2].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 2);
|
|
THUMB_STM_REG(2, 1, 2);
|
|
THUMB_STM_REG(4, 2, 2);
|
|
THUMB_STM_REG(8, 3, 2);
|
|
THUMB_STM_REG(16, 4, 2);
|
|
THUMB_STM_REG(32, 5, 2);
|
|
THUMB_STM_REG(64, 6, 2);
|
|
THUMB_STM_REG(128, 7, 2);
|
|
}
|
|
break;
|
|
case 0xc3:
|
|
{
|
|
// STM R3!, {Rlist}
|
|
u32 address = reg[3].I & 0xFFFFFFFC;
|
|
u32 temp = reg[3].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 3);
|
|
THUMB_STM_REG(2, 1, 3);
|
|
THUMB_STM_REG(4, 2, 3);
|
|
THUMB_STM_REG(8, 3, 3);
|
|
THUMB_STM_REG(16, 4, 3);
|
|
THUMB_STM_REG(32, 5, 3);
|
|
THUMB_STM_REG(64, 6, 3);
|
|
THUMB_STM_REG(128, 7, 3);
|
|
}
|
|
break;
|
|
case 0xc4:
|
|
{
|
|
// STM R4!, {Rlist}
|
|
u32 address = reg[4].I & 0xFFFFFFFC;
|
|
u32 temp = reg[4].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 4);
|
|
THUMB_STM_REG(2, 1, 4);
|
|
THUMB_STM_REG(4, 2, 4);
|
|
THUMB_STM_REG(8, 3, 4);
|
|
THUMB_STM_REG(16, 4, 4);
|
|
THUMB_STM_REG(32, 5, 4);
|
|
THUMB_STM_REG(64, 6, 4);
|
|
THUMB_STM_REG(128, 7, 4);
|
|
}
|
|
break;
|
|
case 0xc5:
|
|
{
|
|
// STM R5!, {Rlist}
|
|
u32 address = reg[5].I & 0xFFFFFFFC;
|
|
u32 temp = reg[5].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 5);
|
|
THUMB_STM_REG(2, 1, 5);
|
|
THUMB_STM_REG(4, 2, 5);
|
|
THUMB_STM_REG(8, 3, 5);
|
|
THUMB_STM_REG(16, 4, 5);
|
|
THUMB_STM_REG(32, 5, 5);
|
|
THUMB_STM_REG(64, 6, 5);
|
|
THUMB_STM_REG(128, 7, 5);
|
|
}
|
|
break;
|
|
case 0xc6:
|
|
{
|
|
// STM R6!, {Rlist}
|
|
u32 address = reg[6].I & 0xFFFFFFFC;
|
|
u32 temp = reg[6].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 6);
|
|
THUMB_STM_REG(2, 1, 6);
|
|
THUMB_STM_REG(4, 2, 6);
|
|
THUMB_STM_REG(8, 3, 6);
|
|
THUMB_STM_REG(16, 4, 6);
|
|
THUMB_STM_REG(32, 5, 6);
|
|
THUMB_STM_REG(64, 6, 6);
|
|
THUMB_STM_REG(128, 7, 6);
|
|
}
|
|
break;
|
|
case 0xc7:
|
|
{
|
|
// STM R7!, {Rlist}
|
|
u32 address = reg[7].I & 0xFFFFFFFC;
|
|
u32 temp = reg[7].I + 4*cpuBitsSet[opcode & 0xff];
|
|
int offset = 0;
|
|
// store
|
|
THUMB_STM_REG(1, 0, 7);
|
|
THUMB_STM_REG(2, 1, 7);
|
|
THUMB_STM_REG(4, 2, 7);
|
|
THUMB_STM_REG(8, 3, 7);
|
|
THUMB_STM_REG(16, 4, 7);
|
|
THUMB_STM_REG(32, 5, 7);
|
|
THUMB_STM_REG(64, 6, 7);
|
|
THUMB_STM_REG(128, 7, 7);
|
|
}
|
|
break;
|
|
#define THUMB_LDM_REG(val,r) \
|
|
if(opcode & (val)) {\
|
|
reg[(r)].I = CPUReadMemory(address);\
|
|
if(offset)\
|
|
clockTicks += 2 + CPUUpdateTicksAccessSeq32(address);\
|
|
else\
|
|
clockTicks += 2 + CPUUpdateTicksAccess32(address);\
|
|
offset = 1;\
|
|
address += 4;\
|
|
}
|
|
case 0xc8:
|
|
{
|
|
// LDM R0!, {Rlist}
|
|
u32 address = reg[0].I & 0xFFFFFFFC;
|
|
u32 temp = reg[0].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 1))
|
|
reg[0].I = temp;
|
|
}
|
|
break;
|
|
case 0xc9:
|
|
{
|
|
// LDM R1!, {Rlist}
|
|
u32 address = reg[1].I & 0xFFFFFFFC;
|
|
u32 temp = reg[1].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 2))
|
|
reg[1].I = temp;
|
|
}
|
|
break;
|
|
case 0xca:
|
|
{
|
|
// LDM R2!, {Rlist}
|
|
u32 address = reg[2].I & 0xFFFFFFFC;
|
|
u32 temp = reg[2].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 4))
|
|
reg[2].I = temp;
|
|
}
|
|
break;
|
|
case 0xcb:
|
|
{
|
|
// LDM R3!, {Rlist}
|
|
u32 address = reg[3].I & 0xFFFFFFFC;
|
|
u32 temp = reg[3].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 8))
|
|
reg[3].I = temp;
|
|
}
|
|
break;
|
|
case 0xcc:
|
|
{
|
|
// LDM R4!, {Rlist}
|
|
u32 address = reg[4].I & 0xFFFFFFFC;
|
|
u32 temp = reg[4].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 16))
|
|
reg[4].I = temp;
|
|
}
|
|
break;
|
|
case 0xcd:
|
|
{
|
|
// LDM R5!, {Rlist}
|
|
u32 address = reg[5].I & 0xFFFFFFFC;
|
|
u32 temp = reg[5].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 32))
|
|
reg[5].I = temp;
|
|
}
|
|
break;
|
|
case 0xce:
|
|
{
|
|
// LDM R6!, {Rlist}
|
|
u32 address = reg[6].I & 0xFFFFFFFC;
|
|
u32 temp = reg[6].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 64))
|
|
reg[6].I = temp;
|
|
}
|
|
break;
|
|
case 0xcf:
|
|
{
|
|
// LDM R7!, {Rlist}
|
|
u32 address = reg[7].I & 0xFFFFFFFC;
|
|
u32 temp = reg[7].I + 4*cpuBitsSet[opcode & 0xFF];
|
|
int offset = 0;
|
|
// load
|
|
THUMB_LDM_REG(1, 0);
|
|
THUMB_LDM_REG(2, 1);
|
|
THUMB_LDM_REG(4, 2);
|
|
THUMB_LDM_REG(8, 3);
|
|
THUMB_LDM_REG(16, 4);
|
|
THUMB_LDM_REG(32, 5);
|
|
THUMB_LDM_REG(64, 6);
|
|
THUMB_LDM_REG(128, 7);
|
|
if(!(opcode & 128))
|
|
reg[7].I = temp;
|
|
}
|
|
break;
|
|
case 0xd0:
|
|
// BEQ offset
|
|
if(Z_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd1:
|
|
// BNE offset
|
|
if(!Z_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd2:
|
|
// BCS offset
|
|
if(C_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd3:
|
|
// BCC offset
|
|
if(!C_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd4:
|
|
// BMI offset
|
|
if(N_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd5:
|
|
// BPL offset
|
|
if(!N_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd6:
|
|
// BVS offset
|
|
if(V_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd7:
|
|
// BVC offset
|
|
if(!V_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd8:
|
|
// BHI offset
|
|
if(C_FLAG && !Z_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xd9:
|
|
// BLS offset
|
|
if(!C_FLAG || Z_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xda:
|
|
// BGE offset
|
|
if(N_FLAG == V_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xdb:
|
|
// BLT offset
|
|
if(N_FLAG != V_FLAG) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xdc:
|
|
// BGT offset
|
|
if(!Z_FLAG && (N_FLAG == V_FLAG)) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xdd:
|
|
// BLE offset
|
|
if(Z_FLAG || (N_FLAG != V_FLAG)) {
|
|
reg[15].I += ((s8)(opcode & 0xFF)) << 1;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
clockTicks = 3;
|
|
}
|
|
break;
|
|
case 0xdf:
|
|
// SWI #comment
|
|
CPUSoftwareInterrupt(opcode & 0xFF);
|
|
break;
|
|
case 0xe0:
|
|
case 0xe1:
|
|
case 0xe2:
|
|
case 0xe3:
|
|
case 0xe4:
|
|
case 0xe5:
|
|
case 0xe6:
|
|
case 0xe7:
|
|
{
|
|
// B offset
|
|
int offset = (opcode & 0x3FF) << 1;
|
|
if(opcode & 0x0400)
|
|
offset |= 0xFFFFF800;
|
|
reg[15].I += offset;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
}
|
|
break;
|
|
case 0xf0:
|
|
case 0xf1:
|
|
case 0xf2:
|
|
case 0xf3:
|
|
{
|
|
// BLL #offset
|
|
int offset = (opcode & 0x7FF);
|
|
reg[14].I = reg[15].I + (offset << 12);
|
|
}
|
|
break;
|
|
case 0xf4:
|
|
case 0xf5:
|
|
case 0xf6:
|
|
case 0xf7:
|
|
{
|
|
// BLL #offset
|
|
int offset = (opcode & 0x7FF);
|
|
reg[14].I = reg[15].I + ((offset << 12) | 0xFF800000);
|
|
}
|
|
break;
|
|
case 0xf8:
|
|
case 0xf9:
|
|
case 0xfa:
|
|
case 0xfb:
|
|
case 0xfc:
|
|
case 0xfd:
|
|
case 0xfe:
|
|
case 0xff:
|
|
{
|
|
// BLH #offset
|
|
int offset = (opcode & 0x7FF);
|
|
u32 temp = reg[15].I-2;
|
|
reg[15].I = (reg[14].I + (offset<<1))&0xFFFFFFFE;
|
|
armNextPC = reg[15].I;
|
|
reg[15].I += 2;
|
|
reg[14].I = temp|1;
|
|
}
|
|
break;
|
|
#ifdef BKPT_SUPPORT
|
|
case 0xbe:
|
|
// BKPT #comment
|
|
extern void (*dbgSignal)(int,int);
|
|
reg[15].I -= 2;
|
|
armNextPC -= 2;
|
|
dbgSignal(5, opcode & 255);
|
|
return;
|
|
#endif
|
|
case 0xb1:
|
|
case 0xb2:
|
|
case 0xb3:
|
|
case 0xb6:
|
|
case 0xb7:
|
|
case 0xb8:
|
|
case 0xb9:
|
|
case 0xba:
|
|
case 0xbb:
|
|
#ifndef BKPT_SUPPORT
|
|
case 0xbe:
|
|
#endif
|
|
case 0xbf:
|
|
case 0xde:
|
|
default:
|
|
unknown_thumb:
|
|
#ifdef DEV_VERSION
|
|
if(systemVerbose & VERBOSE_UNDEFINED)
|
|
log("Undefined THUMB instruction %04x at %08x\n", opcode, armNextPC-2);
|
|
#endif
|
|
CPUUndefinedException();
|
|
break;
|
|
}
|