diff options
Diffstat (limited to 'src/core/arm/dyncom/arm_dyncom_thumb.cpp')
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom_thumb.cpp | 372 |
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; |