BizHawk/BizHawk.Emulation/CPUs/ARM/ARM.ExecuteThumb.cs

962 lines
27 KiB
C#

using System;
using System.Diagnostics;
namespace BizHawk.Emulation.CPUs.ARM
{
partial class ARM
{
uint ExecuteThumb()
{
uint opcode = instruction >> 10;
_currentCondVal = 14;
//TODO - this one could really be turned into a table
switch (opcode)
{
case _.b000000:
case _.b000001:
case _.b000010:
case _.b000011:
case _.b000100:
case _.b000101:
case _.b000110:
case _.b000111:
case _.b001000:
case _.b001001:
case _.b001010:
case _.b001011:
case _.b001100:
case _.b001101:
case _.b001110:
case _.b001111:
return ExecuteThumb_AluMisc();
case _.b010000: return ExecuteThumb_DataProcessing();
case _.b010001: return ExecuteThumb_SpecialBX();
case _.b010010:
case _.b010011:
return Execute_LDR_literal_T1();
case _.b010100:
case _.b010101:
case _.b010110:
case _.b010111:
case _.b011000:
case _.b011001:
case _.b011010:
case _.b011011:
case _.b011100:
case _.b011101:
case _.b011110:
case _.b011111:
case _.b100000:
case _.b100001:
case _.b100010:
case _.b100011:
case _.b100100:
case _.b100101:
case _.b100110:
case _.b100111:
return ExecuteThumb_LoadStore();
case _.b101000:
case _.b101001: return Execute_ADR_T1();
case _.b101010:
case _.b101011: return Execute_ADD_SP_plus_immediate_T1();
case _.b101100:
case _.b101101:
case _.b101110:
case _.b101111:
return ExecuteThumb_Misc16();
case _.b110000:
case _.b110001: return Execute_STM_STMIA_STMEA_T1();
case _.b110010:
case _.b110011: return Execute_LDM_LDMIA_LDMFD_T1();
case _.b110100:
case _.b110101:
case _.b110110:
case _.b110111:
return ExecuteThumb_CondBr_And_SVC();
case _.b111000:
case _.b111001: return Execute_B_T2();
case _.b111010:
case _.b111011:
case _.b111100:
case _.b111101:
case _.b111110:
case _.b111111:
return ExecuteThumb_32();
default:
throw new InvalidOperationException("unhandled case in ExecuteThumb");
}
}
uint Execute_LDR_literal_T1()
{
//A8.6.59
uint t = Reg8(8);
uint imm8 = instruction & 0xFF;
uint imm32 = imm8 << 2;
const bool add = true;
return ExecuteCore_LDR_literal(Encoding.T1, t, imm32, add);
}
uint ExecuteThumb_LoadStore()
{
//A6.2.4
uint opA = (instruction >> 12) & 0xF;
uint opB = (instruction >> 9) & 0x7;
switch (opA)
{
case _.b0101:
switch (opB)
{
case _.b000: return Execute_Unhandled("STR (register) on page A8-386");
case _.b001: return Execute_Unhandled("STRH (register) on page A8-412");
case _.b010: return Execute_STRB_register_T1();
case _.b011: return Execute_Unhandled("LDRSB (register) on page A8-164");
case _.b100: return Execute_LDR_register_T1();
case _.b101: return Execute_Unhandled("LDRH (register)");
case _.b110: return Execute_LDRB_register_T1();
case _.b111: return Execute_Unhandled("LDRSH (register) on page A8-172");
default: throw new InvalidOperationException("decoder fail");
}
case _.b0110:
switch (opB)
{
case _.b000:
case _.b001:
case _.b010:
case _.b011: return Execute_STR_immediate_thumb_T1();
case _.b100:
case _.b101:
case _.b110:
case _.b111: return Execute_LDR_immediate_thumb_T1();
default: throw new InvalidOperationException("decoder fail");
}
case _.b0111:
switch (opB)
{
case _.b000:
case _.b001:
case _.b010:
case _.b011: return Execute_STRB_immediate_thumb_T1();
case _.b100:
case _.b101:
case _.b110:
case _.b111: return Execute_LDRB_immediate_thumb_T1();
default: throw new InvalidOperationException("decoder fail");
}
case _.b1000:
switch (opB)
{
case _.b000:
case _.b001:
case _.b010:
case _.b011: return Execute_STRH_immediate_thumb_T1();
case _.b100:
case _.b101:
case _.b110:
case _.b111: return Execute_LDRH_immediate_thumb_T1();
default: throw new InvalidOperationException("decoder fail");
}
case _.b1001:
switch (opB)
{
case _.b000:
case _.b001:
case _.b010:
case _.b011: return Execute_STR_immediate_thumb_T2();
case _.b100:
case _.b101:
case _.b110:
case _.b111: return Execute_LDR_immediate_thumb_T2();
default: throw new InvalidOperationException("decoder fail");
}
default: throw new InvalidOperationException("decoder fail");
} //switch(opA)
}
uint Execute_STRB_register_T1()
{
//A8.6.198
uint t = Reg8(0);
uint n = Reg8(3);
uint m = Reg8(6);
const bool index = true; const bool add = true; const bool wback = false;
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_STRB_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback);
}
uint Execute_LDR_register_T1()
{
//A8.6.60
if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotSupportedException("Modified operatoin in ThumbEE");
uint t = Reg8(0);
uint n = Reg8(3);
uint m = Reg8(6);
const bool index = true; const bool add = true; const bool wback = false;
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_LDR_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback);
}
uint Execute_LDRB_register_T1()
{
//A8.6.64
uint t = Reg8(0);
uint n = Reg8(3);
uint m = Reg8(6);
const bool index = true; const bool add = true; const bool wback = false;
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_LDRB_register(Encoding.T1, t, n, m, shift_t, shift_n, index, add, wback);
}
uint Execute_LDRB_immediate_thumb_T1()
{
//A8.6.61
uint t = Reg8(0);
uint n = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
uint imm32 = _ZeroExtend_32(imm5);
const bool index = true; const bool add = true; const bool wback = false;
return ExecuteCore_LDRB_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
}
uint Execute_STRB_immediate_thumb_T1()
{
//A8.6.196
uint t = Reg8(0);
uint n = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
uint imm32 = _ZeroExtend_32(imm5);
const bool index = true; const bool add = true; const bool wback = false;
return ExecuteCore_STRB_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
}
uint Execute_LDRH_immediate_thumb_T1()
{
//A8.6.73
uint t = Reg8(0);
uint n = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
uint imm32 = _ZeroExtend_32(imm5 << 1);
const bool index = true; const bool add = true; const bool wback = false;
return ExecuteCore_LDRH_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
}
uint Execute_STRH_immediate_thumb_T1()
{
//A8.6.206 STRH
uint t = Reg8(0);
uint n = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
uint imm32 = _ZeroExtend_32(imm5 << 1);
const bool index = true; const bool add = true; const bool wback = false;
return ExecuteCore_STRH_immediate_thumb(Encoding.T1, t, n, imm32, index, add, wback);
}
uint Execute_LDR_immediate_thumb_T1()
{
//A8.6.57 LDR (immediate,thumb)
uint t = Reg8(0);
uint n = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
uint imm32 = _ZeroExtend_32(imm5 << 2);
bool index = true; bool add = true; bool wback = false;
return ExecuteCore_LDR_immediate_thumb(Encoding.T1, t, imm32, n, index, add, wback);
}
uint Execute_STR_immediate_thumb_T1()
{
//A8.6.193 STR (immediate,thumb)
uint t = Reg8(0);
uint n = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
uint imm32 = _ZeroExtend_32(imm5 << 2);
bool index = true; bool add = true; bool wback = false;
return ExecuteCore_STR_immediate_thumb(Encoding.T1, t, imm32, n, index, add, wback);
}
uint Execute_LDR_immediate_thumb_T2()
{
//A8.6.57 LDR (immediate, thumb)
uint t = Reg8(8);
uint imm8 = instruction & 0xFF;
const uint n = 13;
uint imm32 = _ZeroExtend_32(imm8 << 2);
const bool index = true; const bool add = true; const bool wback = false;
return ExecuteCore_LDR_immediate_thumb(Encoding.T2, t, imm32, n, index, add, wback);
}
uint Execute_STR_immediate_thumb_T2()
{
//A8.6.193 STR (immediate,thumb)
uint Rt = Reg8(8);
uint imm8 = instruction & 0xFF;
const uint n = 13;
uint imm32 = _ZeroExtend_32(imm8 << 2);
const bool index = true; const bool add = true; const bool wback = false;
return ExecuteCore_STR_immediate_thumb(Encoding.T2, Rt, imm32, n, index, add, wback);
}
uint ExecuteThumb_32()
{
uint op1 = (instruction >> 11) & 3;
uint op2 = (instruction >> 4) & 0x7F;
ThumbFetchExtra();
uint op = _.BIT15(thumb_32bit_extra);
switch (op1)
{
case _.b00: throw new InvalidOperationException("decode error");
case _.b01: return Execute_Unhandled("thumb-32bit");
case _.b10:
if (op == 0) return Execute_Unhandled("thumb-32bit");
else return ExecuteThumb_32_BranchAndMiscControl(op2);
case _.b11:
return Execute_Unhandled("thumb-32bit");
default: throw new InvalidOperationException();
}
}
uint ExecuteThumb_32_BranchAndMiscControl(uint op)
{
uint op1 = (thumb_32bit_extra >> 12) & 7;
switch (op1)
{
case _.b000:
case _.b010:
return Execute_Unhandled("thumb-32bit");
case _.b001:
case _.b011: return Execute_Unhandled("thumb-32bit 6T2 branch");
case _.b100:
case _.b110: return Execute_BL_BLX_immediate_T2();
case _.b101:
case _.b111: return Execute_BL_BLX_immediate_T1();
default: throw new InvalidOperationException();
}
}
uint Execute_BL_BLX_immediate_T1()
{
//A8.6.23
uint S = _.BIT10(instruction);
uint J1 = _.BIT13(thumb_32bit_extra);
uint J2 = _.BIT11(thumb_32bit_extra);
uint imm11 = thumb_32bit_extra & _.b11111111111;
uint imm10 = instruction & _.b1111111111;
uint I1 = (~(J1 ^ S)) & 1;
uint I2 = (~(J2 ^ S)) & 1;
int imm32 = _SignExtend_32(25, (imm11 << 1) | (imm10 << 12) | (I2 << 22) | (I1 << 23) | (S << 24));
if (_InITBlock() && !_LastInITBlock()) _UNPREDICTABLE();
return ExecuteCore_BL_BLX_immediate(Encoding.T1, _CurrentInstrSet(), imm32, false);
}
uint Execute_BL_BLX_immediate_T2()
{
//A8.6.23
uint S = _.BIT10(instruction);
uint J1 = _.BIT13(thumb_32bit_extra);
uint J2 = _.BIT11(thumb_32bit_extra);
uint H = _.BIT0(thumb_32bit_extra);
uint imm10L = (thumb_32bit_extra >> 1) & 0x3FF;
uint imm10H = instruction & 0x3FF;
uint I1 = (~(J1 ^ S)) & 1;
uint I2 = (~(J2 ^ S)) & 1;
int imm32 = _SignExtend_32(25, (imm10L << 2) | (imm10H << 12) | (I2 << 22) | (I1 << 23) | (S << 24));
return ExecuteCore_BL_BLX_immediate(Encoding.T2, EInstrSet.ARM, imm32, true);
}
uint ExecuteThumb_AluMisc()
{
//A6.2.1
uint opcode = (instruction >> 9) & 0x1F;
switch (opcode)
{
case _.b00000:
case _.b00001:
case _.b00010:
case _.b00011:
return Execute_LSL_immediate_T1();
case _.b00100:
case _.b00101:
case _.b00110:
case _.b00111:
return Execute_LSR_immediate_T1();
case _.b01000:
case _.b01001:
case _.b01010:
case _.b01011:
return Execute_ASR_immediate_T1();
case _.b01100: return Execute_ADD_Register_T1();
case _.b01101: return Execute_SUB_Register_T1();
case _.b01110: return Execute_ADD_immediate_thumb_T1();
case _.b01111: return Execute_SUB_immediate_thumb_T1();
case _.b10000:
case _.b10001:
case _.b10010:
case _.b10011:
return Execute_MOV_immediate_T1();
case _.b10100:
case _.b10101:
case _.b10110:
case _.b10111:
return Execute_CMP_immediate_T1();
case _.b11000:
case _.b11001:
case _.b11010:
case _.b11011:
return Execute_ADD_immediate_thumb_T2();
case _.b11100:
case _.b11101:
case _.b11110:
case _.b11111:
return Execute_SUB_immediate_thumb_T2();
}
return Execute_Unhandled("ExecuteThumb_AluMisc");
}
uint Execute_CMP_immediate_T1()
{
//A8.6.35 CMP immediate
//A8-80
uint n = Reg8(8);
uint imm8 = instruction & 0xFF;
uint imm32 = _ZeroExtend_32(imm8);
return ExecuteCore_CMP_immediate(Encoding.T1, n, imm32);
}
uint Execute_MOV_immediate_T1()
{
//A8.6.96 MOV immediate
uint d = Reg8(8);
uint imm8 = instruction & 0xFF;
bool setflags = !_InITBlock();
uint imm32 = _ZeroExtend_32(imm8);
Bit carry = APSR.C;
return ExecuteCore_MOV_immediate(Encoding.T1, d, setflags, imm32, carry);
}
uint Execute_SUB_Register_T1()
{
//A8.6.213 SUB (register)
uint d = Reg8(0);
uint n = Reg8(3);
uint m = Reg8(6);
bool setflags = !_InITBlock();
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_SUB_register(Encoding.T1, setflags, m, n, d, shift_t, shift_n);
}
uint Execute_ADD_Register_T1()
{
//A8.6.6 ADD (register)
uint d = Reg8(0);
uint n = Reg8(3);
uint m = Reg8(6);
bool setflags = !_InITBlock();
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_ADD_register(Encoding.T1, m, d, n, setflags, shift_t, shift_n);
}
uint Execute_ADD_register_T2()
{
//A8.6.6 ADD (register)
Bit DN = _.BIT7(instruction);
uint rdn = Reg8(0);
uint m = Reg16(3);
Debug.Assert(!(DN == 1 && rdn == _.b101 || m == _.b1101), "see ADD (SP plus register)");
uint d = rdn;
uint n = rdn;
bool setflags = false;
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
if (n == 15 && m == 15) _FlagUnpredictable();
if (d == 15 && _InITBlock() && !_LastInITBlock()) _FlagUnpredictable();
return ExecuteCore_ADD_register(Encoding.T2, m, d, n, setflags, shift_t, shift_n);
}
uint Execute_SUB_immediate_thumb_T1()
{
//A7.6.211
uint d = Reg8(0);
uint n = Reg8(3);
uint imm3 = (instruction >> 6) & 7;
bool setflags = !_InITBlock();
uint imm32 = _ZeroExtend_32(imm3);
return ExecuteCore_SUB_immediate_thumb(Encoding.T1, n, d, setflags, imm32);
}
uint Execute_ADD_immediate_thumb_T1()
{
uint d = Reg8(0);
uint n = Reg8(3);
uint imm3 = (instruction >> 6) & 7;
bool setflags = !_InITBlock();
uint imm32 = _ZeroExtend_32(imm3);
return ExecuteCore_ADD_immediate_thumb(Encoding.T1, n, d, setflags, imm32);
}
uint Execute_SUB_immediate_thumb_T2()
{
//A8.6.211
uint d = Reg8(8);
uint n = d;
bool setflags = !_InITBlock();
uint imm8 = (instruction & 0xFF);
uint imm32 = _ZeroExtend_32(imm8);
return ExecuteCore_SUB_immediate_thumb(Encoding.T2, n, d, setflags, imm32);
}
uint Execute_ADD_immediate_thumb_T2()
{
uint Rdn = Reg8(8);
uint imm8 = instruction & _.b11111111;
uint d = Rdn;
uint n = Rdn;
bool setflags = !_InITBlock();
uint imm32 = imm8;
return ExecuteCore_ADD_immediate_thumb(Encoding.T2, n, d, setflags, imm32);
}
uint Execute_LSL_immediate_T1()
{
//A8.6.14
uint imm5 = (instruction >> 6) & 0x1F;
if (imm5 == 0 && procopt.Thumb_LSL_immediate_T1_0_is_MOV_register_T2) return Execute_MOV_register_T2();
uint d = Reg8(0);
uint m = Reg8(3);
bool setflags = !_InITBlock();
_DecodeImmShift(0, imm5);
return ExecuteCore_LSL_immediate(Encoding.T1, d, m, setflags, shift_n);
}
uint Execute_ASR_immediate_T1()
{
//A8.6.14 ASR (immediate)
uint d = Reg8(0);
uint m = Reg8(3);
uint imm5 = (instruction >> 6) & 0x1F;
bool setflags = !_InITBlock();
_DecodeImmShift(_.b10, imm5);
return ExecuteCore_ASR_immediate(Encoding.T1, d, m, setflags, shift_n);
}
uint Execute_LSR_immediate_T1()
{
uint imm5 = (instruction >> 6) & 0x1F;
uint m = Reg8(3);
uint d = Reg8(0);
bool setflags = !_InITBlock();
_DecodeImmShift(_.b01, imm5);
return ExecuteCore_LSR_immediate(Encoding.T1, d, m, setflags, shift_n);
}
uint Execute_MOV_register_T1()
{
//A8.6.97 MOV (register)
uint D = _.BIT7(instruction);
uint d = Reg8(0) + 8 * D;
uint m = Reg16(3);
bool setflags = false;
if (d == 15 && _InITBlock() && !_LastInITBlock()) unpredictable = true;
//my own sanity check:
if (m >= 8 && _ArchVersion() < 6) throw new InvalidOperationException("thumb mov register invalid for your architecture version. need to think about this.");
return ExecuteCore_MOV_register(Encoding.T1, d, m, setflags);
}
uint Execute_MOV_register_T2()
{
uint D = _.BIT7(instruction);
uint d = Reg8(0);
uint m = Reg8(3);
bool setflags = true;
if (_InITBlock()) unpredictable = true;
return ExecuteCore_MOV_register(Encoding.T2, d, m, setflags);
}
uint ExecuteThumb_DataProcessing()
{
//A6.2.2
uint opcode = (instruction >> 6) & 0xF;
switch (opcode)
{
case _.b0000: return Execute_Unhandled("thumb AND reg");
case _.b0001: return Execute_EOR_register_T1();
case _.b0010: return Execute_Unhandled("thumb LSL reg");
case _.b0011: return Execute_Unhandled("thumb LSR reg");
case _.b0100: return Execute_Unhandled("thumb ASR reg");
case _.b0101: return Execute_Unhandled("thumb ADC reg");
case _.b0110: return Execute_Unhandled("thumb SBC reg");
case _.b0111: return Execute_Unhandled("thumb ROR reg");
case _.b1000: return Execute_Unhandled("thumb TST reg");
case _.b1001: return Execute_RSB_immediate_T1();
case _.b1010: return Execute_CMP_register_T1();
case _.b1011: return Execute_Unhandled("thumb CMN reg");
case _.b1100: return Execute_ORR_register_T1();
case _.b1101: return Execute_Unhandled("thumb MUL");
case _.b1110: return Execute_Unhandled("thumb BIC reg");
case _.b1111: return Execute_Unhandled("thumb MVN reg");
default: throw new InvalidOperationException();
}
}
uint Execute_RSB_immediate_T1()
{
//A8.6.142
uint d = Reg8(0);
uint n = Reg8(3);
bool setflags = !_InITBlock();
uint imm32 = 0;
return ExecuteCore_RSB_immediate(Encoding.T1, d, n, setflags, imm32);
}
uint Execute_EOR_register_T1()
{
//A8.6.45
uint d = Reg8(0);
uint n = d;
uint m = Reg8(3);
bool setflags = !_InITBlock();
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_EOR_register(Encoding.T1, m, d, n, setflags, shift_t, shift_n);
}
uint Execute_ORR_register_T1()
{
//A7.6.114
uint d = Reg8(0);
uint n = d;
uint m = Reg8(3);
bool setflags = !_InITBlock();
const SRType shift_t = SRType.LSL;
const int shift_n = 0;
return ExecuteCore_ORR_register(Encoding.T1, m, d, n, setflags, shift_t, shift_n);
}
uint Execute_CMP_register_T1()
{
//A8.6.36
uint n = Reg8(0);
uint m = Reg8(3);
SRType shift_t = SRType.LSL;
int shift_n = 0;
return ExecuteCore_CMP_register(Encoding.T1, n, m, shift_t, shift_n);
}
uint ExecuteThumb_SpecialBX()
{
uint opcode = (instruction >> 6) & _.b1111;
switch (opcode)
{
case _.b0000:
return Execute_Unhandled("ADD (low register) on page A8-24 [v6T2*] *unpredictable in earlier variants");
case _.b0001:
case _.b0010:
case _.b0011:
return Execute_ADD_register_T2();
case _.b0100:
return _UNPREDICTABLE();
case _.b0101:
case _.b0110:
case _.b0111:
return Execute_Unhandled("CMP (high register) on page A8-82 [v4t]");
case _.b1000:
return Execute_MOV_register_T1();
case _.b1001:
case _.b1010:
case _.b1011:
return Execute_MOV_register_T1();
case _.b1100:
case _.b1101:
return Execute_BX_T1();
case _.b1110:
case _.b1111:
return Execute_BLX_register_T1();
default: throw new InvalidOperationException("decode fail");
}
}
uint Execute_BLX_register_T1()
{
//A8.6.24
uint m = Reg16(3);
if (m == 15) _FlagUnpredictable();
if (_InITBlock() && !_LastInITBlock()) _FlagUnpredictable();
return ExecuteCore_BLX_register(Encoding.T1, m);
}
uint Execute_BX_T1()
{
//A8.6.25
uint m = Reg16(3);
if (_InITBlock() && !_LastInITBlock()) return _UNPREDICTABLE();
if (disassemble)
return DISNEW("BX", "<Rm!>", m);
_BXWritePC(r[m]);
return 1;
}
uint Execute_ADR_T1()
{
//A8.6.10
uint d = Reg8(8);
uint imm8 = instruction & 0xFF;
uint imm32 = _ZeroExtend_32(imm8 << 2);
const bool add = true;
return ExecuteCore_ADR(Encoding.T1, d, imm32, add);
}
uint Execute_ADD_SP_plus_immediate_T2()
{
//A8.6.8
uint d = 13;
uint imm7 = (instruction & 0xFF);
bool setflags = false;
uint imm32 = _ZeroExtend_32(imm7 << 2);
return ExecuteCore_ADD_SP_plus_immedate(Encoding.T2, d, setflags, imm32);
}
uint Execute_ADD_SP_plus_immediate_T1()
{
//A8.6.8 ADD SP plus immediate
//A8-28
uint d = Reg8(8);
uint imm8 = (instruction & 0xFF);
bool setflags = false;
uint imm32 = _ZeroExtend_32(imm8 << 2);
return ExecuteCore_ADD_SP_plus_immedate(Encoding.T1, d, setflags, imm32);
}
uint ExecuteThumb_Misc16()
{
uint opcode = (instruction >> 5) & 0x7F;
//ThumbMisc
switch((opcode<<0)) {
//opcode == #0110010
case 50:
Execute_Unhandled("SETEND on page A8-314");
break;
//opcode == #0110011
case 51:
Execute_Unhandled("CPS on page B6-3");
break;
//opcode == #00000xx
case 0: case 1: case 2: case 3:
Execute_ADD_SP_plus_immediate_T2();
break;
//opcode == #00001xx
case 4: case 5: case 6: case 7:
Execute_SUB_SP_minus_immediate_T1();
break;
//opcode == #0001xxx
//opcode == #0011xxx
//opcode == #1001xxx
case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 24: case 25: case 26: case 27: case 28: case 29: case 30: case 31: case 72: case 73: case 74: case 75: case 76: case 77: case 78: case 79:
Execute_Unhandled("CBNZ,CBZ on page A8-66 [v6T2]");
break;
//opcode == #001000x
case 16: case 17:
Execute_Unhandled("SXTH on page A8-444");
break;
//opcode == #001001x
case 18: case 19:
Execute_Unhandled("SXTB on page A8-440");
break;
//opcode == #001010x
case 20: case 21:
Execute_UXTH_T1();
break;
//opcode == #001011x
case 22: case 23:
Execute_UXTB_T1();
break;
//opcode == #010xxxx
case 32: case 33: case 34: case 35: case 36: case 37: case 38: case 39: case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47:
Execute_PUSH_T1();
break;
//opcode == #101000x
case 80: case 81:
Execute_Unhandled("REV on page A8-272");
break;
//opcode == #101001x
case 82: case 83:
Execute_Unhandled("REV16 on page A8-274");
break;
//opcode == #101011x
case 86: case 87:
Execute_Unhandled("REVSH on page A8-276");
break;
//opcode == #110xxxx
case 96: case 97: case 98: case 99: case 100: case 101: case 102: case 103: case 104: case 105: case 106: case 107: case 108: case 109: case 110: case 111:
Execute_POP_T1();
break;
//opcode == #1110xxx
case 112: case 113: case 114: case 115: case 116: case 117: case 118: case 119:
Execute_Unhandled("BKPT on page A8-56");
break;
//opcode == #1111xxx
case 120: case 121: case 122: case 123: case 124: case 125: case 126: case 127:
Execute_Unhandled("If-Then and hints on page A6-12");
break;
default: throw new InvalidOperationException("unhandled case for switch ThumbMisc");
}
return 1;
}
uint Execute_POP_T1()
{
//A8.6.122
uint P = _.BIT8(instruction);
uint registers = (P << 15) | (instruction & 0xFF);
bool UnalignedAllowed = false;
if (registers == 0) { _UNPREDICTABLE(); return 1; }
if (P == 1 && _InITBlock() && !_LastInITBlock()) { _UNPREDICTABLE(); return 1; }
if (disassemble)
return DISNEW("pop<c>", "<registers>", registers);
return ExecuteCore_POP(Encoding.T1, registers, UnalignedAllowed);
}
uint Execute_SUB_SP_minus_immediate_T1()
{
//A8.6.215 SUB (SP minus immediate)
const uint d = 13;
uint imm7 = instruction & 0x7F;
bool setflags = false;
uint imm32 = _ZeroExtend_32(imm7 << 2);
return ExecuteCore_SUB_SP_minus_immediate(Encoding.T1, d, setflags, imm32);
}
uint Execute_UXTH_T1()
{
//A8.6.265
uint d = Reg8(0);
uint m = Reg8(3);
const uint rotation = 0;
return ExecuteCore_UXTH(Encoding.T1, d, m, rotation);
}
uint Execute_UXTB_T1()
{
//A8.6.263
uint d = Reg8(0);
uint m = Reg8(3);
const uint rotation = 0;
return ExecuteCore_UXTB(Encoding.T1, d, m, rotation);
}
uint Execute_PUSH_T1()
{
//A8.6.123
uint M = _.BIT8(instruction);
uint regs = (M << 14) | (instruction & 0xFF);
if (_.BitCount(regs) < 1) unpredictable = true;
return ExecuteCore_PUSH(Encoding.T1, regs, false);
}
uint Execute_LDM_LDMIA_LDMFD_T1()
{
//A8.6.53 LDM/LDMIA/LDMFD
if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotImplementedException();
uint n = Reg8(8);
uint registers = instruction & 0xFF;
bool wback = (_.BITN((int)n, registers) == 0);
if (registers == 0) _FlagUnpredictable();
return ExecuteCore_LDM_LDMIA_LDMFD(Encoding.T1, wback, n, registers);
}
uint Execute_STM_STMIA_STMEA_T1()
{
//A8.6.189 STM/STMIA/STMEA
if (_CurrentInstrSet() == EInstrSet.THUMBEE) throw new NotImplementedException();
uint n = Reg8(8);
uint registers = instruction & 0xFF;
bool wback = true;
if (registers == 0) unpredictable = true;
return ExecuteCore_STM_STMIA_STMEA(Encoding.T1, wback, n, registers);
}
uint ExecuteThumb_CondBr_And_SVC()
{
uint opcode = (instruction >> 8) & 0xF;
switch (opcode)
{
case _.b0000:
case _.b0001:
case _.b0010:
case _.b0011:
case _.b0100:
case _.b0101:
case _.b0110:
case _.b0111:
case _.b1000:
case _.b1001:
case _.b1010:
case _.b1011:
case _.b1100:
case _.b1101:
return Execute_B_T1();
case _.b1110: return _PERMANENTLY_UNDEFINED();
case _.b1111: return Execute_SVC_T1();
default: throw new InvalidOperationException("decode fail");
}
}
uint ExecuteThumb_UnCondBr() { return Execute_Unhandled("ExecuteThumb_UnCondBr"); }
uint Execute_B_T2()
{
//A8.6.16 B
uint imm11 = instruction & 0x7FF;
int imm32 = _SignExtend_32(11, imm11 << 1);
if (_InITBlock() && !_LastInITBlock()) unpredictable = true;
return ExecuteCore_B(Encoding.T2, imm32);
}
uint Execute_B_T1()
{
//A8.6.16 B
uint imm8 = (instruction & 0xFF);
int imm32 = _SignExtend_32(9, imm8 << 1);
_currentCondVal = (instruction >> 8) & 0xF;
if (_InITBlock()) return _UNPREDICTABLE();
return ExecuteCore_B(Encoding.T1, imm32);
}
uint Execute_SVC_T1()
{
return Execute_Unhandled("Execute_SVC_T1");
}
}
}