summaryrefslogtreecommitdiffstats
path: root/src/core/arm/dyncom/arm_dyncom_thumb.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/arm/dyncom/arm_dyncom_thumb.cpp')
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp372
1 files changed, 180 insertions, 192 deletions
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index 3576370d1..2a3dd0f53 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -21,50 +21,48 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
*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
+ 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;
+ {
+ 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;
+ {
+ 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
@@ -73,56 +71,51 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
// large subset
if ((tinstr & (1 << 10)) == 0) {
- enum otype {
- t_norm,
- t_shift,
- t_neg,
- t_mul
- };
+ 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
+ {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
+ *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
+ *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
+ *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
+ *ainstr |= ((tinstr & 0x0007) << 16) // Rd
+ | ((tinstr & 0x0007) << 8) // Rs
+ | ((tinstr & 0x0038) >> 3); // Rm
break;
}
} else {
@@ -133,109 +126,106 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
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
+ 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
+ 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
+ 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
+ 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
+ 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
+ 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 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
- }
+ {
+ 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 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
+ 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
@@ -246,14 +236,15 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
// 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
+ *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
+ // 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;
@@ -261,15 +252,15 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
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
+ *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
+ *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
@@ -278,21 +269,21 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
0xE6EF0070, // UXTB
};
- *ainstr = subset[BITS(tinstr, 6, 7)] // base
- | (BITS(tinstr, 0, 2) << 12) // Rd
- | BITS(tinstr, 3, 5); // Rm
+ *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
+ *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
+ *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] = {
@@ -307,9 +298,9 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
if (subset_index == 2) {
valid = ThumbDecodeStatus::UNDEFINED;
} else {
- *ainstr = subset[subset_index] // base
- | (BITS(tinstr, 0, 2) << 12) // Rd
- | BITS(tinstr, 3, 5); // Rm
+ *ainstr = subset[subset_index] // base
+ | (BITS(tinstr, 0, 2) << 12) // Rd
+ | BITS(tinstr, 3, 5); // Rm
}
} else {
static const u32 subset[4] = {
@@ -319,14 +310,13 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
0xE8BD8000 // LDMIA sp!,{rlist,pc}
};
*ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base
- |(tinstr & 0x00FF); // mask8
+ | (tinstr & 0x00FF); // mask8
}
break;
case 24: // STMIA
case 25: // LDMIA
- if (tinstr & (1 << 11))
- {
+ if (tinstr & (1 << 11)) {
unsigned int base = 0xE8900000;
unsigned int rn = BITS(tinstr, 8, 10);
@@ -334,15 +324,13 @@ ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u3
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
+ *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;