mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	arm_disasm: ARMv6 packing and sign-extend media instructions
PKH, SEL SXTAB, SXTAB16, SXTB, SXTB16, SXTH, SXTAH UXTAB, UXTAB16, UXTB, UXTB16, UXTH, UXTAH
This commit is contained in:
		
							parent
							
								
									f48a89af8b
								
							
						
					
					
						commit
						47657a1817
					
				
					 2 changed files with 181 additions and 1 deletions
				
			
		|  | @ -1,6 +1,7 @@ | ||||||
| // Copyright 2006 The Android Open Source Project
 | // Copyright 2006 The Android Open Source Project
 | ||||||
| 
 | 
 | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <unordered_set> | ||||||
| 
 | 
 | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "core/arm/disassembler/arm_disasm.h" | #include "core/arm/disassembler/arm_disasm.h" | ||||||
|  | @ -66,10 +67,12 @@ static const char *opcode_names[] = { | ||||||
|     "mvn", |     "mvn", | ||||||
|     "nop", |     "nop", | ||||||
|     "orr", |     "orr", | ||||||
|  |     "pkh", | ||||||
|     "pld", |     "pld", | ||||||
|     "rsb", |     "rsb", | ||||||
|     "rsc", |     "rsc", | ||||||
|     "sbc", |     "sbc", | ||||||
|  |     "sel", | ||||||
|     "sev", |     "sev", | ||||||
|     "smlal", |     "smlal", | ||||||
|     "smull", |     "smull", | ||||||
|  | @ -88,10 +91,22 @@ static const char *opcode_names[] = { | ||||||
|     "swi", |     "swi", | ||||||
|     "swp", |     "swp", | ||||||
|     "swpb", |     "swpb", | ||||||
|  |     "sxtab", | ||||||
|  |     "sxtab16", | ||||||
|  |     "sxtah", | ||||||
|  |     "sxtb", | ||||||
|  |     "sxtb16", | ||||||
|  |     "sxth", | ||||||
|     "teq", |     "teq", | ||||||
|     "tst", |     "tst", | ||||||
|     "umlal", |     "umlal", | ||||||
|     "umull", |     "umull", | ||||||
|  |     "uxtab", | ||||||
|  |     "uxtab16", | ||||||
|  |     "uxtah", | ||||||
|  |     "uxtb", | ||||||
|  |     "uxtb16", | ||||||
|  |     "uxth", | ||||||
|     "wfe", |     "wfe", | ||||||
|     "wfi", |     "wfi", | ||||||
|     "yield", |     "yield", | ||||||
|  | @ -236,8 +251,12 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | ||||||
|         case OP_WFI: |         case OP_WFI: | ||||||
|         case OP_YIELD: |         case OP_YIELD: | ||||||
|             return DisassembleNoOperands(opcode, insn); |             return DisassembleNoOperands(opcode, insn); | ||||||
|  |         case OP_PKH: | ||||||
|  |             return DisassemblePKH(insn); | ||||||
|         case OP_PLD: |         case OP_PLD: | ||||||
|             return DisassemblePLD(insn); |             return DisassemblePLD(insn); | ||||||
|  |         case OP_SEL: | ||||||
|  |             return DisassembleSEL(insn); | ||||||
|         case OP_STC: |         case OP_STC: | ||||||
|             return "stc"; |             return "stc"; | ||||||
|         case OP_SWI: |         case OP_SWI: | ||||||
|  | @ -245,6 +264,19 @@ std::string ARM_Disasm::Disassemble(uint32_t addr, uint32_t insn) | ||||||
|         case OP_SWP: |         case OP_SWP: | ||||||
|         case OP_SWPB: |         case OP_SWPB: | ||||||
|             return DisassembleSWP(opcode, insn); |             return DisassembleSWP(opcode, insn); | ||||||
|  |         case OP_SXTAB: | ||||||
|  |         case OP_SXTAB16: | ||||||
|  |         case OP_SXTAH: | ||||||
|  |         case OP_SXTB: | ||||||
|  |         case OP_SXTB16: | ||||||
|  |         case OP_SXTH: | ||||||
|  |         case OP_UXTAB: | ||||||
|  |         case OP_UXTAB16: | ||||||
|  |         case OP_UXTAH: | ||||||
|  |         case OP_UXTB: | ||||||
|  |         case OP_UXTB16: | ||||||
|  |         case OP_UXTH: | ||||||
|  |             return DisassembleXT(opcode, insn); | ||||||
|         case OP_UMLAL: |         case OP_UMLAL: | ||||||
|         case OP_UMULL: |         case OP_UMULL: | ||||||
|         case OP_SMLAL: |         case OP_SMLAL: | ||||||
|  | @ -684,6 +716,30 @@ std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, uint32_t insn) | ||||||
|     return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); |     return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::string ARM_Disasm::DisassemblePKH(uint32_t insn) | ||||||
|  | { | ||||||
|  |     uint32_t cond = BITS(insn, 28, 31); | ||||||
|  |     uint32_t rn = BITS(insn, 16, 19); | ||||||
|  |     uint32_t rd = BITS(insn, 12, 15); | ||||||
|  |     uint32_t imm5 = BITS(insn, 7, 11); | ||||||
|  |     uint32_t tb = BIT(insn, 6); | ||||||
|  |     uint32_t rm = BITS(insn, 0, 3); | ||||||
|  | 
 | ||||||
|  |     std::string suffix = tb ? "tb" : "bt"; | ||||||
|  |     std::string shift = ""; | ||||||
|  | 
 | ||||||
|  |     if (tb && imm5 == 0) | ||||||
|  |         imm5 = 32; | ||||||
|  | 
 | ||||||
|  |     if (imm5 > 0) { | ||||||
|  |         shift = tb ? ", ASR" : ", LSL"; | ||||||
|  |         shift += " #" + std::to_string(imm5); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), | ||||||
|  |                                     rd, rn, rm, shift.c_str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| std::string ARM_Disasm::DisassemblePLD(uint32_t insn) | std::string ARM_Disasm::DisassemblePLD(uint32_t insn) | ||||||
| { | { | ||||||
|     uint8_t is_reg = (insn >> 25) & 0x1; |     uint8_t is_reg = (insn >> 25) & 0x1; | ||||||
|  | @ -737,6 +793,17 @@ std::string ARM_Disasm::DisassembleREX(Opcode opcode, uint32_t insn) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::string ARM_Disasm::DisassembleSEL(uint32_t insn) | ||||||
|  | { | ||||||
|  |     uint32_t cond = BITS(insn, 28, 31); | ||||||
|  |     uint32_t rn = BITS(insn, 16, 19); | ||||||
|  |     uint32_t rd = BITS(insn, 12, 15); | ||||||
|  |     uint32_t rm = BITS(insn, 0, 3); | ||||||
|  | 
 | ||||||
|  |     return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond), | ||||||
|  |                                     rd, rn, rm); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| std::string ARM_Disasm::DisassembleSWI(uint32_t insn) | std::string ARM_Disasm::DisassembleSWI(uint32_t insn) | ||||||
| { | { | ||||||
|     uint8_t cond = (insn >> 28) & 0xf; |     uint8_t cond = (insn >> 28) & 0xf; | ||||||
|  | @ -756,6 +823,30 @@ std::string ARM_Disasm::DisassembleSWP(Opcode opcode, uint32_t insn) | ||||||
|     return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); |     return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | std::string ARM_Disasm::DisassembleXT(Opcode opcode, uint32_t insn) | ||||||
|  | { | ||||||
|  |     uint32_t cond = BITS(insn, 28, 31); | ||||||
|  |     uint32_t rn = BITS(insn, 16, 19); | ||||||
|  |     uint32_t rd = BITS(insn, 12, 15); | ||||||
|  |     uint32_t rotate = BITS(insn, 10, 11); | ||||||
|  |     uint32_t rm = BITS(insn, 0, 3); | ||||||
|  | 
 | ||||||
|  |     std::string rn_part = ""; | ||||||
|  |     static std::unordered_set<Opcode, std::hash<int>> extend_with_add = { | ||||||
|  |         OP_SXTAB, OP_SXTAB16, OP_SXTAH, | ||||||
|  |         OP_UXTAB, OP_UXTAB16, OP_UXTAH | ||||||
|  |     }; | ||||||
|  |     if (extend_with_add.find(opcode) != extend_with_add.end()) | ||||||
|  |         rn_part = ", r" + std::to_string(rn); | ||||||
|  | 
 | ||||||
|  |     std::string rotate_part = ""; | ||||||
|  |     if (rotate != 0) | ||||||
|  |         rotate_part = ", ROR #" + std::to_string(rotate << 3); | ||||||
|  | 
 | ||||||
|  |     return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), | ||||||
|  |                                     rd, rn_part.c_str(), rm, rotate_part.c_str()); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Opcode ARM_Disasm::Decode(uint32_t insn) { | Opcode ARM_Disasm::Decode(uint32_t insn) { | ||||||
|     uint32_t bits27_26 = (insn >> 26) & 0x3; |     uint32_t bits27_26 = (insn >> 26) & 0x3; | ||||||
|     switch (bits27_26) { |     switch (bits27_26) { | ||||||
|  | @ -818,7 +909,7 @@ Opcode ARM_Disasm::Decode01(uint32_t insn) { | ||||||
|     uint8_t is_reg = (insn >> 25) & 0x1; |     uint8_t is_reg = (insn >> 25) & 0x1; | ||||||
|     uint8_t bit4 = (insn >> 4) & 0x1; |     uint8_t bit4 = (insn >> 4) & 0x1; | ||||||
|     if (is_reg == 1 && bit4 == 1) |     if (is_reg == 1 && bit4 == 1) | ||||||
|         return OP_UNDEFINED; |         return DecodeMedia(insn); | ||||||
|     uint8_t is_load = (insn >> 20) & 0x1; |     uint8_t is_load = (insn >> 20) & 0x1; | ||||||
|     uint8_t is_byte = (insn >> 22) & 0x1; |     uint8_t is_byte = (insn >> 22) & 0x1; | ||||||
|     if ((insn & 0xfd70f000) == 0xf550f000) { |     if ((insn & 0xfd70f000) == 0xf550f000) { | ||||||
|  | @ -940,6 +1031,59 @@ Opcode ARM_Disasm::DecodeSyncPrimitive(uint32_t insn) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Opcode ARM_Disasm::DecodePackingSaturationReversal(uint32_t insn) { | ||||||
|  |     uint32_t op1 = BITS(insn, 20, 22); | ||||||
|  |     uint32_t a = BITS(insn, 16, 19); | ||||||
|  |     uint32_t op2 = BITS(insn, 5, 7); | ||||||
|  | 
 | ||||||
|  |     switch (op1) { | ||||||
|  |         case 0x0: | ||||||
|  |             if (BIT(op2, 0) == 0) | ||||||
|  |                 return OP_PKH; | ||||||
|  |             if (op2 == 0x3 && a != 0xf) | ||||||
|  |                 return OP_SXTAB16; | ||||||
|  |             if (op2 == 0x3 && a == 0xf) | ||||||
|  |                 return OP_SXTB16; | ||||||
|  |             if (op2 == 0x5) | ||||||
|  |                 return OP_SEL; | ||||||
|  |             break; | ||||||
|  |         case 0x2: | ||||||
|  |             if (op2 == 0x3 && a != 0xf) | ||||||
|  |                 return OP_SXTAB; | ||||||
|  |             if (op2 == 0x3 && a == 0xf) | ||||||
|  |                 return OP_SXTB; | ||||||
|  |             break; | ||||||
|  |         case 0x3: | ||||||
|  |             if (op2 == 0x3 && a != 0xf) | ||||||
|  |                 return OP_SXTAH; | ||||||
|  |             if (op2 == 0x3 && a == 0xf) | ||||||
|  |                 return OP_SXTH; | ||||||
|  |             break; | ||||||
|  |         case 0x4: | ||||||
|  |             if (op2 == 0x3 && a != 0xf) | ||||||
|  |                 return OP_UXTAB16; | ||||||
|  |             if (op2 == 0x3 && a == 0xf) | ||||||
|  |                 return OP_UXTB16; | ||||||
|  |             break; | ||||||
|  |         case 0x6: | ||||||
|  |             if (op2 == 0x3 && a != 0xf) | ||||||
|  |                 return OP_UXTAB; | ||||||
|  |             if (op2 == 0x3 && a == 0xf) | ||||||
|  |                 return OP_UXTB; | ||||||
|  |             break; | ||||||
|  |         case 0x7: | ||||||
|  |             if (op2 == 0x3 && a != 0xf) | ||||||
|  |                 return OP_UXTAH; | ||||||
|  |             if (op2 == 0x3 && a == 0xf) | ||||||
|  |                 return OP_UXTH; | ||||||
|  |             break; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return OP_UNDEFINED; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { | Opcode ARM_Disasm::DecodeMUL(uint32_t insn) { | ||||||
|     uint8_t bit24 = (insn >> 24) & 0x1; |     uint8_t bit24 = (insn >> 24) & 0x1; | ||||||
|     if (bit24 != 0) { |     if (bit24 != 0) { | ||||||
|  | @ -999,6 +1143,23 @@ Opcode ARM_Disasm::DecodeMSRImmAndHints(uint32_t insn) { | ||||||
|     return OP_MSR; |     return OP_MSR; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Opcode ARM_Disasm::DecodeMedia(uint32_t insn) { | ||||||
|  |     uint32_t op1 = BITS(insn, 20, 24); | ||||||
|  |     uint32_t rd = BITS(insn, 12, 15); | ||||||
|  |     uint32_t op2 = BITS(insn, 5, 7); | ||||||
|  |     uint32_t rn = BITS(insn, 0, 3); | ||||||
|  | 
 | ||||||
|  |     switch (BITS(op1, 3, 4)) { | ||||||
|  |         case 0x1: | ||||||
|  |             // Packing, unpacking, saturation, and reversal
 | ||||||
|  |             return DecodePackingSaturationReversal(insn); | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return OP_UNDEFINED; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { | Opcode ARM_Disasm::DecodeLDRH(uint32_t insn) { | ||||||
|     uint8_t is_load = (insn >> 20) & 0x1; |     uint8_t is_load = (insn >> 20) & 0x1; | ||||||
|     uint8_t bits_65 = (insn >> 5) & 0x3; |     uint8_t bits_65 = (insn >> 5) & 0x3; | ||||||
|  |  | ||||||
|  | @ -48,10 +48,12 @@ enum Opcode { | ||||||
|     OP_MVN, |     OP_MVN, | ||||||
|     OP_NOP, |     OP_NOP, | ||||||
|     OP_ORR, |     OP_ORR, | ||||||
|  |     OP_PKH, | ||||||
|     OP_PLD, |     OP_PLD, | ||||||
|     OP_RSB, |     OP_RSB, | ||||||
|     OP_RSC, |     OP_RSC, | ||||||
|     OP_SBC, |     OP_SBC, | ||||||
|  |     OP_SEL, | ||||||
|     OP_SEV, |     OP_SEV, | ||||||
|     OP_SMLAL, |     OP_SMLAL, | ||||||
|     OP_SMULL, |     OP_SMULL, | ||||||
|  | @ -70,10 +72,22 @@ enum Opcode { | ||||||
|     OP_SWI, |     OP_SWI, | ||||||
|     OP_SWP, |     OP_SWP, | ||||||
|     OP_SWPB, |     OP_SWPB, | ||||||
|  |     OP_SXTAB, | ||||||
|  |     OP_SXTAB16, | ||||||
|  |     OP_SXTAH, | ||||||
|  |     OP_SXTB, | ||||||
|  |     OP_SXTB16, | ||||||
|  |     OP_SXTH, | ||||||
|     OP_TEQ, |     OP_TEQ, | ||||||
|     OP_TST, |     OP_TST, | ||||||
|     OP_UMLAL, |     OP_UMLAL, | ||||||
|     OP_UMULL, |     OP_UMULL, | ||||||
|  |     OP_UXTAB, | ||||||
|  |     OP_UXTAB16, | ||||||
|  |     OP_UXTAH, | ||||||
|  |     OP_UXTB, | ||||||
|  |     OP_UXTB16, | ||||||
|  |     OP_UXTH, | ||||||
|     OP_WFE, |     OP_WFE, | ||||||
|     OP_WFI, |     OP_WFI, | ||||||
|     OP_YIELD, |     OP_YIELD, | ||||||
|  | @ -132,8 +146,10 @@ class ARM_Disasm { | ||||||
|   static Opcode Decode10(uint32_t insn); |   static Opcode Decode10(uint32_t insn); | ||||||
|   static Opcode Decode11(uint32_t insn); |   static Opcode Decode11(uint32_t insn); | ||||||
|   static Opcode DecodeSyncPrimitive(uint32_t insn); |   static Opcode DecodeSyncPrimitive(uint32_t insn); | ||||||
|  |   static Opcode DecodePackingSaturationReversal(uint32_t insn); | ||||||
|   static Opcode DecodeMUL(uint32_t insn); |   static Opcode DecodeMUL(uint32_t insn); | ||||||
|   static Opcode DecodeMSRImmAndHints(uint32_t insn); |   static Opcode DecodeMSRImmAndHints(uint32_t insn); | ||||||
|  |   static Opcode DecodeMedia(uint32_t insn); | ||||||
|   static Opcode DecodeLDRH(uint32_t insn); |   static Opcode DecodeLDRH(uint32_t insn); | ||||||
|   static Opcode DecodeALU(uint32_t insn); |   static Opcode DecodeALU(uint32_t insn); | ||||||
| 
 | 
 | ||||||
|  | @ -152,8 +168,11 @@ class ARM_Disasm { | ||||||
|   static std::string DisassembleMRS(uint32_t insn); |   static std::string DisassembleMRS(uint32_t insn); | ||||||
|   static std::string DisassembleMSR(uint32_t insn); |   static std::string DisassembleMSR(uint32_t insn); | ||||||
|   static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); |   static std::string DisassembleNoOperands(Opcode opcode, uint32_t insn); | ||||||
|  |   static std::string DisassemblePKH(uint32_t insn); | ||||||
|   static std::string DisassemblePLD(uint32_t insn); |   static std::string DisassemblePLD(uint32_t insn); | ||||||
|   static std::string DisassembleREX(Opcode opcode, uint32_t insn); |   static std::string DisassembleREX(Opcode opcode, uint32_t insn); | ||||||
|  |   static std::string DisassembleSEL(uint32_t insn); | ||||||
|   static std::string DisassembleSWI(uint32_t insn); |   static std::string DisassembleSWI(uint32_t insn); | ||||||
|   static std::string DisassembleSWP(Opcode opcode, uint32_t insn); |   static std::string DisassembleSWP(Opcode opcode, uint32_t insn); | ||||||
|  |   static std::string DisassembleXT(Opcode opcode, uint32_t insn); | ||||||
| }; | }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue