summaryrefslogtreecommitdiffstats
path: root/src/core/arm/dyncom/arm_dyncom_thumb.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp390
1 files changed, 0 insertions, 390 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
deleted file mode 100644
index 2a3dd0f53..000000000
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ /dev/null
@@ -1,390 +0,0 @@
-// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include <cstddef>
-
-// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
-// ARM instruction, and using the existing ARM simulator.
-
-#include "core/arm/dyncom/arm_dyncom_thumb.h"
-#include "core/arm/skyeye_common/armsupp.h"
-
-// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
-// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
-// allows easier simulation of the special dual BL instruction.
-
-ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
- ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED;
- u32 tinstr = GetThumbInstruction(instr, addr);
-
- *ainstr = 0xDEADC0DE; // Debugging to catch non updates
-
- switch ((tinstr & 0xF800) >> 11) {
- case 0: // LSL
- case 1: // LSR
- case 2: // ASR
- *ainstr = 0xE1B00000 // base opcode
- | ((tinstr & 0x1800) >> (11 - 5)) // shift type
- | ((tinstr & 0x07C0) << (7 - 6)) // imm5
- | ((tinstr & 0x0038) >> 3) // Rs
- | ((tinstr & 0x0007) << 12); // Rd
- break;
-
- case 3: // ADD/SUB
- {
- static const u32 subset[4] = {
- 0xE0900000, // ADDS Rd,Rs,Rn
- 0xE0500000, // SUBS Rd,Rs,Rn
- 0xE2900000, // ADDS Rd,Rs,#imm3
- 0xE2500000 // SUBS Rd,Rs,#imm3
- };
- // It is quicker indexing into a table, than performing switch or conditionals:
- *ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode
- | ((tinstr & 0x01C0) >> 6) // Rn or imm3
- | ((tinstr & 0x0038) << (16 - 3)) // Rs
- | ((tinstr & 0x0007) << (12 - 0)); // Rd
- } break;
-
- case 4: // MOV
- case 5: // CMP
- case 6: // ADD
- case 7: // SUB
- {
- static const u32 subset[4] = {
- 0xE3B00000, // MOVS Rd,#imm8
- 0xE3500000, // CMP Rd,#imm8
- 0xE2900000, // ADDS Rd,Rd,#imm8
- 0xE2500000, // SUBS Rd,Rd,#imm8
- };
-
- *ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode
- | ((tinstr & 0x00FF) >> 0) // imm8
- | ((tinstr & 0x0700) << (16 - 8)) // Rn
- | ((tinstr & 0x0700) << (12 - 8)); // Rd
- } break;
-
- case 8: // Arithmetic and high register transfers
-
- // TODO: Since the subsets for both Format 4 and Format 5 instructions are made up of
- // different ARM encodings, we could save the following conditional, and just have one
- // large subset
-
- if ((tinstr & (1 << 10)) == 0) {
- enum otype { t_norm, t_shift, t_neg, t_mul };
-
- static const struct {
- u32 opcode;
- otype type;
- } subset[16] = {
- {0xE0100000, t_norm}, // ANDS Rd,Rd,Rs
- {0xE0300000, t_norm}, // EORS Rd,Rd,Rs
- {0xE1B00010, t_shift}, // MOVS Rd,Rd,LSL Rs
- {0xE1B00030, t_shift}, // MOVS Rd,Rd,LSR Rs
- {0xE1B00050, t_shift}, // MOVS Rd,Rd,ASR Rs
- {0xE0B00000, t_norm}, // ADCS Rd,Rd,Rs
- {0xE0D00000, t_norm}, // SBCS Rd,Rd,Rs
- {0xE1B00070, t_shift}, // MOVS Rd,Rd,ROR Rs
- {0xE1100000, t_norm}, // TST Rd,Rs
- {0xE2700000, t_neg}, // RSBS Rd,Rs,#0
- {0xE1500000, t_norm}, // CMP Rd,Rs
- {0xE1700000, t_norm}, // CMN Rd,Rs
- {0xE1900000, t_norm}, // ORRS Rd,Rd,Rs
- {0xE0100090, t_mul}, // MULS Rd,Rd,Rs
- {0xE1D00000, t_norm}, // BICS Rd,Rd,Rs
- {0xE1F00000, t_norm} // MVNS Rd,Rs
- };
-
- *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; // base
-
- switch (subset[(tinstr & 0x03C0) >> 6].type) {
- case t_norm:
- *ainstr |= ((tinstr & 0x0007) << 16) // Rn
- | ((tinstr & 0x0007) << 12) // Rd
- | ((tinstr & 0x0038) >> 3); // Rs
- break;
- case t_shift:
- *ainstr |= ((tinstr & 0x0007) << 12) // Rd
- | ((tinstr & 0x0007) >> 0) // Rm
- | ((tinstr & 0x0038) << (8 - 3)); // Rs
- break;
- case t_neg:
- *ainstr |= ((tinstr & 0x0007) << 12) // Rd
- | ((tinstr & 0x0038) << (16 - 3)); // Rn
- break;
- case t_mul:
- *ainstr |= ((tinstr & 0x0007) << 16) // Rd
- | ((tinstr & 0x0007) << 8) // Rs
- | ((tinstr & 0x0038) >> 3); // Rm
- break;
- }
- } else {
- u32 Rd = ((tinstr & 0x0007) >> 0);
- u32 Rs = ((tinstr & 0x0078) >> 3);
-
- if (tinstr & (1 << 7))
- Rd += 8;
-
- switch ((tinstr & 0x03C0) >> 6) {
- case 0x0: // ADD Rd,Rd,Rs
- case 0x1: // ADD Rd,Rd,Hs
- case 0x2: // ADD Hd,Hd,Rs
- case 0x3: // ADD Hd,Hd,Hs
- *ainstr = 0xE0800000 // base
- | (Rd << 16) // Rn
- | (Rd << 12) // Rd
- | (Rs << 0); // Rm
- break;
- case 0x4: // CMP Rd,Rs
- case 0x5: // CMP Rd,Hs
- case 0x6: // CMP Hd,Rs
- case 0x7: // CMP Hd,Hs
- *ainstr = 0xE1500000 // base
- | (Rd << 16) // Rn
- | (Rs << 0); // Rm
- break;
- case 0x8: // MOV Rd,Rs
- case 0x9: // MOV Rd,Hs
- case 0xA: // MOV Hd,Rs
- case 0xB: // MOV Hd,Hs
- *ainstr = 0xE1A00000 // base
- | (Rd << 12) // Rd
- | (Rs << 0); // Rm
- break;
- case 0xC: // BX Rs
- case 0xD: // BX Hs
- *ainstr = 0xE12FFF10 // base
- | ((tinstr & 0x0078) >> 3); // Rd
- break;
- case 0xE: // BLX
- case 0xF: // BLX
- *ainstr = 0xE1200030 // base
- | (Rs << 0); // Rm
- break;
- }
- }
- break;
-
- case 9: // LDR Rd,[PC,#imm8]
- *ainstr = 0xE59F0000 // base
- | ((tinstr & 0x0700) << (12 - 8)) // Rd
- | ((tinstr & 0x00FF) << (2 - 0)); // off8
- break;
-
- case 10:
- case 11: {
- static const u32 subset[8] = {
- 0xE7800000, // STR Rd,[Rb,Ro]
- 0xE18000B0, // STRH Rd,[Rb,Ro]
- 0xE7C00000, // STRB Rd,[Rb,Ro]
- 0xE19000D0, // LDRSB Rd,[Rb,Ro]
- 0xE7900000, // LDR Rd,[Rb,Ro]
- 0xE19000B0, // LDRH Rd,[Rb,Ro]
- 0xE7D00000, // LDRB Rd,[Rb,Ro]
- 0xE19000F0 // LDRSH Rd,[Rb,Ro]
- };
-
- *ainstr = subset[(tinstr & 0xE00) >> 9] // base
- | ((tinstr & 0x0007) << (12 - 0)) // Rd
- | ((tinstr & 0x0038) << (16 - 3)) // Rb
- | ((tinstr & 0x01C0) >> 6); // Ro
- } break;
-
- case 12: // STR Rd,[Rb,#imm5]
- case 13: // LDR Rd,[Rb,#imm5]
- case 14: // STRB Rd,[Rb,#imm5]
- case 15: // LDRB Rd,[Rb,#imm5]
- {
- static const u32 subset[4] = {
- 0xE5800000, // STR Rd,[Rb,#imm5]
- 0xE5900000, // LDR Rd,[Rb,#imm5]
- 0xE5C00000, // STRB Rd,[Rb,#imm5]
- 0xE5D00000 // LDRB Rd,[Rb,#imm5]
- };
- // The offset range defends on whether we are transferring a byte or word value:
- *ainstr = subset[(tinstr & 0x1800) >> 11] // base
- | ((tinstr & 0x0007) << (12 - 0)) // Rd
- | ((tinstr & 0x0038) << (16 - 3)) // Rb
- | ((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5
- } break;
-
- case 16: // STRH Rd,[Rb,#imm5]
- case 17: // LDRH Rd,[Rb,#imm5]
- *ainstr = ((tinstr & (1 << 11)) // base
- ? 0xE1D000B0 // LDRH
- : 0xE1C000B0) // STRH
- | ((tinstr & 0x0007) << (12 - 0)) // Rd
- | ((tinstr & 0x0038) << (16 - 3)) // Rb
- | ((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble
- | ((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble
- break;
-
- case 18: // STR Rd,[SP,#imm8]
- case 19: // LDR Rd,[SP,#imm8]
- *ainstr = ((tinstr & (1 << 11)) // base
- ? 0xE59D0000 // LDR
- : 0xE58D0000) // STR
- | ((tinstr & 0x0700) << (12 - 8)) // Rd
- | ((tinstr & 0x00FF) << 2); // off8
- break;
-
- case 20: // ADD Rd,PC,#imm8
- case 21: // ADD Rd,SP,#imm8
-
- if ((tinstr & (1 << 11)) == 0) {
-
- // NOTE: The PC value used here should by word aligned. We encode shift-left-by-2 in the
- // rotate immediate field, so no shift of off8 is needed.
-
- *ainstr = 0xE28F0F00 // base
- | ((tinstr & 0x0700) << (12 - 8)) // Rd
- | (tinstr & 0x00FF); // off8
- } else {
- // We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is
- // needed.
- *ainstr = 0xE28D0F00 // base
- | ((tinstr & 0x0700) << (12 - 8)) // Rd
- | (tinstr & 0x00FF); // off8
- }
- break;
-
- case 22:
- case 23:
- if ((tinstr & 0x0F00) == 0x0000) {
- // NOTE: The instruction contains a shift left of 2 equivalent (implemented as ROR #30):
- *ainstr = ((tinstr & (1 << 7)) // base
- ? 0xE24DDF00 // SUB
- : 0xE28DDF00) // ADD
- | (tinstr & 0x007F); // off7
- } else if ((tinstr & 0x0F00) == 0x0e00) {
- // BKPT
- *ainstr = 0xEF000000 // base
- | BITS(tinstr, 0, 3) // imm4 field;
- | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
- } else if ((tinstr & 0x0F00) == 0x0200) {
- static const u32 subset[4] = {
- 0xE6BF0070, // SXTH
- 0xE6AF0070, // SXTB
- 0xE6FF0070, // UXTH
- 0xE6EF0070, // UXTB
- };
-
- *ainstr = subset[BITS(tinstr, 6, 7)] // base
- | (BITS(tinstr, 0, 2) << 12) // Rd
- | BITS(tinstr, 3, 5); // Rm
- } else if ((tinstr & 0x0F00) == 0x600) {
- if (BIT(tinstr, 5) == 0) {
- // SETEND
- *ainstr = 0xF1010000 // base
- | (BIT(tinstr, 3) << 9); // endian specifier
- } else {
- // CPS
- *ainstr = 0xF1080000 // base
- | (BIT(tinstr, 0) << 6) // fiq bit
- | (BIT(tinstr, 1) << 7) // irq bit
- | (BIT(tinstr, 2) << 8) // abort bit
- | (BIT(tinstr, 4) << 18); // enable bit
- }
- } else if ((tinstr & 0x0F00) == 0x0a00) {
- static const u32 subset[4] = {
- 0xE6BF0F30, // REV
- 0xE6BF0FB0, // REV16
- 0, // undefined
- 0xE6FF0FB0, // REVSH
- };
-
- size_t subset_index = BITS(tinstr, 6, 7);
-
- if (subset_index == 2) {
- valid = ThumbDecodeStatus::UNDEFINED;
- } else {
- *ainstr = subset[subset_index] // base
- | (BITS(tinstr, 0, 2) << 12) // Rd
- | BITS(tinstr, 3, 5); // Rm
- }
- } else {
- static const u32 subset[4] = {
- 0xE92D0000, // STMDB sp!,{rlist}
- 0xE92D4000, // STMDB sp!,{rlist,lr}
- 0xE8BD0000, // LDMIA sp!,{rlist}
- 0xE8BD8000 // LDMIA sp!,{rlist,pc}
- };
- *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base
- | (tinstr & 0x00FF); // mask8
- }
- break;
-
- case 24: // STMIA
- case 25: // LDMIA
- if (tinstr & (1 << 11)) {
- unsigned int base = 0xE8900000;
- unsigned int rn = BITS(tinstr, 8, 10);
-
- // Writeback
- if ((tinstr & (1 << rn)) == 0)
- base |= (1 << 21);
-
- *ainstr = base // base (LDMIA)
- | (rn << 16) // Rn
- | (tinstr & 0x00FF); // Register list
- } else {
- *ainstr = 0xE8A00000 // base (STMIA)
- | (BITS(tinstr, 8, 10) << 16) // Rn
- | (tinstr & 0x00FF); // Register list
- }
- break;
-
- case 26: // Bcc
- case 27: // Bcc/SWI
- if ((tinstr & 0x0F00) == 0x0F00) {
- // Format 17 : SWI
- *ainstr = 0xEF000000;
- // Breakpoint must be handled specially.
- if ((tinstr & 0x00FF) == 0x18)
- *ainstr |= ((tinstr & 0x00FF) << 16);
- // New breakpoint value. See gdb/arm-tdep.c
- else if ((tinstr & 0x00FF) == 0xFE)
- *ainstr |= 0x180000; // base |= BKPT mask
- else
- *ainstr |= (tinstr & 0x00FF);
- } else if ((tinstr & 0x0F00) != 0x0E00)
- valid = ThumbDecodeStatus::BRANCH;
- else // UNDEFINED : cc=1110(AL) uses different format
- valid = ThumbDecodeStatus::UNDEFINED;
-
- break;
-
- case 28: // B
- valid = ThumbDecodeStatus::BRANCH;
- break;
-
- case 29:
- if (tinstr & 0x1)
- valid = ThumbDecodeStatus::UNDEFINED;
- else
- valid = ThumbDecodeStatus::BRANCH;
- break;
-
- case 30: // BL instruction 1
-
- // There is no single ARM instruction equivalent for this Thumb instruction. To keep the
- // simulation simple (from the user perspective) we check if the following instruction is
- // the second half of this BL, and if it is we simulate it immediately
-
- valid = ThumbDecodeStatus::BRANCH;
- break;
-
- case 31: // BL instruction 2
-
- // There is no single ARM instruction equivalent for this instruction. Also, it should only
- // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the
- // simulation of it on its own, with undefined results if r14 is not suitably initialised.
-
- valid = ThumbDecodeStatus::BRANCH;
- break;
- }
-
- *inst_size = 2;
-
- return valid;
-}